Merge "Extracting LightSensorController from ABC" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6ecd38f..3391698 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -335,6 +335,11 @@
aconfig_declarations: "android.os.flags-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
mode: "exported",
+ min_sdk_version: "30",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.mediaprovider",
+ ],
}
cc_aconfig_library {
@@ -716,6 +721,7 @@
name: "android.credentials.flags-aconfig",
package: "android.credentials.flags",
srcs: ["core/java/android/credentials/flags.aconfig"],
+ exportable: true,
}
java_aconfig_library {
@@ -724,6 +730,13 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+java_aconfig_library {
+ name: "android.credentials.flags-aconfig-java-export",
+ aconfig_declarations: "android.credentials.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ mode: "exported",
+}
+
// Content Protection
aconfig_declarations {
name: "android.view.contentprotection.flags-aconfig",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c904eb4..49384cd 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -232,30 +232,5 @@
}
]
}
- ],
- "auto-features-postsubmit": [
- // Test tag for automotive feature targets. These are only running in postsubmit.
- // This tag is used in targeted test features testing to limit resource use.
- // TODO(b/256932212): this tag to be removed once the above is no longer in use.
- {
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorSUSDTest"
- },
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorMUMDTest"
- },
- {
- "include-filter": "com.android.server.pm.UserVisibilityMediatorMUPANDTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
]
}
diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig
index 788e824..2c1a853 100644
--- a/apex/jobscheduler/framework/aconfig/job.aconfig
+++ b/apex/jobscheduler/framework/aconfig/job.aconfig
@@ -9,6 +9,7 @@
flag {
name: "job_debug_info_apis"
+ is_exported: true
namespace: "backstage_power"
description: "Add APIs to let apps attach debug information to jobs"
bug: "293491637"
@@ -16,6 +17,7 @@
flag {
name: "backup_jobs_exemption"
+ is_exported: true
namespace: "backstage_power"
description: "Introduce a new RUN_BACKUP_JOBS permission and exemption logic allowing for longer running jobs for apps whose primary purpose is to backup or sync content."
bug: "318731461"
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d3ca13..982ab64 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10731,6 +10731,7 @@
field public static final String DROPBOX_SERVICE = "dropbox";
field public static final String EUICC_SERVICE = "euicc";
field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
+ field public static final String FINGERPRINT_SERVICE = "fingerprint";
field public static final String GAME_SERVICE = "game";
field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
@@ -10764,6 +10765,7 @@
field public static final String OVERLAY_SERVICE = "overlay";
field public static final String PEOPLE_SERVICE = "people";
field public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
+ field @FlaggedApi("android.security.frp_enforcement") public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
field public static final String POWER_SERVICE = "power";
field public static final String PRINT_SERVICE = "print";
field @FlaggedApi("android.os.telemetry_apis_framework_initialization") public static final String PROFILING_SERVICE = "profiling";
@@ -12505,7 +12507,7 @@
method public boolean hasShortcutHostPermission();
method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public boolean isPackageEnabled(String, android.os.UserHandle);
- method public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle);
+ method @RequiresPermission(conditional=true, value="android.permission.ACCESS_SHORTCUTS") public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle);
method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public void registerCallback(android.content.pm.LauncherApps.Callback);
method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
method public void registerPackageInstallerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageInstaller.SessionCallback);
@@ -20235,10 +20237,10 @@
method public android.hardware.camera2.CaptureRequest getSessionParameters();
method public int getSessionType();
method public android.hardware.camera2.CameraCaptureSession.StateCallback getStateCallback();
- method @FlaggedApi("com.android.internal.camera.flags.camera_device_setup") public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback);
method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setInputConfiguration(@NonNull android.hardware.camera2.params.InputConfiguration);
method public void setSessionParameters(android.hardware.camera2.CaptureRequest);
+ method @FlaggedApi("com.android.internal.camera.flags.camera_device_setup") public void setStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.SessionConfiguration> CREATOR;
field public static final int SESSION_HIGH_SPEED = 1; // 0x1
@@ -20386,6 +20388,54 @@
}
+package android.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManager {
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+ field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+ field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+ field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+ field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+ field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+ field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+ field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+ field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+ }
+
+ @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManager.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence);
+ method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
+ }
+
+ @Deprecated public static class FingerprintManager.AuthenticationResult {
+ method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
+ }
+
+ @Deprecated public static final class FingerprintManager.CryptoObject {
+ ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
+ ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher getCipher();
+ method @Deprecated public javax.crypto.Mac getMac();
+ method @Deprecated public java.security.Signature getSignature();
+ }
+
+}
+
package android.hardware.input {
public final class HostUsiVersion implements android.os.Parcelable {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index c61f163..3c7c0d6 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -35,7 +35,6 @@
method @Deprecated @Nullable public String getFeatureId();
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(String);
- field public static final String FINGERPRINT_SERVICE = "fingerprint";
}
public class ContextWrapper extends android.content.Context {
@@ -146,54 +145,6 @@
}
-package android.hardware.fingerprint {
-
- @Deprecated public class FingerprintManager {
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
- method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
- field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
- field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
- field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
- field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
- field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
- field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
- field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
- field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
- field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
- field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
- field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
- field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
- field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
- field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
- field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
- }
-
- @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
- ctor public FingerprintManager.AuthenticationCallback();
- method public void onAuthenticationError(int, CharSequence);
- method public void onAuthenticationFailed();
- method public void onAuthenticationHelp(int, CharSequence);
- method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
- }
-
- @Deprecated public static class FingerprintManager.AuthenticationResult {
- method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
- }
-
- @Deprecated public static final class FingerprintManager.CryptoObject {
- ctor public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
- ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
- ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
- method public javax.crypto.Cipher getCipher();
- method public javax.crypto.Mac getMac();
- method public java.security.Signature getSignature();
- }
-
-}
-
package android.media {
public final class AudioFormat implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8ceda62..22d39a4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -598,7 +598,6 @@
field public static final int FOREGROUND_SERVICE_API_TYPE_MICROPHONE = 6; // 0x6
field public static final int FOREGROUND_SERVICE_API_TYPE_PHONE_CALL = 7; // 0x7
field public static final int FOREGROUND_SERVICE_API_TYPE_USB = 8; // 0x8
- field @FlaggedApi("android.media.audio.foreground_audio_control") public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 64; // 0x40
field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
@@ -3797,7 +3796,6 @@
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String ON_DEVICE_INTELLIGENCE_SERVICE = "on_device_intelligence";
field public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
field public static final String PERMISSION_SERVICE = "permission";
- field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness";
field public static final String ROLLBACK_SERVICE = "rollback";
field public static final String SAFETY_CENTER_SERVICE = "safety_center";
@@ -4356,7 +4354,7 @@
field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
- field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
+ field @Deprecated public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
field @FlaggedApi("android.content.pm.fix_duplicated_flags") public static final long MATCH_CLONE_PROFILE_LONG = 17179869184L; // 0x400000000L
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
@@ -15344,7 +15342,7 @@
method @Deprecated public boolean getDataEnabled(int);
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(int);
- method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackageName();
+ method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackageName();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0a26490..a76aa67 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1721,6 +1721,15 @@
}
+package android.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManager {
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+ }
+
+}
+
package android.hardware.hdmi {
public final class HdmiControlServiceWrapper {
@@ -2460,6 +2469,7 @@
}
public class UserManager {
+ method @FlaggedApi("android.os.allow_private_profile") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean canAddPrivateProfile();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt
index 2e44176..d802177 100644
--- a/core/api/test-removed.txt
+++ b/core/api/test-removed.txt
@@ -1,10 +1 @@
// Signature format: 2.0
-package android.hardware.fingerprint {
-
- @Deprecated public class FingerprintManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
- }
-
-}
-
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1cc2d25..a5dd4a7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -796,7 +796,7 @@
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
private static final String SAVED_DIALOG_ARGS_KEY_PREFIX = "android:dialog_args_";
- private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY =
+ private static final String HAS_CURRENT_PERMISSIONS_REQUEST_KEY =
"android:hasCurrentPermissionsRequest";
private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
@@ -9318,14 +9318,14 @@
private void storeHasCurrentPermissionRequest(Bundle bundle) {
if (bundle != null && mHasCurrentPermissionsRequest) {
- bundle.putBoolean(HAS_CURENT_PERMISSIONS_REQUEST_KEY, true);
+ bundle.putBoolean(HAS_CURRENT_PERMISSIONS_REQUEST_KEY, true);
}
}
private void restoreHasCurrentPermissionRequest(Bundle bundle) {
if (bundle != null) {
mHasCurrentPermissionsRequest = bundle.getBoolean(
- HAS_CURENT_PERMISSIONS_REQUEST_KEY, false);
+ HAS_CURRENT_PERMISSIONS_REQUEST_KEY, false);
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index fae4348..0c54351 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.media.audio.Flags.FLAG_FOREGROUND_AUDIO_CONTROL;
import android.Manifest;
import android.annotation.ColorInt;
@@ -948,8 +947,6 @@
* @hide
* Process can access volume APIs and can request audio focus with GAIN.
*/
- @FlaggedApi(FLAG_FOREGROUND_AUDIO_CONTROL)
- @SystemApi
public static final int PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL = 1 << 6;
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae5cacd..fa9346e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -712,16 +712,22 @@
stopped = false;
hideForNow = false;
activityConfigCallback = new ViewRootImpl.ActivityConfigCallback() {
+
@Override
- public void onConfigurationChanged(Configuration overrideConfig,
- int newDisplayId) {
+ public void onConfigurationChanged(@NonNull Configuration overrideConfig,
+ int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
if (activity == null) {
throw new IllegalStateException(
"Received config update for non-existing activity");
}
+ if (activityWindowInfoFlag() && activityWindowInfo == null) {
+ Log.w(TAG, "Received empty ActivityWindowInfo update for r=" + activity);
+ activityWindowInfo = mActivityWindowInfo;
+ }
activity.mMainThread.handleActivityConfigurationChanged(
ActivityClientRecord.this, overrideConfig, newDisplayId,
- mActivityWindowInfo, false /* alwaysReportChange */);
+ activityWindowInfo,
+ false /* alwaysReportChange */);
}
@Override
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a8352fa..0ed25eb 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1581,6 +1581,10 @@
* Allows an app to access location without the traditional location permissions and while the
* user location setting is off, but only during pre-defined emergency sessions.
*
+ * <p>This op is only used for tracking, not for permissions, so it is still the client's
+ * responsibility to check the {@link Manifest.permission.LOCATION_BYPASS} permission
+ * appropriately.
+ *
* @hide
*/
public static final int OP_EMERGENCY_LOCATION = AppProtoEnums.APP_OP_EMERGENCY_LOCATION;
@@ -2459,6 +2463,10 @@
* Allows an app to access location without the traditional location permissions and while the
* user location setting is off, but only during pre-defined emergency sessions.
*
+ * <p>This op is only used for tracking, not for permissions, so it is still the client's
+ * responsibility to check the {@link Manifest.permission.LOCATION_BYPASS} permission
+ * appropriately.
+ *
* @hide
*/
@SystemApi
@@ -2677,8 +2685,7 @@
.setDefaultMode(getSystemAlertWindowDefault()).build(),
new AppOpInfo.Builder(OP_ACCESS_NOTIFICATIONS, OPSTR_ACCESS_NOTIFICATIONS,
"ACCESS_NOTIFICATIONS")
- .setPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
- .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ .setPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS).build(),
new AppOpInfo.Builder(OP_CAMERA, OPSTR_CAMERA, "CAMERA")
.setPermission(android.Manifest.permission.CAMERA)
.setRestriction(UserManager.DISALLOW_CAMERA)
@@ -3047,8 +3054,10 @@
new AppOpInfo.Builder(OP_UNARCHIVAL_CONFIRMATION, OPSTR_UNARCHIVAL_CONFIRMATION,
"UNARCHIVAL_CONFIRMATION")
.setDefaultMode(MODE_ALLOWED).build(),
- // TODO(b/301150056): STOPSHIP determine how this appop should work with the permission
new AppOpInfo.Builder(OP_EMERGENCY_LOCATION, OPSTR_EMERGENCY_LOCATION, "EMERGENCY_LOCATION")
+ .setDefaultMode(MODE_ALLOWED)
+ // even though this has a permission associated, this op is only used for tracking,
+ // and the client is responsible for checking the LOCATION_BYPASS permission.
.setPermission(Manifest.permission.LOCATION_BYPASS).build(),
};
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 24cb9ea..cac10f5 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -487,6 +487,15 @@
*/
public static final int SUBREASON_FREEZER_BINDER_ASYNC_FULL = 31;
+ /**
+ * The process was killed because it was sending too many broadcasts while it is in the
+ * Cached state. This would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED = 32;
+
// If there is any OEM code which involves additional app kill reasons, it should
// be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
@@ -665,6 +674,7 @@
SUBREASON_EXCESSIVE_BINDER_OBJECTS,
SUBREASON_OOM_KILL,
SUBREASON_FREEZER_BINDER_ASYNC_FULL,
+ SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SubReason {}
@@ -1396,6 +1406,8 @@
return "OOM KILL";
case SUBREASON_FREEZER_BINDER_ASYNC_FULL:
return "FREEZER BINDER ASYNC FULL";
+ case SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED:
+ return "EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6f6e091..716dee4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -344,23 +344,37 @@
*/
private boolean mOwnsToken = false;
- private final Object mDirsLock = new Object();
- @GuardedBy("mDirsLock")
+ private final Object mDatabasesDirLock = new Object();
+ @GuardedBy("mDatabasesDirLock")
private File mDatabasesDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mPreferencesDirLock = new Object();
@UnsupportedAppUsage
+ @GuardedBy("mPreferencesDirLock")
private File mPreferencesDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mFilesDirLock = new Object();
+ @GuardedBy("mFilesDirLock")
private File mFilesDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mCratesDirLock = new Object();
+ @GuardedBy("mCratesDirLock")
private File mCratesDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mNoBackupFilesDirLock = new Object();
+ @GuardedBy("mNoBackupFilesDirLock")
private File mNoBackupFilesDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mCacheDirLock = new Object();
+ @GuardedBy("mCacheDirLock")
private File mCacheDir;
- @GuardedBy("mDirsLock")
+
+ private final Object mCodeCacheDirLock = new Object();
+ @GuardedBy("mCodeCacheDirLock")
private File mCodeCacheDir;
+ private final Object mMiscDirsLock = new Object();
+
// The system service cache for the system services that are cached per-ContextImpl.
@UnsupportedAppUsage
final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
@@ -742,7 +756,7 @@
@UnsupportedAppUsage
private File getPreferencesDir() {
- synchronized (mDirsLock) {
+ synchronized (mPreferencesDirLock) {
if (mPreferencesDir == null) {
mPreferencesDir = new File(getDataDir(), "shared_prefs");
}
@@ -831,7 +845,7 @@
@Override
public File getFilesDir() {
- synchronized (mDirsLock) {
+ synchronized (mFilesDirLock) {
if (mFilesDir == null) {
mFilesDir = new File(getDataDir(), "files");
}
@@ -846,7 +860,7 @@
final Path absoluteNormalizedCratePath = cratesRootPath.resolve(crateId)
.toAbsolutePath().normalize();
- synchronized (mDirsLock) {
+ synchronized (mCratesDirLock) {
if (mCratesDir == null) {
mCratesDir = cratesRootPath.toFile();
}
@@ -859,7 +873,7 @@
@Override
public File getNoBackupFilesDir() {
- synchronized (mDirsLock) {
+ synchronized (mNoBackupFilesDirLock) {
if (mNoBackupFilesDir == null) {
mNoBackupFilesDir = new File(getDataDir(), "no_backup");
}
@@ -876,7 +890,7 @@
@Override
public File[] getExternalFilesDirs(String type) {
- synchronized (mDirsLock) {
+ synchronized (mMiscDirsLock) {
File[] dirs = Environment.buildExternalStorageAppFilesDirs(getPackageName());
if (type != null) {
dirs = Environment.buildPaths(dirs, type);
@@ -894,7 +908,7 @@
@Override
public File[] getObbDirs() {
- synchronized (mDirsLock) {
+ synchronized (mMiscDirsLock) {
File[] dirs = Environment.buildExternalStorageAppObbDirs(getPackageName());
return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
}
@@ -902,7 +916,7 @@
@Override
public File getCacheDir() {
- synchronized (mDirsLock) {
+ synchronized (mCacheDirLock) {
if (mCacheDir == null) {
mCacheDir = new File(getDataDir(), "cache");
}
@@ -912,7 +926,7 @@
@Override
public File getCodeCacheDir() {
- synchronized (mDirsLock) {
+ synchronized (mCodeCacheDirLock) {
if (mCodeCacheDir == null) {
mCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir());
}
@@ -938,7 +952,7 @@
@Override
public File[] getExternalCacheDirs() {
- synchronized (mDirsLock) {
+ synchronized (mMiscDirsLock) {
File[] dirs = Environment.buildExternalStorageAppCacheDirs(getPackageName());
// We don't try to create cache directories in-process, because they need special
// setup for accurate quota tracking. This ensures the cache dirs are always
@@ -949,7 +963,7 @@
@Override
public File[] getExternalMediaDirs() {
- synchronized (mDirsLock) {
+ synchronized (mMiscDirsLock) {
File[] dirs = Environment.buildExternalStorageAppMediaDirs(getPackageName());
return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
}
@@ -1051,7 +1065,7 @@
}
private File getDatabasesDir() {
- synchronized (mDirsLock) {
+ synchronized (mDatabasesDirLock) {
if (mDatabasesDir == null) {
if ("android".equals(getPackageName())) {
mDatabasesDir = new File("/data/system");
diff --git a/core/java/android/app/GrammaticalInflectionManager.java b/core/java/android/app/GrammaticalInflectionManager.java
index 3e7d665..f0bc3e2 100644
--- a/core/java/android/app/GrammaticalInflectionManager.java
+++ b/core/java/android/app/GrammaticalInflectionManager.java
@@ -143,4 +143,24 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Peeks the current grammatical gender of privileged application from the specific user's
+ * encrypted file.
+ *
+ * @return the value of system grammatical gender.
+ * @hide
+ * @see Configuration#getGrammaticalGender
+ */
+ @RequiresPermission(Manifest.permission.READ_SYSTEM_GRAMMATICAL_GENDER)
+ @FlaggedApi(Flags.FLAG_SYSTEM_TERMS_OF_ADDRESS_ENABLED)
+ @Configuration.GrammaticalGender
+ public int peekSystemGrammaticalGenderByUserId(int userId) {
+ try {
+ return mService.peekSystemGrammaticalGenderByUserId(mContext.getAttributionSource(),
+ userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/IGrammaticalInflectionManager.aidl b/core/java/android/app/IGrammaticalInflectionManager.aidl
index 86f2e91..a5e2d0b 100644
--- a/core/java/android/app/IGrammaticalInflectionManager.aidl
+++ b/core/java/android/app/IGrammaticalInflectionManager.aidl
@@ -43,4 +43,10 @@
* Gets the grammatical gender from system.
*/
int getSystemGrammaticalGender(in AttributionSource attributionSource, int userId);
+
+ /**
+ * Peeks the grammatical gender from system by user Id.
+ */
+ int peekSystemGrammaticalGenderByUserId(in AttributionSource attributionSource, int userId);
+
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index fe8655c..f092945 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -1135,6 +1135,9 @@
} catch (RemoteException ex) {
}
onTimeout(startId);
+ if (Flags.introduceNewServiceOntimeoutCallback()) {
+ onTimeout(startId, ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
+ }
}
/**
@@ -1146,6 +1149,12 @@
* doesn't finish even after it's timed out,
* the app will be declared an ANR after a short grace period of several seconds.
*
+ * <p>Starting from Android version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
+ * {@link #onTimeout(int, int)} will also be called when a foreground service of type
+ * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE} times out.
+ * Developers do not need to implement both of the callbacks on
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and onwards.
+ *
* <p>Note, even though
* {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}
* was added
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1cbec31..66ec865 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -450,6 +450,11 @@
new CachedServiceFetcher<VcnManager>() {
@Override
public VcnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ if (!ctx.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
+ return null;
+ }
+
IBinder b = ServiceManager.getService(Context.VCN_MANAGEMENT_SERVICE);
IVcnManagementService service = IVcnManagementService.Stub.asInterface(b);
return new VcnManager(ctx, service);
@@ -1736,6 +1741,13 @@
return fetcher;
}
+ private static boolean hasSystemFeatureOpportunistic(@NonNull ContextImpl ctx,
+ @NonNull String featureName) {
+ PackageManager manager = ctx.getPackageManager();
+ if (manager == null) return true;
+ return manager.hasSystemFeature(featureName);
+ }
+
/**
* Gets a system service from a given context.
* @hide
@@ -1758,12 +1770,18 @@
case Context.VIRTUALIZATION_SERVICE:
case Context.VIRTUAL_DEVICE_SERVICE:
return null;
- case Context.SEARCH_SERVICE:
- // Wear device does not support SEARCH_SERVICE so we do not print WTF here
- PackageManager manager = ctx.getPackageManager();
- if (manager != null && manager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ case Context.VCN_MANAGEMENT_SERVICE:
+ if (!hasSystemFeatureOpportunistic(ctx,
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
return null;
}
+ break;
+ case Context.SEARCH_SERVICE:
+ // Wear device does not support SEARCH_SERVICE so we do not print WTF here
+ if (hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_WATCH)) {
+ return null;
+ }
+ break;
}
Slog.wtf(TAG, "Manager wrapper not available: " + name);
return null;
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 350b1ed..b9aa18c 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -3,6 +3,7 @@
flag {
namespace: "system_performance"
name: "app_start_info"
+ is_exported: true
description: "Control collecting of ApplicationStartInfo records and APIs."
bug: "247814855"
}
@@ -10,6 +11,7 @@
flag {
namespace: "backstage_power"
name: "get_binding_uid_importance"
+ is_exported: true
description: "API to get importance of UID that's binding to the caller"
bug: "292533010"
}
@@ -17,6 +19,7 @@
flag {
namespace: "backstage_power"
name: "app_restrictions_api"
+ is_exported: true
description: "API to track and query restrictions applied to apps"
bug: "320150834"
}
@@ -24,6 +27,7 @@
flag {
namespace: "backstage_power"
name: "uid_importance_listener_for_uids"
+ is_exported: true
description: "API to add OnUidImportanceListener with targetted UIDs"
bug: "286258140"
}
@@ -31,12 +35,14 @@
flag {
namespace: "backstage_power"
name: "introduce_new_service_ontimeout_callback"
+ is_exported: true
description: "Add a new callback in Service to indicate a FGS has reached its timeout."
bug: "317799821"
}
flag {
name: "bcast_event_timestamps"
+ is_exported: true
namespace: "backstage_power"
description: "Add APIs for clients to provide broadcast event trigger timestamps"
bug: "325136414"
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a075ac5..60dffbd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6545,8 +6545,10 @@
}
/**
- * Flag for {@link #wipeData(int)}: also erase the device's external
- * storage (such as SD cards).
+ * Flag for {@link #wipeData(int)}: also erase the device's adopted external storage (such as
+ * adopted SD cards).
+ * @see <a href="{@docRoot}about/versions/marshmallow/android-6.0.html#adoptable-storage">
+ * Adoptable Storage Devices</a>
*/
public static final int WIPE_EXTERNAL_STORAGE = 0x0001;
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 3ec6fe7..4fa45be 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -5,6 +5,7 @@
flag {
name: "policy_engine_migration_v2_enabled"
+ is_exported: true
namespace: "enterprise"
description: "V2 of the policy engine migrations for Android V"
bug: "289520697"
@@ -12,6 +13,7 @@
flag {
name: "device_policy_size_tracking_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Add feature to track the total policy size and have a max threshold - public API changes"
bug: "281543351"
@@ -26,6 +28,7 @@
flag {
name: "onboarding_bugreport_v2_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Add feature to track required changes for enabled V2 of auto-capturing of onboarding bug reports."
bug: "302517677"
@@ -47,6 +50,7 @@
flag {
name: "dedicated_device_control_api_enabled"
+ is_exported: true
namespace: "enterprise"
description: "(API) Allow the device management role holder to control which platform features are available on dedicated devices."
bug: "281964214"
@@ -54,6 +58,7 @@
flag {
name: "permission_migration_for_zero_trust_api_enabled"
+ is_exported: true
namespace: "enterprise"
description: "(API) Migrate existing APIs to permission based, and enable DMRH to call them to collect Zero Trust signals."
bug: "289520697"
@@ -68,6 +73,7 @@
flag {
name: "device_theft_api_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Add new API for theft detection."
bug: "325073410"
@@ -89,6 +95,7 @@
flag {
name: "security_log_v2_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Improve access to security logging in the context of Zero Trust."
bug: "295324350"
@@ -103,6 +110,7 @@
flag {
name: "allow_querying_profile_type"
+ is_exported: true
namespace: "enterprise"
description: "Public APIs to query if a user is a profile and what kind of profile type it is."
bug: "323001115"
@@ -117,6 +125,7 @@
flag {
name: "assist_content_user_restriction_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Prevent work data leakage by sending assist content to privileged apps."
bug: "322975406"
@@ -134,6 +143,7 @@
flag {
name: "backup_service_security_log_event_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Emit a security log event when DPM.setBackupServiceEnabled is called"
bug: "304999634"
@@ -141,6 +151,7 @@
flag {
name: "esim_management_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Enable APIs to provision and manage eSIMs"
bug: "295301164"
@@ -148,6 +159,7 @@
flag {
name: "headless_device_owner_single_user_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Add Headless DO support."
bug: "289515470"
@@ -155,6 +167,7 @@
flag {
name: "is_mte_policy_enforced"
+ is_exported: true
namespace: "enterprise"
description: "Allow to query whether MTE is enabled or not to check for compliance for enterprise policy"
bug: "322777918"
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index 4473b95..5f3bb07 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -3,6 +3,7 @@
flag {
namespace: "preload_safety"
name: "bic_client"
+ is_exported: true
description: "System API for background install control."
is_fixed_read_only: true
bug: "287507984"
diff --git a/core/java/android/app/grammatical_inflection_manager.aconfig b/core/java/android/app/grammatical_inflection_manager.aconfig
index 68d12ba..0d7bf65 100644
--- a/core/java/android/app/grammatical_inflection_manager.aconfig
+++ b/core/java/android/app/grammatical_inflection_manager.aconfig
@@ -2,6 +2,7 @@
flag {
name: "system_terms_of_address_enabled"
+ is_exported: true
namespace: "globalintl"
description: "Feature flag for System Terms of Address"
bug: "297798866"
diff --git a/core/java/android/app/multitasking.aconfig b/core/java/android/app/multitasking.aconfig
index ab00891..dbf3173 100644
--- a/core/java/android/app/multitasking.aconfig
+++ b/core/java/android/app/multitasking.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_pip_ui_state_callback_on_entering"
+ is_exported: true
namespace: "multitasking"
description: "Enables PiP UI state callback on entering"
bug: "303718131"
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 274d02a..e9a7460 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -2,6 +2,7 @@
flag {
name: "modes_api"
+ is_exported: true
namespace: "systemui"
description: "This flag controls new and updated DND apis"
bug: "300477976"
@@ -16,6 +17,7 @@
flag {
name: "api_tvextender"
+ is_exported: true
namespace: "systemui"
description: "Guards new android.app.Notification.TvExtender api"
bug: "308164892"
@@ -24,6 +26,7 @@
flag {
name: "lifetime_extension_refactor"
+ is_exported: true
namespace: "systemui"
description: "Enables moving notification lifetime extension management from SystemUI to "
"Notification Manager Service"
@@ -46,6 +49,7 @@
flag {
name: "category_voicemail"
+ is_exported: true
namespace: "wear_sysui"
description: "Adds a new voicemail category for notifications"
bug: "322806700"
@@ -53,6 +57,7 @@
flag {
name: "notification_channel_vibration_effect_api"
+ is_exported: true
namespace: "systemui"
description: "This flag enables the API to allow setting VibrationEffect for NotificationChannels"
bug: "241732519"
diff --git a/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl b/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl
index 0dbe181..8bf288a 100644
--- a/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl
+++ b/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl
@@ -53,19 +53,22 @@
void getFeatureDetails(in Feature feature, in IFeatureDetailsCallback featureDetailsCallback) = 4;
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
- void requestFeatureDownload(in Feature feature, in ICancellationSignal signal, in IDownloadCallback callback) = 5;
+ void requestFeatureDownload(in Feature feature, in AndroidFuture cancellationSignalFuture, in IDownloadCallback callback) = 5;
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
- void requestTokenInfo(in Feature feature, in Bundle requestBundle, in ICancellationSignal signal,
+ void requestTokenInfo(in Feature feature, in Bundle requestBundle, in AndroidFuture cancellationSignalFuture,
in ITokenInfoCallback tokenInfocallback) = 6;
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
- void processRequest(in Feature feature, in Bundle requestBundle, int requestType, in ICancellationSignal cancellationSignal,
- in IProcessingSignal signal, in IResponseCallback responseCallback) = 7;
+ void processRequest(in Feature feature, in Bundle requestBundle, int requestType,
+ in AndroidFuture cancellationSignalFuture,
+ in AndroidFuture processingSignalFuture,
+ in IResponseCallback responseCallback) = 7;
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
void processRequestStreaming(in Feature feature,
- in Bundle requestBundle, int requestType, in ICancellationSignal cancellationSignal, in IProcessingSignal signal,
+ in Bundle requestBundle, int requestType, in AndroidFuture cancellationSignalFuture,
+ in AndroidFuture processingSignalFuture,
in IStreamingResponseCallback streamingCallback) = 8;
String getRemoteServicePackageName() = 9;
diff --git a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
index a465e3c..bc50d2e4 100644
--- a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
+++ b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
@@ -26,22 +26,23 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.OutcomeReceiver;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.system.OsConstants;
+import android.util.Log;
import androidx.annotation.IntDef;
-import com.android.internal.R;
+import com.android.internal.infra.AndroidFuture;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -76,6 +77,8 @@
*/
public static final String AUGMENT_REQUEST_CONTENT_BUNDLE_KEY =
"AugmentRequestContentBundleKey";
+
+ private static final String TAG = "OnDeviceIntelligence";
private final Context mContext;
private final IOnDeviceIntelligenceManager mService;
@@ -121,9 +124,9 @@
@RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
public String getRemoteServicePackageName() {
String result;
- try{
- result = mService.getRemoteServicePackageName();
- } catch (RemoteException e){
+ try {
+ result = mService.getRemoteServicePackageName();
+ } catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return result;
@@ -288,18 +291,15 @@
}
};
- ICancellationSignal transport = null;
- if (cancellationSignal != null) {
- transport = CancellationSignal.createTransport();
- cancellationSignal.setRemote(transport);
- }
-
- mService.requestFeatureDownload(feature, transport, downloadCallback);
+ mService.requestFeatureDownload(feature,
+ configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
+ downloadCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
/**
* The methods computes the token related information for a given request payload using the
* provided {@link Feature}.
@@ -337,13 +337,9 @@
}
};
- ICancellationSignal transport = null;
- if (cancellationSignal != null) {
- transport = CancellationSignal.createTransport();
- cancellationSignal.setRemote(transport);
- }
-
- mService.requestTokenInfo(feature, request, transport, callback);
+ mService.requestTokenInfo(feature, request,
+ configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
+ callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -407,19 +403,9 @@
};
- IProcessingSignal transport = null;
- if (processingSignal != null) {
- transport = ProcessingSignal.createTransport();
- processingSignal.setRemote(transport);
- }
-
- ICancellationSignal cancellationTransport = null;
- if (cancellationSignal != null) {
- cancellationTransport = CancellationSignal.createTransport();
- cancellationSignal.setRemote(cancellationTransport);
- }
-
- mService.processRequest(feature, request, requestType, cancellationTransport, transport,
+ mService.processRequest(feature, request, requestType,
+ configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
+ configureRemoteProcessingSignalFuture(processingSignal, callbackExecutor),
callback);
} catch (RemoteException e) {
@@ -449,7 +435,8 @@
* @param callbackExecutor executor to run the callback on.
*/
@RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
- public void processRequestStreaming(@NonNull Feature feature, @NonNull @InferenceParams Bundle request,
+ public void processRequestStreaming(@NonNull Feature feature,
+ @NonNull @InferenceParams Bundle request,
@RequestType int requestType,
@Nullable CancellationSignal cancellationSignal,
@Nullable ProcessingSignal processingSignal,
@@ -500,20 +487,11 @@
}
};
- IProcessingSignal transport = null;
- if (processingSignal != null) {
- transport = ProcessingSignal.createTransport();
- processingSignal.setRemote(transport);
- }
-
- ICancellationSignal cancellationTransport = null;
- if (cancellationSignal != null) {
- cancellationTransport = CancellationSignal.createTransport();
- cancellationSignal.setRemote(cancellationTransport);
- }
-
mService.processRequestStreaming(
- feature, request, requestType, cancellationTransport, transport, callback);
+ feature, request, requestType,
+ configureRemoteCancellationFuture(cancellationSignal, callbackExecutor),
+ configureRemoteProcessingSignalFuture(processingSignal, callbackExecutor),
+ callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -574,4 +552,45 @@
@Target({ElementType.PARAMETER, ElementType.FIELD})
public @interface InferenceParams {
}
+
+
+ @Nullable
+ private static AndroidFuture<IBinder> configureRemoteCancellationFuture(
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull Executor callbackExecutor) {
+ if (cancellationSignal == null) {
+ return null;
+ }
+ AndroidFuture<IBinder> cancellationFuture = new AndroidFuture<>();
+ cancellationFuture.whenCompleteAsync(
+ (cancellationTransport, error) -> {
+ if (error != null || cancellationTransport == null) {
+ Log.e(TAG, "Unable to receive the remote cancellation signal.", error);
+ } else {
+ cancellationSignal.setRemote(
+ ICancellationSignal.Stub.asInterface(cancellationTransport));
+ }
+ }, callbackExecutor);
+ return cancellationFuture;
+ }
+
+ @Nullable
+ private static AndroidFuture<IBinder> configureRemoteProcessingSignalFuture(
+ ProcessingSignal processingSignal, Executor executor) {
+ if (processingSignal == null) {
+ return null;
+ }
+ AndroidFuture<IBinder> processingSignalFuture = new AndroidFuture<>();
+ processingSignalFuture.whenCompleteAsync(
+ (transport, error) -> {
+ if (error != null || transport == null) {
+ Log.e(TAG, "Unable to receive the remote processing signal.", error);
+ } else {
+ processingSignal.setRemote(IProcessingSignal.Stub.asInterface(transport));
+ }
+ }, executor);
+ return processingSignalFuture;
+ }
+
+
}
diff --git a/core/java/android/app/ondeviceintelligence/ProcessingSignal.java b/core/java/android/app/ondeviceintelligence/ProcessingSignal.java
index c275cc7..733f4fa 100644
--- a/core/java/android/app/ondeviceintelligence/ProcessingSignal.java
+++ b/core/java/android/app/ondeviceintelligence/ProcessingSignal.java
@@ -123,10 +123,10 @@
* Sets the processing signal callback to be called when signals are received.
*
* This method is intended to be used by the recipient of a processing signal
- * such as the remote implementation for {@link OnDeviceIntelligenceManager} to handle
- * cancellation requests while performing a long-running operation. This method is not
- * intended
- * to be used by applications themselves.
+ * such as the remote implementation in
+ * {@link android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService} to handle
+ * processing signals while performing a long-running operation. This method is not
+ * intended to be used by the caller themselves.
*
* If {@link ProcessingSignal#sendSignal} has already been called, then the provided callback
* is invoked immediately and all previously queued actions are passed to remote signal.
@@ -200,7 +200,7 @@
}
/**
- * Given a locally created transport, returns its associated cancellation signal.
+ * Given a locally created transport, returns its associated processing signal.
*
* @param transport The locally created transport, or null if none.
* @return The associated processing signal, or null if none.
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
index 44f3329..dd9210f 100644
--- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_on_device_intelligence"
+ is_exported: true
namespace: "ondeviceintelligence"
description: "Make methods on OnDeviceIntelligenceManager available for local inference."
bug: "304755128"
diff --git a/core/java/android/app/pinner-client.aconfig b/core/java/android/app/pinner-client.aconfig
index b60ad9e..0f7fa14 100644
--- a/core/java/android/app/pinner-client.aconfig
+++ b/core/java/android/app/pinner-client.aconfig
@@ -3,6 +3,7 @@
flag {
namespace: "system_performance"
name: "pinner_service_client_api"
+ is_exported: true
description: "Control exposing PinnerService APIs."
bug: "307594624"
}
\ No newline at end of file
diff --git a/core/java/android/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java
index fedffe1..1817c5e 100644
--- a/core/java/android/app/servertransaction/WindowStateResizeItem.java
+++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java
@@ -25,6 +25,7 @@
import android.app.ActivityThread;
import android.app.ClientTransactionHandler;
import android.content.Context;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.Trace;
@@ -32,6 +33,7 @@
import android.util.MergedConfiguration;
import android.view.IWindow;
import android.view.InsetsState;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import java.util.Objects;
@@ -55,6 +57,14 @@
private int mSyncSeqId;
private boolean mDragResizing;
+ /** {@code null} if this is not an Activity window. */
+ @Nullable
+ private IBinder mActivityToken;
+
+ /** {@code null} if this is not an Activity window. */
+ @Nullable
+ private ActivityWindowInfo mActivityWindowInfo;
+
@Override
public void execute(@NonNull ClientTransactionHandler client,
@NonNull PendingTransactionActions pendingActions) {
@@ -65,7 +75,8 @@
}
try {
mWindow.resized(mFrames, mReportDraw, mConfiguration, mInsetsState, mForceLayout,
- mAlwaysConsumeSystemBars, mDisplayId, mSyncSeqId, mDragResizing);
+ mAlwaysConsumeSystemBars, mDisplayId, mSyncSeqId, mDragResizing,
+ mActivityWindowInfo);
} catch (RemoteException e) {
// Should be a local call.
// An exception could happen if the process is restarted. It is safe to ignore since
@@ -78,6 +89,7 @@
@Nullable
@Override
public Context getContextToUpdate(@NonNull ClientTransactionHandler client) {
+ // TODO(b/260873529): dispatch for mActivityToken as well.
// WindowStateResizeItem may update the global config with #mConfiguration.
return ActivityThread.currentApplication();
}
@@ -91,7 +103,8 @@
@NonNull ClientWindowFrames frames, boolean reportDraw,
@NonNull MergedConfiguration configuration, @NonNull InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
- boolean dragResizing) {
+ boolean dragResizing, @Nullable IBinder activityToken,
+ @Nullable ActivityWindowInfo activityWindowInfo) {
WindowStateResizeItem instance =
ObjectPool.obtain(WindowStateResizeItem.class);
if (instance == null) {
@@ -107,6 +120,10 @@
instance.mDisplayId = displayId;
instance.mSyncSeqId = syncSeqId;
instance.mDragResizing = dragResizing;
+ instance.mActivityToken = activityToken;
+ instance.mActivityWindowInfo = activityWindowInfo != null
+ ? new ActivityWindowInfo(activityWindowInfo)
+ : null;
return instance;
}
@@ -123,6 +140,8 @@
mDisplayId = INVALID_DISPLAY;
mSyncSeqId = -1;
mDragResizing = false;
+ mActivityToken = null;
+ mActivityWindowInfo = null;
ObjectPool.recycle(this);
}
@@ -141,6 +160,8 @@
dest.writeInt(mDisplayId);
dest.writeInt(mSyncSeqId);
dest.writeBoolean(mDragResizing);
+ dest.writeStrongBinder(mActivityToken);
+ dest.writeTypedObject(mActivityWindowInfo, flags);
}
/** Reads from Parcel. */
@@ -155,6 +176,8 @@
mDisplayId = in.readInt();
mSyncSeqId = in.readInt();
mDragResizing = in.readBoolean();
+ mActivityToken = in.readStrongBinder();
+ mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
}
public static final @NonNull Creator<WindowStateResizeItem> CREATOR = new Creator<>() {
@@ -185,7 +208,9 @@
&& mAlwaysConsumeSystemBars == other.mAlwaysConsumeSystemBars
&& mDisplayId == other.mDisplayId
&& mSyncSeqId == other.mSyncSeqId
- && mDragResizing == other.mDragResizing;
+ && mDragResizing == other.mDragResizing
+ && Objects.equals(mActivityToken, other.mActivityToken)
+ && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
}
@Override
@@ -201,6 +226,8 @@
result = 31 * result + mDisplayId;
result = 31 * result + mSyncSeqId;
result = 31 * result + (mDragResizing ? 1 : 0);
+ result = 31 * result + Objects.hashCode(mActivityToken);
+ result = 31 * result + Objects.hashCode(mActivityWindowInfo);
return result;
}
@@ -209,6 +236,8 @@
return "WindowStateResizeItem{window=" + mWindow
+ ", reportDrawn=" + mReportDraw
+ ", configuration=" + mConfiguration
+ + ", activityToken=" + mActivityToken
+ + ", activityWindowInfo=" + mActivityWindowInfo
+ "}";
}
diff --git a/core/java/android/app/smartspace/flags.aconfig b/core/java/android/app/smartspace/flags.aconfig
index 12af888..e90ba67 100644
--- a/core/java/android/app/smartspace/flags.aconfig
+++ b/core/java/android/app/smartspace/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "remote_views"
+ is_exported: true
namespace: "sysui_integrations"
description: "Flag to enable the FlaggedApi to include RemoteViews in SmartspaceTarget"
bug: "300157758"
@@ -9,6 +10,7 @@
flag {
name: "access_smartspace"
+ is_exported: true
namespace: "sysui_integrations"
description: "Flag to enable the ACCESS_SMARTSPACE check in SmartspaceManagerService"
bug: "297207196"
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index 4d9d911..9a2d2e5 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "user_interaction_type_api"
+ is_exported: true
namespace: "backstage_power"
description: "Feature flag for user interaction event report/query API"
bug: "296061232"
@@ -9,6 +10,7 @@
flag {
name: "report_usage_stats_permission"
+ is_exported: true
namespace: "backstage_power"
description: "Feature flag for the new REPORT_USAGE_STATS permission."
bug: "296056771"
@@ -31,6 +33,7 @@
flag {
name: "filter_based_event_query_api"
+ is_exported: true
namespace: "backstage_power"
description: " Feature flag to support filter based event query API"
bug: "194321117"
@@ -38,6 +41,7 @@
flag {
name: "get_app_bytes_by_data_type_api"
+ is_exported: true
namespace: "system_performance"
description: "Feature flag for collecting app data size by file type API"
bug: "294088945"
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index b4f628f..d1d7b5d 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_unsupported_operation_status_code"
+ is_exported: true
namespace: "machine_learning"
description: "This flag enables the WearableSensingManager#STATUS_UNSUPPORTED_OPERATION status code API."
bug: "301427767"
@@ -9,6 +10,7 @@
flag {
name: "enable_data_request_observer_api"
+ is_exported: true
namespace: "machine_learning"
description: "This flag enables the API to register a data request observer on WearableSensingManager."
bug: "301427767"
@@ -16,6 +18,7 @@
flag {
name: "enable_provide_wearable_connection_api"
+ is_exported: true
namespace: "machine_learning"
description: "This flag enables the WearableSensingManager#provideWearableConnection API."
bug: "301427767"
@@ -30,6 +33,7 @@
flag {
name: "enable_hotword_wearable_sensing_api"
+ is_exported: true
namespace: "machine_learning"
description: "This flag enables the APIs related to hotword in WearableSensingManager and WearableSensingService."
bug: "310055381"
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2c0e035..57b5c13 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -1384,7 +1384,8 @@
*
* @return {@code TRUE} if the launcher supports this feature. Note the API will return without
* waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
- * the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature.
+ * the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature or if
+ * calling app belongs to a user-profile with items restricted on home screen.
*
* @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
* @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 822f02f..4511954 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "generated_previews"
+ is_exported: true
namespace: "app_widgets"
description: "Enable support for generated previews in AppWidgetManager"
bug: "306546610"
@@ -26,6 +27,7 @@
flag {
name: "draw_data_parcel"
+ is_exported: true
namespace: "app_widgets"
description: "Enable support for transporting draw instructions as data parcel"
bug: "286130467"
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 5e00b7a..2c26389 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -1086,7 +1086,7 @@
}
Objects.requireNonNull(deviceAddress, "address cannot be null");
try {
- mService.registerDevicePresenceListenerService(deviceAddress,
+ mService.legacyStartObservingDevicePresence(deviceAddress,
mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
@@ -1128,7 +1128,7 @@
}
Objects.requireNonNull(deviceAddress, "address cannot be null");
try {
- mService.unregisterDevicePresenceListenerService(deviceAddress,
+ mService.legacyStopObservingDevicePresence(deviceAddress,
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
@@ -1328,7 +1328,7 @@
@RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
public void notifyDeviceAppeared(int associationId) {
try {
- mService.notifyDeviceAppeared(associationId);
+ mService.notifySelfManagedDeviceAppeared(associationId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1350,7 +1350,7 @@
@RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED)
public void notifyDeviceDisappeared(int associationId) {
try {
- mService.notifyDeviceDisappeared(associationId);
+ mService.notifySelfManagedDeviceDisappeared(associationId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 57d59e5..1b00f90e 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -59,12 +59,16 @@
int userId);
@EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
- void registerDevicePresenceListenerService(in String deviceAddress, in String callingPackage,
- int userId);
+ void legacyStartObservingDevicePresence(in String deviceAddress, in String callingPackage, int userId);
@EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
- void unregisterDevicePresenceListenerService(in String deviceAddress, in String callingPackage,
- int userId);
+ void legacyStopObservingDevicePresence(in String deviceAddress, in String callingPackage, int userId);
+
+ @EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
+ void startObservingDevicePresence(in ObservingDevicePresenceRequest request, in String packageName, int userId);
+
+ @EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
+ void stopObservingDevicePresence(in ObservingDevicePresenceRequest request, in String packageName, int userId);
boolean canPairWithoutPrompt(in String packageName, in String deviceMacAddress, int userId);
@@ -93,9 +97,11 @@
@EnforcePermission("USE_COMPANION_TRANSPORTS")
void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener);
- void notifyDeviceAppeared(int associationId);
+ @EnforcePermission("REQUEST_COMPANION_SELF_MANAGED")
+ void notifySelfManagedDeviceAppeared(int associationId);
- void notifyDeviceDisappeared(int associationId);
+ @EnforcePermission("REQUEST_COMPANION_SELF_MANAGED")
+ void notifySelfManagedDeviceDisappeared(int associationId);
PendingIntent buildPermissionTransferUserConsentIntent(String callingPackage, int userId,
int associationId);
@@ -135,10 +141,4 @@
byte[] getBackupPayload(int userId);
void applyRestoredPayload(in byte[] payload, int userId);
-
- @EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
- void startObservingDevicePresence(in ObservingDevicePresenceRequest request, in String packageName, int userId);
-
- @EnforcePermission("REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE")
- void stopObservingDevicePresence(in ObservingDevicePresenceRequest request, in String packageName, int userId);
}
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index d634b64..ecc5e1b 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "new_association_builder"
+ is_exported: true
namespace: "companion"
description: "Controls if the new Builder is exposed to test apis."
bug: "296251481"
@@ -16,6 +17,7 @@
flag {
name: "association_tag"
+ is_exported: true
namespace: "companion"
description: "Enable Association tag APIs "
bug: "289241123"
@@ -23,6 +25,7 @@
flag {
name: "device_presence"
+ is_exported: true
namespace: "companion"
description: "Enable device presence APIs"
bug: "283000075"
@@ -30,6 +33,7 @@
flag {
name: "perm_sync_user_consent"
+ is_exported: true
namespace: "companion"
description: "Expose perm sync user consent API"
bug: "309528663"
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 6eab363..30a1135 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -79,6 +79,11 @@
int getDevicePolicy(int policyType);
/**
+ * Returns whether the device has a valid microphone.
+ */
+ boolean hasCustomAudioInputSupport();
+
+ /**
* Closes the virtual device and frees all associated resources.
*/
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index 97fa2ba..b9e9afe 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -17,7 +17,6 @@
package android.companion.virtual;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
-import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
@@ -176,8 +175,7 @@
@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
public boolean hasCustomAudioInputSupport() {
try {
- return mVirtualDevice.getDevicePolicy(POLICY_TYPE_AUDIO) == DEVICE_POLICY_CUSTOM;
- // TODO(b/291735254): also check for a custom audio injection mix for this device id.
+ return mVirtualDevice.hasCustomAudioInputSupport();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 3304475..ec59cf6 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -972,6 +972,7 @@
*
* @param config camera configuration.
* @return newly created camera.
+ * @throws UnsupportedOperationException if virtual camera isn't supported on this device.
* @see VirtualDeviceParams#POLICY_TYPE_CAMERA
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 588e4fc..a6a4f5e 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -19,6 +19,7 @@
flag {
name: "dynamic_policy"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable dynamic policy API"
bug: "298401780"
@@ -26,6 +27,7 @@
flag {
name: "cross_device_clipboard"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable cross-device clipboard API"
bug: "306622082"
@@ -40,6 +42,7 @@
flag {
name: "vdm_custom_ime"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable custom IME API"
bug: "287269288"
@@ -47,6 +50,7 @@
flag {
name: "vdm_custom_home"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable custom home API"
bug: "297168328"
@@ -54,6 +58,7 @@
flag {
name: "vdm_public_apis"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable public VDM API for device capabilities"
bug: "297253526"
@@ -61,6 +66,7 @@
flag {
name: "virtual_camera"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable Virtual Camera"
bug: "270352264"
@@ -82,6 +88,7 @@
flag {
name: "persistent_device_id_api"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable persistent device ID notification API"
bug: "295258915"
@@ -96,6 +103,7 @@
flag {
name: "interactive_screen_mirror"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable interactive screen mirroring using Virtual Devices"
bug: "292212199"
@@ -103,6 +111,7 @@
flag {
name: "virtual_stylus"
+ is_exported: true
namespace: "virtual_devices"
description: "Enable virtual stylus input"
bug: "304829446"
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 89300e3..c0c91cb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4208,7 +4208,7 @@
MEDIA_COMMUNICATION_SERVICE,
BATTERY_SERVICE,
JOB_SCHEDULER_SERVICE,
- //@hide: PERSISTENT_DATA_BLOCK_SERVICE,
+ PERSISTENT_DATA_BLOCK_SERVICE,
//@hide: OEM_LOCK_SERVICE,
MEDIA_PROJECTION_SERVICE,
MIDI_SERVICE,
@@ -5067,7 +5067,6 @@
* {@link android.hardware.fingerprint.FingerprintManager} for handling management
* of fingerprints.
*
- * @removed See {@link android.hardware.biometrics.BiometricPrompt}
* @see #getSystemService(String)
* @see android.hardware.fingerprint.FingerprintManager
*/
@@ -5930,9 +5929,8 @@
*
* @see #getSystemService(String)
* @see android.service.persistentdata.PersistentDataBlockManager
- * @hide
*/
- @SystemApi
+ @FlaggedApi(android.security.Flags.FLAG_FRP_ENFORCEMENT)
public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
/**
diff --git a/core/java/android/content/flags/flags.aconfig b/core/java/android/content/flags/flags.aconfig
index 3445fb5..27bce5b 100644
--- a/core/java/android/content/flags/flags.aconfig
+++ b/core/java/android/content/flags/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_bind_package_isolated_process"
+ is_exported: true
namespace: "machine_learning"
description: "This flag enables the newly added flag for binding package-private isolated processes."
bug: "312706530"
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd04634..535cebb 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1280,6 +1280,26 @@
264301586L; // buganizer id
/**
+ * Excludes the packages the override is applied to from the camera compatibility treatment
+ * in free-form windowing mode for fixed-orientation apps.
+ *
+ * <p>In free-form windowing mode, the compatibility treatment emulates running on a portrait
+ * device by letterboxing the app window and changing the camera characteristics to what apps
+ * commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front
+ * cameras, respectively, and setting display rotation to 0.
+ *
+ * <p>Use this flag to disable the compatibility treatment for apps that do not respond well to
+ * the treatment.
+ *
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT =
+ 314961188L;
+
+ /**
* This change id forces the packages it is applied to sandbox {@link android.view.View} API to
* an activity bounds for:
*
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 39b9149..6168b68 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -29,6 +29,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -694,9 +695,16 @@
* <p>If the caller is running on a managed profile, it'll return only the current profile.
* Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
*
- * <p> To get hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>To get hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public List<UserHandle> getProfiles() {
@@ -756,15 +764,21 @@
* list.</li>
* </ul>
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param packageName The specific package to query. If null, it checks all installed packages
* in the profile.
* @param user The UserHandle of the profile.
* @return List of launchable activities. Can be an empty list but will not be null.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
@@ -806,15 +820,21 @@
* Returns information related to a user which is useful for displaying UI elements
* to distinguish it from other users (eg, badges).
*
- * <p>If the user in question is a hidden profile like
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param userHandle user handle of the user for which LauncherUserInfo is requested.
* @return the {@link LauncherUserInfo} object related to the user specified, null in case
* the user is inaccessible.
*/
@Nullable
+ @SuppressLint("RequiresPermission")
@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
@@ -853,9 +873,14 @@
* </ul>
* </p>
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param packageName the package for which intent sender to launch App Market Activity is
* required.
@@ -864,6 +889,7 @@
* there is no such activity.
*/
@Nullable
+ @SuppressLint("RequiresPermission")
@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
@@ -887,9 +913,14 @@
* <p>An empty list denotes that all system packages should be treated as pre-installed for that
* user at creation.
*
- * <p>If the user in question is a hidden profile like
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param userHandle the user for which installed system packages are required.
* @return {@link List} of {@link String}, representing the package name of the installed
@@ -897,6 +928,7 @@
*/
@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
@NonNull
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public List<String> getPreInstalledSystemPackages(@NonNull UserHandle userHandle) {
@@ -936,14 +968,20 @@
* Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
* returns null.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param intent The intent to find a match for.
* @param user The profile to look in for a match.
* @return An activity info object if there is a match.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
@@ -995,15 +1033,21 @@
/**
* Starts a Main activity in the specified profile.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param component The ComponentName of the activity to launch
* @param user The UserHandle of the profile
* @param sourceBounds The Rect containing the source bounds of the clicked icon
* @param opts Options to pass to startActivity
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
@@ -1043,15 +1087,21 @@
* Starts the settings activity to show the application details for a
* package in the specified profile.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param component The ComponentName of the package to launch settings for.
* @param user The UserHandle of the profile
* @param sourceBounds The Rect containing the source bounds of the clicked icon
* @param opts Options to pass to startActivity
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public void startAppDetailsActivity(ComponentName component, UserHandle user,
@@ -1097,7 +1147,8 @@
* @param packageName The specific package to query. If null, it checks all installed packages
* in the profile.
* @param user The UserHandle of the profile.
- * @return List of config activities. Can be an empty list but will not be null.
+ * @return List of config activities. Can be an empty list but will not be null. Empty list will
+ * be returned for user-profiles that have items restricted on home screen.
*
* @see Intent#ACTION_CREATE_SHORTCUT
* @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
@@ -1164,15 +1215,21 @@
/**
* Checks if the package is installed and enabled for a profile.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param packageName The package to check.
* @param user The UserHandle of the profile.
*
* @return true if the package exists and is enabled.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public boolean isPackageEnabled(String packageName, UserHandle user) {
@@ -1192,9 +1249,14 @@
* <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
* app and the launcher.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* <p>Note: This just returns whatever extras were provided to the system, <em>which might
* even be {@code null}.</em>
@@ -1207,6 +1269,7 @@
* @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
* @see PackageManager#isPackageSuspended()
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
@@ -1223,14 +1286,20 @@
* could be done because the package was marked as distracting to the user via
* {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param packageName The package for which to check.
* @param user the {@link UserHandle} of the profile.
* @return
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public boolean shouldHideFromSuggestions(@NonNull String packageName,
@@ -1247,9 +1316,14 @@
/**
* Returns {@link ApplicationInfo} about an application installed for a specific user profile.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param packageName The package name of the application
* @param flags Additional option flags {@link PackageManager#getApplicationInfo}
@@ -1259,6 +1333,7 @@
* {@code null} if the package isn't installed for the given profile, or the profile
* isn't enabled.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public ApplicationInfo getApplicationInfo(@NonNull String packageName,
@@ -1310,15 +1385,21 @@
* <p>The activity may still not be exported, in which case {@link #startMainActivity} will
* throw a {@link SecurityException} unless the caller has the same UID as the target app's.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param component The activity to check.
* @param user The UserHandle of the profile.
*
* @return true if the activity exists and is enabled.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public boolean isActivityEnabled(ComponentName component, UserHandle user) {
@@ -1488,6 +1569,9 @@
* <p>The calling launcher application must be allowed to access the shortcut information,
* as defined in {@link #hasShortcutHostPermission()}.
*
+ * <p>For user-profiles with items restricted on home screen, caller must have the required
+ * permission.
+ *
* @param packageName The target package name.
* @param shortcutIds The IDs of the shortcut to be pinned.
* @param user The UserHandle of the profile.
@@ -1496,6 +1580,7 @@
*
* @see ShortcutManager
*/
+ @RequiresPermission(conditional = true, value = android.Manifest.permission.ACCESS_SHORTCUTS)
public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
@NonNull UserHandle user) {
logErrorForInvalidProfileAccess(user);
@@ -1875,12 +1960,18 @@
/**
* Registers a callback for changes to packages in this user and managed profiles.
*
- * <p>To receive callbacks for hidden profile{@link UserManager.USER_TYPE_PROFILE_PRIVATE},
- * caller should have {@link android.app.role.RoleManager.ROLE_HOME} and either of the
- * permissions required.
+ * <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param callback The callback to register.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public void registerCallback(Callback callback) {
@@ -1891,12 +1982,18 @@
* Registers a callback for changes to packages in this user and managed profiles.
*
* <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
- * caller should have {@link android.app.role.RoleManager.ROLE_HOME} and either of the
- * permissions required.
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @param callback The callback to register.
* @param handler that should be used to post callbacks on, may be null.
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public void registerCallback(Callback callback, Handler handler) {
@@ -2298,6 +2395,9 @@
* app's manifest, have the android.permission.QUERY_ALL_PACKAGES, or be the session owner to
* watch for these events.
*
+ * <p> Session callbacks are not sent for user-profiles that have items restricted on home
+ * screen.
+ *
* @param callback The callback to register.
* @param executor {@link Executor} to handle the callbacks, cannot be null.
*
@@ -2346,12 +2446,18 @@
* package name in the app's manifest, have the android.permission.QUERY_ALL_PACKAGES, or be
* the session owner to retrieve these details.
*
- * <p>If the user in question is a hidden profile
- * {@link UserManager.USER_TYPE_PROFILE_PRIVATE}, caller should have
- * {@link android.app.role.RoleManager.ROLE_HOME} and either of the permissions required.
+ * <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * caller should have either:</p>
+ * <ul>
+ * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES}
+ * permission</li>
+ * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * </ul>
*
* @see PackageInstaller#getAllSessions()
*/
+ @SuppressLint("RequiresPermission")
@RequiresPermission(conditional = true,
anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 17e6f16..270fc32 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -177,6 +177,10 @@
* Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
* for a new install is committed. For managed profile, this is sent to the default launcher
* of the primary profile.
+ * For user-profiles that have items restricted on home screen, this broadcast is sent to
+ * the default launcher of the primary profile, only if it has either
+ * {@link Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL} or
+ * {@link Manifest.permission.ACCESS_HIDDEN_PROFILES} permission.
* <p>
* The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
* session was created in {@link Intent#EXTRA_USER}.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9f2f74b..41f0936 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -895,7 +895,7 @@
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
- MATCH_CLONE_PROFILE,
+ MATCH_CLONE_PROFILE_LONG,
MATCH_QUARANTINED_COMPONENTS,
})
@Retention(RetentionPolicy.SOURCE)
@@ -1235,10 +1235,11 @@
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
/**
- * Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
+ * @deprecated Use {@link #MATCH_CLONE_PROFILE_LONG} instead.
*
* @hide
*/
+ @Deprecated
@SystemApi
public static final int MATCH_CLONE_PROFILE = 0x20000000;
@@ -3262,6 +3263,16 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: This device is capable of launching apps in automotive display
+ * compatibility mode.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_CAR_DISPLAY_COMPATIBILITY =
+ "android.software.car.display_compatibility";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
* {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
* at the given feature version.
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index e48a02a..3514914 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -583,8 +583,8 @@
*
* @return {@code TRUE} if the launcher supports this feature. Note the API will return without
* waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
- * the shortcut was pinned successfully. {@code FALSE} if the launcher doesn't support this
- * feature.
+ * the shortcut was pinned successfully. {@code FALSE} if the launcher doesn't support this
+ * feature or if calling app belongs to a user-profile with items restricted on home screen.
*
* @see #isRequestPinShortcutSupported()
* @see IntentSender
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 92cb9cc..cde565b 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "quarantined_enabled"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag for Quarantined state"
bug: "269127435"
@@ -9,6 +10,7 @@
flag {
name: "archiving"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to enable the archiving feature."
bug: "278553670"
@@ -24,6 +26,7 @@
flag {
name: "stay_stopped"
+ is_exported: true
namespace: "backstage_power"
description: "Feature flag to improve stopped state enforcement"
bug: "296644915"
@@ -39,6 +42,7 @@
flag {
name: "get_package_info"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to enable the feature to retrieve package info without installation."
bug: "269149275"
@@ -54,6 +58,7 @@
flag {
name: "sdk_lib_independence"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to keep app working even if its declared sdk-library dependency is unavailable."
bug: "295827951"
@@ -78,6 +83,7 @@
flag {
name: "get_resolved_apk_path"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to retrieve resolved path of the base APK during an app install."
bug: "269728874"
@@ -92,6 +98,7 @@
flag {
name: "read_install_info"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to read install related information from an APK."
bug: "275658500"
@@ -113,6 +120,7 @@
flag {
name: "relative_reference_intent_filters"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to enable relative reference intent filters"
bug: "307556883"
@@ -121,6 +129,7 @@
flag {
name: "fix_duplicated_flags"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to fix duplicated PackageManager flag values"
bug: "314815969"
@@ -128,6 +137,7 @@
flag {
name: "provide_info_of_apk_in_apex"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to provide the information of APK-in-APEX"
bug: "306329516"
@@ -144,6 +154,7 @@
flag {
name: "introduce_media_processing_type"
+ is_exported: true
namespace: "backstage_power"
description: "Add a new FGS type for media processing use cases."
bug: "317788011"
@@ -182,6 +193,7 @@
flag {
name: "emergency_install_permission"
+ is_exported: true
namespace: "permissions"
description: "Feature flag to enable permission EMERGENCY_INSTALL_PACKAGES"
bug: "321080601"
@@ -189,6 +201,7 @@
flag {
name: "asl_in_apk_app_metadata_source"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to allow to know if the Android Safety Label (ASL) of an app is provided by the app's APK itself, or provided by an installer."
bug: "287487923"
@@ -205,6 +218,7 @@
flag {
name: "set_pre_verified_domains"
+ is_exported: true
namespace: "package_manager_service"
description: "Feature flag to enable pre-verified domains"
bug: "307327678"
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 2d32aed..4963a4f 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -24,6 +24,7 @@
flag {
name: "support_communal_profile"
+ is_exported: true
namespace: "multiuser"
description: "Framework support for communal profile."
bug: "285426179"
@@ -31,6 +32,7 @@
flag {
name: "support_communal_profile_nextgen"
+ is_exported: true
namespace: "multiuser"
description: "Further framework support for communal profile, beyond the basics, for later releases."
bug: "285426179"
@@ -59,6 +61,7 @@
flag {
name: "enable_biometrics_to_unlock_private_space"
+ is_exported: true
namespace: "profile_experiences"
description: "Add support to unlock the private space using biometrics"
bug: "312184187"
@@ -102,6 +105,7 @@
flag {
name: "enable_system_user_only_for_services_and_providers"
+ is_exported: true
namespace: "multiuser"
description: "Enable systemUserOnly manifest attribute for services and providers."
bug: "302354856"
@@ -118,6 +122,7 @@
flag {
name: "enable_permission_to_access_hidden_profiles"
+ is_exported: true
namespace: "profile_experiences"
description: "Add permission to access API hidden users data via system APIs"
bug: "321988638"
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index d274792..885f4c5 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -802,14 +802,20 @@
public static final int SCREEN_WIDTH_DP_UNDEFINED = 0;
/**
- * The width of the available screen space in dp units excluding the area
- * occupied by {@link android.view.WindowInsets window insets}.
+ * The width of the available screen space in dp units.
*
- * <aside class="note"><b>Note:</b> The width measurement excludes window
- * insets even when the app is displayed edge to edge using
- * {@link android.view.Window#setDecorFitsSystemWindows(boolean)
+ * <aside class="note"><b>Note:</b> If the app targets
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ * or after, The width measurement reflects the window size without excluding insets.
+ * Otherwise, the measurement excludes window insets even when the app is displayed edge to edge
+ * using {@link android.view.Window#setDecorFitsSystemWindows(boolean)
* Window#setDecorFitsSystemWindows(boolean)}.</aside>
*
+ * Use {@link android.view.WindowMetrics#getBounds()} to always obtain the horizontal
+ * display area available to an app or embedded activity including the area
+ * occupied by window insets. A version of the API is also available for use on older platforms
+ * through {@link androidx.window.layout.WindowMetrics}.
+ *
* <p>Corresponds to the
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier">
* available width</a> resource qualifier. Defaults to
@@ -831,14 +837,15 @@
* environment, {@code screenWidthDp} is the width of the screen on which
* the app is displayed excluding window insets.
*
- * <p>Differs from {@link android.view.WindowMetrics} by not including
+ * <p>If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
+ * it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
+ * dp rather than px.
+ *
+ * <p>Otherwise, differs from {@link android.view.WindowMetrics} by not including
* window insets in the width measurement and by expressing the measurement
* in dp rather than px. Use {@code screenWidthDp} to obtain the width of
* the display area available to an app or embedded activity excluding the
- * area occupied by window insets. Use
- * {@link android.view.WindowMetrics#getBounds()} to obtain the horizontal
- * display area available to an app or embedded activity including the area
- * occupied by window insets.
+ * area occupied by window insets.
*/
public int screenWidthDp;
@@ -849,15 +856,20 @@
public static final int SCREEN_HEIGHT_DP_UNDEFINED = 0;
/**
- * The height of the available screen space in dp units excluding the area
- * occupied by {@link android.view.WindowInsets window insets}, such as the
- * status bar, navigation bar, and cutouts.
+ * The height of the available screen space in dp units.
*
- * <aside class="note"><b>Note:</b> The height measurement excludes window
- * insets even when the app is displayed edge to edge using
- * {@link android.view.Window#setDecorFitsSystemWindows(boolean)
+ * <aside class="note"><b>Note:</b> If the app targets
+ * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}
+ * or after, the height measurement reflects the window size without excluding insets.
+ * Otherwise, the measurement excludes window insets even when the app is displayed edge to edge
+ * using {@link android.view.Window#setDecorFitsSystemWindows(boolean)
* Window#setDecorFitsSystemWindows(boolean)}.</aside>
*
+ * Use {@link android.view.WindowMetrics#getBounds()} to always obtain the vertical
+ * display area available to an app or embedded activity including the area
+ * occupied by window insets. A version of the API is also available for use on older platforms
+ * through {@link androidx.window.layout.WindowMetrics}.
+ *
* <p>Corresponds to the
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#AvailableWidthHeightQualifier">
* available height</a> resource qualifier. Defaults to
@@ -879,14 +891,15 @@
* multiple-screen environment, {@code screenHeightDp} is the height of the
* screen on which the app is displayed excluding window insets.
*
- * <p>Differs from {@link android.view.WindowMetrics} by not including
+ * <p>If the app targets {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or after,
+ * it is the same as {@link android.view.WindowMetrics}, but is expressed rounded to the nearest
+ * dp rather than px.
+ *
+ * <p>Otherwise, differs from {@link android.view.WindowMetrics} by not including
* window insets in the height measurement and by expressing the measurement
* in dp rather than px. Use {@code screenHeightDp} to obtain the height of
* the display area available to an app or embedded activity excluding the
- * area occupied by window insets. Use
- * {@link android.view.WindowMetrics#getBounds()} to obtain the vertical
- * display area available to an app or embedded activity including the area
- * occupied by window insets.
+ * area occupied by window insets.
*/
public int screenHeightDp;
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index 7fd0b03..8f5c912 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "default_locale"
+ is_exported: true
namespace: "resource_manager"
description: "Feature flag for default locale in LocaleConfig"
bug: "117306409"
@@ -11,6 +12,7 @@
flag {
name: "font_scale_converter_public"
+ is_exported: true
namespace: "accessibility"
description: "Enables the public API for FontScaleConverter, including enabling thread-safe caching."
bug: "239736383"
@@ -20,6 +22,7 @@
flag {
name: "asset_file_descriptor_frro"
+ is_exported: true
namespace: "resource_manager"
description: "Feature flag for passing in an AssetFileDescriptor to create an frro"
bug: "304478666"
@@ -27,6 +30,7 @@
flag {
name: "manifest_flagging"
+ is_exported: true
namespace: "resource_manager"
description: "Feature flag for flagging manifest entries"
bug: "297373084"
@@ -36,6 +40,7 @@
flag {
name: "nine_patch_frro"
+ is_exported: true
namespace: "resource_manager"
description: "Feature flag for creating an frro from a 9-patch"
bug: "296324826"
@@ -43,6 +48,7 @@
flag {
name: "register_resource_paths"
+ is_exported: true
namespace: "resource_manager"
description: "Feature flag for register resource paths for shared library"
bug: "306202569"
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 47edba6..d077329 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -3,6 +3,7 @@
flag {
namespace: "credential_manager"
name: "settings_activity_enabled"
+ is_exported: true
description: "Enable the Credential Manager Settings Activity APIs"
bug: "300014059"
}
@@ -24,6 +25,7 @@
flag {
namespace: "credential_manager"
name: "new_settings_intents"
+ is_exported: true
description: "Enables settings intents to redirect to new settings page"
bug: "307587989"
}
@@ -45,8 +47,10 @@
flag {
namespace: "credential_manager"
name: "configurable_selector_ui_enabled"
+ is_exported: true
description: "Enables OEM configurable Credential Selector UI"
bug: "319448437"
+ is_exported: true
}
flag {
diff --git a/core/java/android/credentials/selection/IntentCreationResult.java b/core/java/android/credentials/selection/IntentCreationResult.java
new file mode 100644
index 0000000..189ff7b
--- /dev/null
+++ b/core/java/android/credentials/selection/IntentCreationResult.java
@@ -0,0 +1,155 @@
+/*
+ * 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.credentials.selection;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+
+/**
+ * Result of creating a Credential Manager UI intent.
+ *
+ * @hide
+ */
+public final class IntentCreationResult {
+ @NonNull
+ private final Intent mIntent;
+ @Nullable
+ private final String mFallbackUiPackageName;
+ @Nullable
+ private final String mOemUiPackageName;
+ @NonNull
+ private final OemUiUsageStatus mOemUiUsageStatus;
+
+ private IntentCreationResult(@NonNull Intent intent, @Nullable String fallbackUiPackageName,
+ @Nullable String oemUiPackageName, OemUiUsageStatus oemUiUsageStatus) {
+ mIntent = intent;
+ mFallbackUiPackageName = fallbackUiPackageName;
+ mOemUiPackageName = oemUiPackageName;
+ mOemUiUsageStatus = oemUiUsageStatus;
+ }
+
+ /** Returns the UI intent. */
+ @NonNull
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ /**
+ * Returns the result of attempting to use the config_oemCredentialManagerDialogComponent
+ * as the Credential Manager UI.
+ */
+ @NonNull
+ public OemUiUsageStatus getOemUiUsageStatus() {
+ return mOemUiUsageStatus;
+ }
+
+ /**
+ * Returns the package name of the ui component specified in
+ * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable
+ * successfully.
+ */
+ @Nullable
+ public String getFallbackUiPackageName() {
+ return mFallbackUiPackageName;
+ }
+
+ /**
+ * Returns the package name of the oem ui component specified in
+ * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable.
+ */
+ @Nullable
+ public String getOemUiPackageName() {
+ return mOemUiPackageName;
+ }
+
+ /**
+ * Result of attempting to use the config_oemCredentialManagerDialogComponent as the Credential
+ * Manager UI.
+ */
+ public enum OemUiUsageStatus {
+ UNKNOWN,
+ // Success: the UI specified in config_oemCredentialManagerDialogComponent was used to
+ // fulfill the request.
+ SUCCESS,
+ // The config value was not specified (e.g. left empty).
+ OEM_UI_CONFIG_NOT_SPECIFIED,
+ // The config value component was specified but not found (e.g. component doesn't exist or
+ // component isn't a system app).
+ OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND,
+ // The config value component was found but not enabled.
+ OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED,
+ }
+
+ /**
+ * Builder for {@link IntentCreationResult}.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ @NonNull
+ private Intent mIntent;
+ @Nullable
+ private String mFallbackUiPackageName = null;
+ @Nullable
+ private String mOemUiPackageName = null;
+ @NonNull
+ private OemUiUsageStatus mOemUiUsageStatus = OemUiUsageStatus.UNKNOWN;
+
+ public Builder(Intent intent) {
+ mIntent = intent;
+ }
+
+ /**
+ * Sets the package name of the ui component specified in
+ * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable
+ * successfully.
+ */
+ @NonNull
+ public Builder setFallbackUiPackageName(@Nullable String fallbackUiPackageName) {
+ mFallbackUiPackageName = fallbackUiPackageName;
+ return this;
+ }
+
+ /**
+ * Sets the package name of the oem ui component specified in
+ * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable.
+ */
+ @NonNull
+ public Builder setOemUiPackageName(@Nullable String oemUiPackageName) {
+ mOemUiPackageName = oemUiPackageName;
+ return this;
+ }
+
+ /**
+ * Sets the result of attempting to use the config_oemCredentialManagerDialogComponent
+ * as the Credential Manager UI.
+ */
+ @NonNull
+ public Builder setOemUiUsageStatus(OemUiUsageStatus oemUiUsageStatus) {
+ mOemUiUsageStatus = oemUiUsageStatus;
+ return this;
+ }
+
+ /** Builds a {@link IntentCreationResult}. */
+ @NonNull
+ public IntentCreationResult build() {
+ return new IntentCreationResult(mIntent, mFallbackUiPackageName, mOemUiPackageName,
+ mOemUiUsageStatus);
+ }
+ }
+}
diff --git a/core/java/android/credentials/selection/IntentFactory.java b/core/java/android/credentials/selection/IntentFactory.java
index 79fba9b..b98a0d8 100644
--- a/core/java/android/credentials/selection/IntentFactory.java
+++ b/core/java/android/credentials/selection/IntentFactory.java
@@ -36,6 +36,8 @@
import android.text.TextUtils;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
/**
@@ -57,98 +59,48 @@
* @hide
*/
@NonNull
- public static Intent createCredentialSelectorIntentForAutofill(
+ public static IntentCreationResult createCredentialSelectorIntentForAutofill(
@NonNull Context context,
@NonNull RequestInfo requestInfo,
@SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling.
@NonNull
ArrayList<DisabledProviderData> disabledProviderDataList,
@NonNull ResultReceiver resultReceiver) {
- return createCredentialSelectorIntent(context, requestInfo,
+ return createCredentialSelectorIntentInternal(context, requestInfo,
disabledProviderDataList, resultReceiver);
}
/**
* Generate a new launch intent to the Credential Selector UI.
+ *
+ * @param context the CredentialManager system service (only expected caller)
+ * context that may be used to query existence of the key UI
+ * application
+ * @param disabledProviderDataList the list of disabled provider data that when non-empty the
+ * UI should accordingly generate an entry suggesting the user
+ * to navigate to settings and enable them
+ * @param enabledProviderDataList the list of enabled provider that contain options for this
+ * request; the UI should render each option to the user for
+ * selection
+ * @param requestInfo the display information about the given app request
+ * @param resultReceiver used by the UI to send the UI selection result back
+ * @hide
*/
@NonNull
- private static Intent createCredentialSelectorIntent(
+ public static IntentCreationResult createCredentialSelectorIntentForCredMan(
@NonNull Context context,
@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) {
- Intent intent = new Intent();
- setCredentialSelectorUiComponentName(context, intent);
- intent.putParcelableArrayListExtra(
- ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList);
- intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo);
- intent.putExtra(
- Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver));
-
- return intent;
- }
-
- private static void setCredentialSelectorUiComponentName(@NonNull Context context,
- @NonNull Intent intent) {
- if (configurableSelectorUiEnabled()) {
- ComponentName componentName = getOemOverrideComponentName(context);
- if (componentName == null) {
- componentName = ComponentName.unflattenFromString(Resources.getSystem().getString(
- com.android.internal.R.string
- .config_fallbackCredentialManagerDialogComponent));
- }
- intent.setComponent(componentName);
- } else {
- ComponentName componentName = ComponentName.unflattenFromString(Resources.getSystem()
- .getString(com.android.internal.R.string
- .config_fallbackCredentialManagerDialogComponent));
- intent.setComponent(componentName);
- }
- }
-
- /**
- * Returns null if there is not an enabled and valid oem override component. It means the
- * default platform UI component name should be used instead.
- */
- @Nullable
- private static ComponentName getOemOverrideComponentName(@NonNull Context context) {
- ComponentName result = null;
- String oemComponentString =
- Resources.getSystem()
- .getString(
- com.android.internal.R.string
- .config_oemCredentialManagerDialogComponent);
- if (!TextUtils.isEmpty(oemComponentString)) {
- ComponentName oemComponentName = ComponentName.unflattenFromString(
- oemComponentString);
- if (oemComponentName != null) {
- try {
- ActivityInfo info = context.getPackageManager().getActivityInfo(
- oemComponentName,
- PackageManager.ComponentInfoFlags.of(
- PackageManager.MATCH_SYSTEM_ONLY));
- if (info.enabled && info.exported) {
- Slog.i(TAG,
- "Found enabled oem CredMan UI component."
- + oemComponentString);
- result = oemComponentName;
- } else {
- Slog.i(TAG,
- "Found enabled oem CredMan UI component but it was not "
- + "enabled.");
- }
- } catch (PackageManager.NameNotFoundException e) {
- Slog.i(TAG, "Unable to find oem CredMan UI component: "
- + oemComponentString + ".");
- }
- } else {
- Slog.i(TAG, "Invalid OEM ComponentName format.");
- }
- } else {
- Slog.i(TAG, "Invalid empty OEM component name.");
- }
+ IntentCreationResult result = createCredentialSelectorIntentInternal(context, requestInfo,
+ disabledProviderDataList, resultReceiver);
+ result.getIntent().putParcelableArrayListExtra(
+ ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList);
return result;
}
@@ -167,6 +119,7 @@
* @param requestInfo the display information about the given app request
* @param resultReceiver used by the UI to send the UI selection result back
*/
+ @VisibleForTesting
@NonNull
public static Intent createCredentialSelectorIntent(
@NonNull Context context,
@@ -178,22 +131,21 @@
@NonNull
ArrayList<DisabledProviderData> disabledProviderDataList,
@NonNull ResultReceiver resultReceiver) {
- Intent intent = createCredentialSelectorIntent(context, requestInfo,
- disabledProviderDataList, resultReceiver);
- intent.putParcelableArrayListExtra(
- ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList);
- return intent;
+ return createCredentialSelectorIntentForCredMan(context, requestInfo,
+ enabledProviderDataList, disabledProviderDataList, resultReceiver).getIntent();
}
/**
* Creates an Intent that cancels any UI matching the given request token id.
*/
+ @VisibleForTesting
@NonNull
public static Intent createCancelUiIntent(@NonNull Context context,
@NonNull IBinder requestToken, boolean shouldShowCancellationUi,
@NonNull String appPackageName) {
Intent intent = new Intent();
- setCredentialSelectorUiComponentName(context, intent);
+ IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent);
+ setCredentialSelectorUiComponentName(context, intent, intentResultBuilder);
intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST,
new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi,
appPackageName));
@@ -201,6 +153,119 @@
}
/**
+ * Generate a new launch intent to the Credential Selector UI.
+ */
+ @NonNull
+ private static IntentCreationResult createCredentialSelectorIntentInternal(
+ @NonNull Context context,
+ @NonNull RequestInfo requestInfo,
+ @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling.
+ @NonNull
+ ArrayList<DisabledProviderData> disabledProviderDataList,
+ @NonNull ResultReceiver resultReceiver) {
+ Intent intent = new Intent();
+ IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent);
+ setCredentialSelectorUiComponentName(context, intent, intentResultBuilder);
+ intent.putParcelableArrayListExtra(
+ ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList);
+ intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo);
+ intent.putExtra(
+ Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver));
+ return intentResultBuilder.build();
+ }
+
+ private static void setCredentialSelectorUiComponentName(@NonNull Context context,
+ @NonNull Intent intent, @NonNull IntentCreationResult.Builder intentResultBuilder) {
+ if (configurableSelectorUiEnabled()) {
+ ComponentName componentName = getOemOverrideComponentName(context, intentResultBuilder);
+
+ ComponentName fallbackUiComponentName = null;
+ try {
+ fallbackUiComponentName = ComponentName.unflattenFromString(
+ Resources.getSystem().getString(
+ com.android.internal.R.string
+ .config_fallbackCredentialManagerDialogComponent));
+ intentResultBuilder.setFallbackUiPackageName(
+ fallbackUiComponentName.getPackageName());
+ } catch (Exception e) {
+ Slog.w(TAG, "Fallback CredMan IU not found: " + e);
+ }
+
+ if (componentName == null) {
+ componentName = fallbackUiComponentName;
+ }
+
+ intent.setComponent(componentName);
+ } else {
+ ComponentName componentName = ComponentName.unflattenFromString(Resources.getSystem()
+ .getString(com.android.internal.R.string
+ .config_fallbackCredentialManagerDialogComponent));
+ intent.setComponent(componentName);
+ }
+ }
+
+ /**
+ * Returns null if there is not an enabled and valid oem override component. It means the
+ * default platform UI component name should be used instead.
+ */
+ @Nullable
+ private static ComponentName getOemOverrideComponentName(@NonNull Context context,
+ @NonNull IntentCreationResult.Builder intentResultBuilder) {
+ ComponentName result = null;
+ String oemComponentString =
+ Resources.getSystem()
+ .getString(
+ com.android.internal.R.string
+ .config_oemCredentialManagerDialogComponent);
+ if (!TextUtils.isEmpty(oemComponentString)) {
+ ComponentName oemComponentName = null;
+ try {
+ oemComponentName = ComponentName.unflattenFromString(
+ oemComponentString);
+ } catch (Exception e) {
+ Slog.i(TAG, "Failed to parse OEM component name " + oemComponentString + ": " + e);
+ }
+ if (oemComponentName != null) {
+ try {
+ intentResultBuilder.setOemUiPackageName(oemComponentName.getPackageName());
+ ActivityInfo info = context.getPackageManager().getActivityInfo(
+ oemComponentName,
+ PackageManager.ComponentInfoFlags.of(
+ PackageManager.MATCH_SYSTEM_ONLY));
+ if (info.enabled && info.exported) {
+ intentResultBuilder.setOemUiUsageStatus(IntentCreationResult
+ .OemUiUsageStatus.SUCCESS);
+ Slog.i(TAG,
+ "Found enabled oem CredMan UI component."
+ + oemComponentString);
+ result = oemComponentName;
+ } else {
+ intentResultBuilder.setOemUiUsageStatus(IntentCreationResult
+ .OemUiUsageStatus.OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED);
+ Slog.i(TAG,
+ "Found enabled oem CredMan UI component but it was not "
+ + "enabled.");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus
+ .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND);
+ Slog.i(TAG, "Unable to find oem CredMan UI component: "
+ + oemComponentString + ".");
+ }
+ } else {
+ intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus
+ .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND);
+ Slog.i(TAG, "Invalid OEM ComponentName format.");
+ }
+ } else {
+ intentResultBuilder.setOemUiUsageStatus(
+ IntentCreationResult.OemUiUsageStatus.OEM_UI_CONFIG_NOT_SPECIFIED);
+ Slog.i(TAG, "Invalid empty OEM component name.");
+ }
+ return result;
+ }
+
+ /**
* Convert an instance of a "locally-defined" ResultReceiver to an instance of {@link
* android.os.ResultReceiver} itself, which the receiving process will be able to unmarshall.
*/
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index 92ef9c2..7ecffaf 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "sqlite_apis_35"
+ is_exported: true
namespace: "system_performance"
is_fixed_read_only: true
description: "SQLite APIs held back for Android 15"
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index a8d54ed..7d61c14 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -123,6 +123,15 @@
public static final int DISMISSED_REASON_CREDENTIAL_CONFIRMED = 7;
/**
+ * Dialog is done animating away after user clicked on the button set via
+ * {@link PromptContentViewWithMoreOptionsButton.Builder#setMoreOptionsButtonListener(Executor,
+ * DialogInterface.OnClickListener)} )}.
+ *
+ * @hide
+ */
+ public static final int DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS = 8;
+
+ /**
* @hide
*/
@IntDef({DISMISSED_REASON_BIOMETRIC_CONFIRMED,
@@ -131,7 +140,8 @@
DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
DISMISSED_REASON_ERROR,
DISMISSED_REASON_SERVER_REQUESTED,
- DISMISSED_REASON_CREDENTIAL_CONFIRMED})
+ DISMISSED_REASON_CREDENTIAL_CONFIRMED,
+ DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS})
@Retention(RetentionPolicy.SOURCE)
public @interface DismissedReason {}
@@ -654,8 +664,6 @@
private final IAuthService mService;
private final PromptInfo mPromptInfo;
private final ButtonInfo mNegativeButtonInfo;
- // TODO(b/328843028): add callback onContentViewMoreOptionsButtonClicked() in
- // IBiometricServiceReceiver.
private final ButtonInfo mContentViewMoreOptionsButtonInfo;
private CryptoObject mCryptoObject;
@@ -745,6 +753,13 @@
mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
mIsPromptShowing = false;
});
+ } else if (reason == DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS) {
+ if (mContentViewMoreOptionsButtonInfo != null) {
+ mContentViewMoreOptionsButtonInfo.executor.execute(() -> {
+ mContentViewMoreOptionsButtonInfo.listener.onClick(null,
+ DialogInterface.BUTTON_NEGATIVE);
+ });
+ }
} else {
mIsPromptShowing = false;
Log.e(TAG, "Unknown reason: " + reason);
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index ff07498..9836eec 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -18,6 +18,7 @@
flag {
name: "get_op_id_crypto_object"
+ is_exported: true
namespace: "biometrics_framework"
description: "Feature flag for adding a get operation id api to CryptoObject."
bug: "307601768"
@@ -25,8 +26,8 @@
flag {
name: "custom_biometric_prompt"
+ is_exported: true
namespace: "biometrics_framework"
description: "Feature flag for adding a custom content view API to BiometricPrompt.Builder."
bug: "302735104"
}
-
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 13d5c7e..6f901d7 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2800,7 +2800,9 @@
* upright.</p>
* <p>Camera devices may either encode this value into the JPEG EXIF header, or
* rotate the image data to match this orientation. When the image data is rotated,
- * the thumbnail data will also be rotated.</p>
+ * the thumbnail data will also be rotated. Additionally, in the case where the image data
+ * is rotated, {@link android.media.Image#getWidth } and {@link android.media.Image#getHeight }
+ * will not be updated to reflect the height and width of the rotated image.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
* <p>To translate from the device orientation given by the Android sensor APIs for camera
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7145501..69b1c34 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3091,7 +3091,9 @@
* upright.</p>
* <p>Camera devices may either encode this value into the JPEG EXIF header, or
* rotate the image data to match this orientation. When the image data is rotated,
- * the thumbnail data will also be rotated.</p>
+ * the thumbnail data will also be rotated. Additionally, in the case where the image data
+ * is rotated, {@link android.media.Image#getWidth } and {@link android.media.Image#getHeight }
+ * will not be updated to reflect the height and width of the rotated image.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
* <p>To translate from the device orientation given by the Android sensor APIs for camera
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index b0f354f..3b2913c 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -133,7 +133,7 @@
* {@link CameraDeviceSetup.isSessionConfigurationSupported} and {@link
* CameraDeviceSetup.getSessionCharacteristics} to query a camera device's feature
* combination support and session specific characteristics. For the SessionConfiguration
- * object to be used to create a capture session, {@link #setCallback} must be called to
+ * object to be used to create a capture session, {@link #setStateCallback} must be called to
* specify the state callback function, and any incomplete OutputConfigurations must be
* completed via {@link OutputConfiguration#addSurface} or
* {@link OutputConfiguration#setSurfacesForMultiResolutionOutput} as appropriate.</p>
@@ -419,7 +419,7 @@
* @param cb A state callback interface implementation.
*/
@FlaggedApi(Flags.FLAG_CAMERA_DEVICE_SETUP)
- public void setCallback(
+ public void setStateCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull CameraCaptureSession.StateCallback cb) {
mStateCallback = cb;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index b067095..978a8f9 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1473,6 +1473,11 @@
* <li>ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH
* <li>ImageFormat.HEIC => HAL_DATASPACE_HEIF
* <li>ImageFormat.JPEG_R => HAL_DATASPACE_JPEG_R
+ * <li>ImageFormat.YUV_420_888 => HAL_DATASPACE_JFIF
+ * <li>ImageFormat.RAW_SENSOR => HAL_DATASPACE_ARBITRARY
+ * <li>ImageFormat.RAW_OPAQUE => HAL_DATASPACE_ARBITRARY
+ * <li>ImageFormat.RAW10 => HAL_DATASPACE_ARBITRARY
+ * <li>ImageFormat.RAW12 => HAL_DATASPACE_ARBITRARY
* <li>others => HAL_DATASPACE_UNKNOWN
* </ul>
* </p>
@@ -1511,6 +1516,11 @@
return HAL_DATASPACE_JPEG_R;
case ImageFormat.YUV_420_888:
return HAL_DATASPACE_JFIF;
+ case ImageFormat.RAW_SENSOR:
+ case ImageFormat.RAW_PRIVATE:
+ case ImageFormat.RAW10:
+ case ImageFormat.RAW12:
+ return HAL_DATASPACE_ARBITRARY;
default:
return HAL_DATASPACE_UNKNOWN;
}
@@ -2005,6 +2015,12 @@
private static final int HAL_DATASPACE_RANGE_SHIFT = 27;
private static final int HAL_DATASPACE_UNKNOWN = 0x0;
+
+ /**
+ * @hide
+ */
+ public static final int HAL_DATASPACE_ARBITRARY = 0x1;
+
/** @hide */
public static final int HAL_DATASPACE_V0_JFIF =
(2 << HAL_DATASPACE_STANDARD_SHIFT) |
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java
index b214da2..689e343 100644
--- a/core/java/android/hardware/devicestate/DeviceState.java
+++ b/core/java/android/hardware/devicestate/DeviceState.java
@@ -173,7 +173,7 @@
public static final int PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT = 17;
/** @hide */
- @IntDef(prefix = {"PROPERTY_"}, flag = true, value = {
+ @IntDef(prefix = {"PROPERTY_"}, flag = false, value = {
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED,
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN,
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN,
@@ -197,7 +197,7 @@
public @interface DeviceStateProperties {}
/** @hide */
- @IntDef(prefix = {"PROPERTY_"}, flag = true, value = {
+ @IntDef(prefix = {"PROPERTY_"}, flag = false, value = {
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED,
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN,
PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN
@@ -207,7 +207,7 @@
public @interface PhysicalDeviceStateProperties {}
/** @hide */
- @IntDef(prefix = {"PROPERTY_"}, flag = true, value = {
+ @IntDef(prefix = {"PROPERTY_"}, flag = false, value = {
PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL,
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
index 73a9e34..e474603 100644
--- a/core/java/android/hardware/devicestate/feature/flags.aconfig
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "device_state_property_api"
+ is_exported: true
namespace: "windowing_sdk"
description: "Updated DeviceState hasProperty API"
bug: "293636629"
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b0f69f5..81e321d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -83,8 +83,7 @@
/**
* A class that coordinates access to the fingerprint hardware.
- *
- * @removed See {@link BiometricPrompt} which shows a system-provided dialog upon starting
+ * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
* authentication. In a world where devices may have different types of biometric authentication,
* it's much more realistic to have a system-provided authentication dialog since the method may
* vary by vendor/device.
@@ -95,6 +94,7 @@
@RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
private static final String TAG = "FingerprintManager";
+ private static final boolean DEBUG = true;
private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -196,7 +196,6 @@
/**
* Retrieves a test session for FingerprintManager.
- *
* @hide
*/
@TestApi
@@ -255,10 +254,9 @@
}
/**
- * A wrapper class for the crypto objects supported by FingerprintManager. Currently, the
+ * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
- *
- * @removed See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
*/
@Deprecated
public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -332,8 +330,7 @@
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
* CancellationSignal, int, AuthenticationCallback, Handler)}.
- *
- * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
*/
@Deprecated
public static class AuthenticationResult {
@@ -395,8 +392,7 @@
* FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events.
- *
- * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
+ * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
*/
@Deprecated
public static abstract class AuthenticationCallback
@@ -459,7 +455,6 @@
/**
* Callback structure provided for {@link #detectFingerprint(CancellationSignal,
* FingerprintDetectionCallback, int, Surface)}.
- *
* @hide
*/
public interface FingerprintDetectionCallback {
@@ -613,8 +608,7 @@
* by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
* facility</a>.
* @throws IllegalStateException if the crypto primitive is not initialized.
- *
- * @removed See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+ * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
* BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
* BiometricPrompt.CryptoObject, CancellationSignal, Executor,
* BiometricPrompt.AuthenticationCallback)}
@@ -629,7 +623,6 @@
/**
* Per-user version of authenticate.
* @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
- *
* @hide
*/
@Deprecated
@@ -642,7 +635,6 @@
/**
* Per-user and per-sensor version of authenticate.
* @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
- *
* @hide
*/
@Deprecated
@@ -659,7 +651,6 @@
/**
* Version of authenticate with additional options.
- *
* @hide
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -707,7 +698,6 @@
/**
* Uses the fingerprint hardware to detect for the presence of a finger, without giving details
* about accept/reject/lockout.
- *
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -750,7 +740,6 @@
* @param callback an object to receive enrollment events
* @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics
* should be logged.
- *
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
@@ -821,7 +810,6 @@
/**
* Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first
* enumerated sensor.
- *
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
@@ -836,7 +824,6 @@
/**
* Revokes the specified challenge.
- *
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
@@ -862,7 +849,6 @@
* @param sensorId Sensor ID that this operation takes effect for
* @param userId User ID that this operation takes effect for.
* @param hardwareAuthToken An opaque token returned by password confirmation.
- *
* @hide
*/
@RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
@@ -900,7 +886,6 @@
/**
* Removes all fingerprint templates for the given user.
- *
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
@@ -1020,7 +1005,6 @@
/**
* Forwards BiometricStateListener to FingerprintService
* @param listener new BiometricStateListener being added
- *
* @hide
*/
public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
@@ -1172,8 +1156,7 @@
}
/**
- * This is triggered by SideFpsEventHandler.
- *
+ * This is triggered by SideFpsEventHandler
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1186,8 +1169,7 @@
* Determine if there is at least one fingerprint enrolled.
*
* @return true if at least one fingerprint is enrolled, false otherwise
- *
- * @removed See {@link BiometricPrompt} and
+ * @deprecated See {@link BiometricPrompt} and
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
*/
@Deprecated
@@ -1221,8 +1203,7 @@
* Determine if fingerprint hardware is present and functional.
*
* @return true if hardware is present and functional, false otherwise.
- *
- * @removed See {@link BiometricPrompt} and
+ * @deprecated See {@link BiometricPrompt} and
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
*/
@Deprecated
@@ -1248,7 +1229,6 @@
/**
* Get statically configured sensor properties.
- *
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1267,7 +1247,6 @@
/**
* Returns whether the device has a power button fingerprint sensor.
* @return boolean indicating whether power button is fingerprint sensor
- *
* @hide
*/
public boolean isPowerbuttonFps() {
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
index c6a352e..1165e65 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "overlayproperties_class_api"
+ is_exported: true
namespace: "core_graphics"
description: "public OverlayProperties class, OverlayProperties#supportMixedColorSpaces and Display#getOverlaySupport API"
bug: "267234573"
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index e070fe5..9684e64 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -27,6 +27,7 @@
flag {
namespace: "input_native"
name: "pointer_coords_is_resampled_api"
+ is_exported: true
description: "Makes MotionEvent.PointerCoords#isResampled() a public API"
bug: "298197511"
}
@@ -34,6 +35,7 @@
flag {
namespace: "input_native"
name: "emoji_and_screenshot_keycodes_available"
+ is_exported: true
description: "Add new KeyEvent keycodes for opening Emoji Picker and Taking Screenshots"
bug: "315307777"
}
diff --git a/core/java/android/hardware/radio/flags.aconfig b/core/java/android/hardware/radio/flags.aconfig
index dbc1a4b..d0d10c1 100644
--- a/core/java/android/hardware/radio/flags.aconfig
+++ b/core/java/android/hardware/radio/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "hd_radio_improved"
+ is_exported: true
namespace: "car_framework"
description: "Feature flag for improved HD radio support with less vendor extensions"
bug: "280300929"
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
index 9e487e1..fac02ce 100644
--- a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_usb_data_compliance_warning"
+ is_exported: true
namespace: "system_sw_usb"
description: "Enable USB data compliance warnings when set"
bug: "296119135"
diff --git a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
index a495631..3dd746c 100644
--- a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_is_pd_compliant_api"
+ is_exported: true
namespace: "usb"
description: "Feature flag for the api to check if a port is PD compliant"
bug: "323470419"
@@ -9,6 +10,7 @@
flag {
name: "enable_is_mode_change_supported_api"
+ is_exported: true
namespace: "usb"
description: "Feature flag for the api to check if a port supports mode change"
bug: "323470419"
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 83b7eda..6246dd7 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -20,10 +20,12 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.os.Binder;
@@ -69,8 +71,13 @@
* tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default.
* Additionally, during Safe Mode, the VCN will continue to retry the connections, and will
* automatically exit Safe Mode if all active tunnels connect successfully.
+ *
+ * <p>Apps targeting Android 15 or newer should check the existence of {@link
+ * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION} before querying the service. If the feature is
+ * absent, {@link Context#getSystemService} may return null.
*/
@SystemService(Context.VCN_MANAGEMENT_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 97b773e..e64823a 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -20,4 +20,18 @@
namespace: "vcn"
description: "Feature flag for enabling network metric monitor"
bug: "282996138"
+}
+
+flag{
+ name: "validate_network_on_ipsec_loss"
+ namespace: "vcn"
+ description: "Trigger network validation when IPsec packet loss exceeds the threshold"
+ bug: "329139898"
+}
+
+flag{
+ name: "evaluate_ipsec_loss_on_lp_nc_change"
+ namespace: "vcn"
+ description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change"
+ bug: "323238888"
}
\ No newline at end of file
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 387eebe..ed4037c 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -18,6 +18,7 @@
import static java.util.Objects.requireNonNull;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -31,6 +32,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.Serializable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -53,6 +56,53 @@
@VisibleForTesting
static final int FLAG_ALLOW_FDS = 1 << 10;
+ @VisibleForTesting
+ static final int FLAG_HAS_BINDERS_KNOWN = 1 << 11;
+
+ @VisibleForTesting
+ static final int FLAG_HAS_BINDERS = 1 << 12;
+
+
+ /**
+ * Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain
+ * Binder object(s).
+ *
+ * @hide
+ */
+ public static final int STATUS_BINDERS_NOT_PRESENT = 0;
+
+ /**
+ * Status when the Bundle can <b>assert</b> that there are Binder object(s) in the Parcel.
+ *
+ * @hide
+ */
+ public static final int STATUS_BINDERS_PRESENT = 1;
+
+ /**
+ * Status when the Bundle cannot be checked for Binders and there is no parcelled data
+ * available to check either.
+ * <p> This could happen when a Bundle is unparcelled or was never parcelled, and modified such
+ * that it is not possible to assert if the Bundle has any Binder objects in the current state.
+ *
+ * For e.g. calling {@link #putParcelable} or {@link #putBinder} could have added a Binder
+ * object to the Bundle but it is not possible to assert this fact unless the Bundle is written
+ * to a Parcel.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int STATUS_BINDERS_UNKNOWN = 2;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"STATUS_BINDERS_"}, value = {
+ STATUS_BINDERS_PRESENT,
+ STATUS_BINDERS_UNKNOWN,
+ STATUS_BINDERS_NOT_PRESENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HasBinderStatus {
+ }
+
/** An unmodifiable {@code Bundle} that is always {@link #isEmpty() empty}. */
public static final Bundle EMPTY;
@@ -75,7 +125,7 @@
*/
public Bundle() {
super();
- mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -111,7 +161,6 @@
*
* @param from The bundle to be copied.
* @param deep Whether is a deep or shallow copy.
- *
* @hide
*/
Bundle(Bundle from, boolean deep) {
@@ -143,7 +192,7 @@
*/
public Bundle(ClassLoader loader) {
super(loader);
- mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -154,7 +203,7 @@
*/
public Bundle(int capacity) {
super(capacity);
- mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -180,7 +229,7 @@
*/
public Bundle(PersistableBundle b) {
super(b);
- mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -292,6 +341,9 @@
if ((mFlags & FLAG_HAS_FDS) != 0) {
mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
+ if ((mFlags & FLAG_HAS_BINDERS) != 0) {
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
+ }
}
/**
@@ -306,13 +358,20 @@
bundle.mOwnsLazyValues = false;
mMap.putAll(bundle.mMap);
- // FD state is now known if and only if both bundles already knew
+ // FD and Binders state is now known if and only if both bundles already knew
if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
mFlags |= FLAG_HAS_FDS;
}
if ((bundle.mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
+
+ if ((bundle.mFlags & FLAG_HAS_BINDERS) != 0) {
+ mFlags |= FLAG_HAS_BINDERS;
+ }
+ if ((bundle.mFlags & FLAG_HAS_BINDERS_KNOWN) == 0) {
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
+ }
}
/**
@@ -343,6 +402,33 @@
return (mFlags & FLAG_HAS_FDS) != 0;
}
+ /**
+ * Returns a status indicating whether the bundle contains any parcelled Binder objects.
+ * @hide
+ */
+ public @HasBinderStatus int hasBinders() {
+ if ((mFlags & FLAG_HAS_BINDERS_KNOWN) != 0) {
+ if ((mFlags & FLAG_HAS_BINDERS) != 0) {
+ return STATUS_BINDERS_PRESENT;
+ } else {
+ return STATUS_BINDERS_NOT_PRESENT;
+ }
+ }
+
+ final Parcel p = mParcelledData;
+ if (p == null) {
+ return STATUS_BINDERS_UNKNOWN;
+ }
+ if (p.hasBinders()) {
+ mFlags = mFlags | FLAG_HAS_BINDERS | FLAG_HAS_BINDERS_KNOWN;
+ return STATUS_BINDERS_PRESENT;
+ } else {
+ mFlags = mFlags & ~FLAG_HAS_BINDERS;
+ mFlags |= FLAG_HAS_BINDERS_KNOWN;
+ return STATUS_BINDERS_NOT_PRESENT;
+ }
+ }
+
/** {@hide} */
@Override
public void putObject(@Nullable String key, @Nullable Object value) {
@@ -464,6 +550,7 @@
unparcel();
mMap.put(key, value);
mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
@@ -502,6 +589,7 @@
unparcel();
mMap.put(key, value);
mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
@@ -517,6 +605,7 @@
unparcel();
mMap.put(key, value);
mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/** {@hide} */
@@ -525,6 +614,7 @@
unparcel();
mMap.put(key, value);
mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
@@ -540,6 +630,7 @@
unparcel();
mMap.put(key, value);
mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
@@ -680,6 +771,7 @@
public void putBinder(@Nullable String key, @Nullable IBinder value) {
unparcel();
mMap.put(key, value);
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
@@ -697,6 +789,7 @@
public void putIBinder(@Nullable String key, @Nullable IBinder value) {
unparcel();
mMap.put(key, value);
+ mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
}
/**
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index ccfb632..bcef815 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -475,6 +475,10 @@
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native boolean nativeHasFileDescriptorsInRange(
long nativePtr, int offset, int length);
+
+ private static native boolean nativeHasBinders(long nativePtr);
+ private static native boolean nativeHasBindersInRange(
+ long nativePtr, int offset, int length);
@RavenwoodThrow
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
@RavenwoodThrow
@@ -970,6 +974,34 @@
}
/**
+ * Report whether the parcel contains any marshalled IBinder objects.
+ *
+ * @throws UnsupportedOperationException if binder kernel driver was disabled or if method was
+ * invoked in case of Binder RPC protocol.
+ * @hide
+ */
+ public boolean hasBinders() {
+ return nativeHasBinders(mNativePtr);
+ }
+
+ /**
+ * Report whether the parcel contains any marshalled {@link IBinder} objects in the range
+ * defined by {@code offset} and {@code length}.
+ *
+ * @param offset The offset from which the range starts. Should be between 0 and
+ * {@link #dataSize()}.
+ * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code
+ * offset}.
+ * @return whether there are binders in the range or not.
+ * @throws IllegalArgumentException if the parameters are out of the permitted ranges.
+ *
+ * @hide
+ */
+ public boolean hasBinders(int offset, int length) {
+ return nativeHasBindersInRange(mNativePtr, offset, length);
+ }
+
+ /**
* Store or read an IBinder interface token in the parcel at the current
* {@link #dataPosition}. This is used to validate that the marshalled
* transaction is intended for the target interface. This is typically written
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7020a38..db06a6b 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -48,6 +48,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.concurrent.TimeoutException;
/**
@@ -588,6 +589,8 @@
**/
public static final int THREAD_GROUP_RESTRICTED = 7;
+ /** @hide */
+ public static final int SIGNAL_DEFAULT = 0;
public static final int SIGNAL_QUIT = 3;
public static final int SIGNAL_KILL = 9;
public static final int SIGNAL_USR1 = 10;
@@ -1437,6 +1440,49 @@
sendSignal(pid, SIGNAL_KILL);
}
+ /**
+ * Check the tgid and tid pair to see if the tid still exists and belong to the tgid.
+ *
+ * TOCTOU warning: the status of the tid can change at the time this method returns. This should
+ * be used in very rare cases such as checking if a (tid, tgid) pair that is known to exist
+ * recently no longer exists now. As the possibility of the same tid to be reused under the same
+ * tgid during a short window is rare. And even if it happens the caller logic should be robust
+ * to handle it without error.
+ *
+ * @throws IllegalArgumentException if tgid or tid is not positive.
+ * @throws SecurityException if the caller doesn't have the permission, this method is expected
+ * to be used by system process with {@link #SYSTEM_UID} because it
+ * internally uses tkill(2).
+ * @throws NoSuchElementException if the Linux process with pid as the tid has exited or it
+ * doesn't belong to the tgid.
+ * @hide
+ */
+ public static final void checkTid(int tgid, int tid)
+ throws IllegalArgumentException, SecurityException, NoSuchElementException {
+ sendTgSignalThrows(tgid, tid, SIGNAL_DEFAULT);
+ }
+
+ /**
+ * Check if the pid still exists.
+ *
+ * TOCTOU warning: the status of the pid can change at the time this method returns. This should
+ * be used in very rare cases such as checking if a pid that belongs to an isolated process of a
+ * uid known to exist recently no longer exists now. As the possibility of the same pid to be
+ * reused again under the same uid during a short window is rare. And even if it happens the
+ * caller logic should be robust to handle it without error.
+ *
+ * @throws IllegalArgumentException if pid is not positive.
+ * @throws SecurityException if the caller doesn't have the permission, this method is expected
+ * to be used by system process with {@link #SYSTEM_UID} because it
+ * internally uses kill(2).
+ * @throws NoSuchElementException if the Linux process with the pid has exited.
+ * @hide
+ */
+ public static final void checkPid(int pid)
+ throws IllegalArgumentException, SecurityException, NoSuchElementException {
+ sendSignalThrows(pid, SIGNAL_DEFAULT);
+ }
+
/** @hide */
public static final native int setUid(int uid);
@@ -1451,6 +1497,12 @@
*/
public static final native void sendSignal(int pid, int signal);
+ private static native void sendSignalThrows(int pid, int signal)
+ throws IllegalArgumentException, SecurityException, NoSuchElementException;
+
+ private static native void sendTgSignalThrows(int pid, int tgid, int signal)
+ throws IllegalArgumentException, SecurityException, NoSuchElementException;
+
/**
* @hide
* Private impl for avoiding a log message... DO NOT USE without doing
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index bebb912..edb3a64 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -125,15 +125,15 @@
@UnsupportedAppUsage
@CriticalNative
@android.ravenwood.annotation.RavenwoodReplace
- private static native long nativeGetEnabledTags();
+ private static native boolean nativeIsTagEnabled(long tag);
@android.ravenwood.annotation.RavenwoodReplace
private static native void nativeSetAppTracingAllowed(boolean allowed);
@android.ravenwood.annotation.RavenwoodReplace
private static native void nativeSetTracingEnabled(boolean allowed);
- private static long nativeGetEnabledTags$ravenwood() {
+ private static boolean nativeIsTagEnabled$ravenwood(long traceTag) {
// Tracing currently completely disabled under Ravenwood
- return 0;
+ return false;
}
private static void nativeSetAppTracingAllowed$ravenwood(boolean allowed) {
@@ -181,8 +181,7 @@
@UnsupportedAppUsage
@SystemApi(client = MODULE_LIBRARIES)
public static boolean isTagEnabled(long traceTag) {
- long tags = nativeGetEnabledTags();
- return (tags & traceTag) != 0;
+ return nativeIsTagEnabled(traceTag);
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 84619a0..f172c3e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3188,6 +3188,8 @@
* @return whether the context user can add a private profile.
* @hide
*/
+ @TestApi
+ @FlaggedApi(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE)
@RequiresPermission(anyOf = {
Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS},
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 375d729..311e991 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -26,6 +26,7 @@
flag {
name: "remove_app_profiler_pss_collection"
+ is_exported: true
namespace: "backstage_power"
description: "Replaces background PSS collection in AppProfiler with RSS"
bug: "297542292"
@@ -33,6 +34,7 @@
flag {
name: "allow_thermal_headroom_thresholds"
+ is_exported: true
namespace: "game"
description: "Enable thermal headroom thresholds API"
bug: "288119641"
@@ -41,6 +43,7 @@
# This flag guards the private space feature, its APIs, and some of the feature implementations. The flag android.multiuser.Flags.enable_private_space_features exclusively guards all the implementations.
flag {
name: "allow_private_profile"
+ is_exported: true
namespace: "profile_experiences"
description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
bug: "299069460"
@@ -49,6 +52,7 @@
flag {
name: "bugreport_mode_max_value"
+ is_exported: true
namespace: "telephony"
description: "Introduce a constant as maximum value of bugreport mode."
bug: "305067125"
@@ -56,6 +60,7 @@
flag {
name: "adpf_prefer_power_efficiency"
+ is_exported: true
namespace: "game"
description: "Guards the ADPF power efficiency API"
bug: "288117936"
@@ -63,6 +68,7 @@
flag {
name: "security_state_service"
+ is_exported: true
namespace: "dynamic_spl"
description: "Guards the Security State API."
bug: "302189431"
@@ -70,6 +76,7 @@
flag {
name: "battery_saver_supported_check_api"
+ is_exported: true
namespace: "backstage_power"
description: "Guards a new API in PowerManager to check if battery saver is supported or not."
bug: "305067031"
@@ -77,6 +84,7 @@
flag {
name: "adpf_gpu_report_actual_work_duration"
+ is_exported: true
namespace: "game"
description: "Guards the ADPF GPU APIs."
bug: "284324521"
@@ -114,6 +122,7 @@
flag {
name: "battery_part_status_api"
+ is_exported: true
namespace: "phoenix"
description: "Feature flag for adding Health HAL v3 APIs."
is_fixed_read_only: true
@@ -122,6 +131,7 @@
flag {
name: "storage_lifetime_api"
+ is_exported: true
namespace: "phoenix"
description: "Feature flag for adding storage component health APIs."
is_fixed_read_only: true
@@ -131,6 +141,7 @@
flag {
namespace: "system_performance"
name: "telemetry_apis_framework_initialization"
+ is_exported: true
description: "Control framework initialization APIs of telemetry APIs feature."
is_fixed_read_only: true
bug: "324241334"
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index d485eca..bb0498e 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -10,6 +10,7 @@
flag {
namespace: "haptics"
name: "haptics_customization_enabled"
+ is_exported: true
description: "Enables the haptics customization feature"
bug: "241918098"
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 999bc99..2710df2 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "device_aware_permission_apis_enabled"
+ is_exported: true
is_fixed_read_only: true
namespace: "permissions"
description: "enable device aware permission APIs"
@@ -10,6 +11,7 @@
flag {
name: "voice_activation_permission_apis"
+ is_exported: true
namespace: "permissions"
description: "enable voice activation permission APIs"
bug: "287264308"
@@ -17,6 +19,7 @@
flag {
name: "system_server_role_controller_enabled"
+ is_exported: true
is_fixed_read_only: true
namespace: "permissions"
description: "enable role controller in system server"
@@ -25,6 +28,7 @@
flag {
name: "set_next_attribution_source"
+ is_exported: true
namespace: "permissions"
description: "enable AttributionSource.setNextAttributionSource"
bug: "304478648"
@@ -32,6 +36,7 @@
flag {
name: "should_register_attribution_source"
+ is_exported: true
namespace: "permissions"
description: "enable the shouldRegisterAttributionSource API"
bug: "305057691"
@@ -39,6 +44,7 @@
flag {
name: "attribution_source_constructor"
+ is_exported: true
namespace: "permissions"
description: "enable AttributionSource(int, int, String, String, IBinder, String[], AttributionSource)"
bug: "304478648"
@@ -46,6 +52,7 @@
flag {
name: "enhanced_confirmation_mode_apis_enabled"
+ is_exported: true
is_fixed_read_only: true
namespace: "permissions"
description: "enable enhanced confirmation mode apis"
@@ -54,6 +61,7 @@
flag {
name: "op_enable_mobile_data_by_user"
+ is_exported: true
namespace: "permissions"
description: "enables logging of the OP_ENABLE_MOBILE_DATA_BY_USER"
bug: "222650148"
@@ -61,6 +69,7 @@
flag {
name: "factory_reset_prep_permission_apis"
+ is_exported: true
namespace: "wallet_integration"
description: "enable Permission PREPARE_FACTORY_RESET."
bug: "302016478"
@@ -68,6 +77,7 @@
flag {
name: "retail_demo_role_enabled"
+ is_exported: true
namespace: "permissions"
description: "default retail demo role holder"
bug: "274132354"
@@ -82,6 +92,7 @@
flag {
name: "wallet_role_enabled"
+ is_exported: true
namespace: "wallet_integration"
description: "This flag is used to enabled the Wallet Role for all users on the device"
bug: "283989236"
@@ -114,6 +125,7 @@
flag {
name: "get_emergency_role_holder_api_enabled"
+ is_exported: true
is_fixed_read_only: true
namespace: "permissions"
description: "Enables the getEmergencyRoleHolder API."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e26dc73..ec5421e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,6 +16,8 @@
package android.provider;
+import static android.app.Flags.systemTermsOfAddressEnabled;
+
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
@@ -37,6 +39,7 @@
import android.app.AppOpsManager;
import android.app.Application;
import android.app.AutomaticZenRule;
+import android.app.GrammaticalInflectionManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.SearchManager;
@@ -4594,6 +4597,13 @@
}
outConfig.fontWeightAdjustment = Settings.Secure.getIntForUser(
cr, Settings.Secure.FONT_WEIGHT_ADJUSTMENT, DEFAULT_FONT_WEIGHT, userHandle);
+ if (systemTermsOfAddressEnabled()) {
+ GrammaticalInflectionManager manager =
+ ActivityThread.currentApplication().getApplicationContext()
+ .getSystemService(GrammaticalInflectionManager.class);
+ outConfig.setGrammaticalGender(
+ manager.peekSystemGrammaticalGenderByUserId(userHandle));
+ }
final String localeValue =
Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle);
@@ -8502,6 +8512,19 @@
public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets";
/**
+ * Setting specifying the accessibility services, shortcut targets or features
+ * to be toggled via the floating accessibility menu
+ *
+ * <p> This is a colon-separated string list which contains the flattened
+ * {@link ComponentName} and the class name of a system class
+ * implementing a supported accessibility feature.
+ * @hide
+ */
+ @Readable
+ public static final String ACCESSIBILITY_FLOATING_MENU_TARGETS =
+ "accessibility_floating_menu_targets";
+
+ /**
* Setting specifying the accessibility services, accessibility shortcut targets,
* or features to be toggled via a tile in the quick settings panel.
*
@@ -11090,21 +11113,12 @@
"assist_long_press_home_enabled";
/**
- * Whether press and hold on nav handle can trigger search.
+ * Whether all entrypoints can trigger search. Replaces individual settings.
*
* @hide
*/
- public static final String SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED =
- "search_press_hold_nav_handle_enabled";
-
- /**
- * Whether long-pressing on the home button can trigger search.
- *
- * @hide
- */
- public static final String SEARCH_LONG_PRESS_HOME_ENABLED =
- "search_long_press_home_enabled";
-
+ public static final String SEARCH_ALL_ENTRYPOINTS_ENABLED =
+ "search_all_entrypoints_enabled";
/**
* Whether or not the accessibility data streaming is enbled for the
@@ -12395,6 +12409,17 @@
*/
public static final String HIDE_PRIVATESPACE_ENTRY_POINT = "hide_privatespace_entry_point";
+ /**
+ * Whether or not secure windows should be disabled. This only works on debuggable builds.
+ *
+ * <p>When this setting is set to a non-zero value, all windows are treated as non-secure.
+ * Content in windows with {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} will
+ * appear in screenshots and recordings.
+ *
+ * @hide
+ */
+ public static final String DISABLE_SECURE_WINDOWS = "disable_secure_windows";
+
/** @hide */
public static final int PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK = 0;
/** @hide */
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index ea1ac27..d0cef83 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -1,7 +1,15 @@
package: "android.provider"
flag {
+ name: "a11y_standalone_fab_enabled"
+ namespace: "accessibility"
+ description: "Separating a11y software shortcut and floating a11y button"
+ bug: "297544054"
+}
+
+flag {
name: "system_settings_default"
+ is_exported: true
namespace: "package_manager_service"
description: "Enable Settings.System.resetToDefault APIs."
bug: "279083734"
@@ -9,6 +17,7 @@
flag {
name: "user_keys"
+ is_exported: true
namespace: "privacy_infra_policy"
description: "This flag controls new E2EE contact keys API"
bug: "290696572"
@@ -16,7 +25,8 @@
flag {
name: "backup_tasks_settings_screen"
+ is_exported: true
namespace: "backstage_power"
description: "Add a new settings page for the RUN_BACKUP_JOBS permission."
bug: "320563660"
-}
+}
\ No newline at end of file
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 3c77c44..7f5b550 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -10,6 +10,7 @@
flag {
name: "fsverity_api"
+ is_exported: true
namespace: "hardware_backed_security"
description: "Feature flag for fs-verity API"
bug: "285185747"
@@ -64,6 +65,7 @@
flag {
name: "frp_enforcement"
+ is_exported: true
namespace: "hardware_backed_security"
description: "This flag controls whether PDB enforces FRP"
bug: "290312729"
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 0bae459..548f8aa 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -9,6 +9,7 @@
flag {
name: "asm_restrictions_enabled"
+ is_exported: true
namespace: "responsible_apis"
description: "Enables ASM restrictions for activity starts and finishes"
bug: "230590090"
@@ -23,6 +24,7 @@
flag {
name: "content_uri_permission_apis"
+ is_exported: true
namespace: "responsible_apis"
description: "Enables the content URI permission APIs"
bug: "293467489"
@@ -30,6 +32,7 @@
flag {
name: "enforce_intent_filter_match"
+ is_exported: true
namespace: "responsible_apis"
description: "Make delivered intents match components' intent filters"
bug: "293560872"
diff --git a/core/java/android/service/appprediction/flags/flags.aconfig b/core/java/android/service/appprediction/flags/flags.aconfig
index c7e47d4..7f9764e 100644
--- a/core/java/android/service/appprediction/flags/flags.aconfig
+++ b/core/java/android/service/appprediction/flags/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "service_features_api"
+ is_exported: true
namespace: "systemui"
description: "Guards the new requestServiceFeatures api"
bug: "292565550"
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index d72441f..a3eff3b 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "chooser_album_text"
+ is_exported: true
namespace: "intentresolver"
description: "Flag controlling the album text subtype hint for sharesheet"
bug: "323380224"
@@ -9,6 +10,7 @@
flag {
name: "enable_sharesheet_metadata_extra"
+ is_exported: true
namespace: "intentresolver"
description: "This flag enables sharesheet metadata to be displayed to users."
bug: "318942069"
@@ -16,6 +18,7 @@
flag {
name: "chooser_payload_toggling"
+ is_exported: true
namespace: "intentresolver"
description: "This flag controls content toggling in Chooser"
bug: "302691505"
@@ -23,18 +26,8 @@
flag {
name: "enable_chooser_result"
+ is_exported: true
namespace: "intentresolver"
description: "Provides additional callbacks with information about user actions in ChooserResult"
bug: "263474465"
}
-
-flag {
- name: "legacy_chooser_pinning_removal"
- namespace: "intentresolver"
- description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)"
- bug: "301068735"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
diff --git a/core/java/android/service/controls/flags/flags.aconfig b/core/java/android/service/controls/flags/flags.aconfig
index 3a28844..197f1bc 100644
--- a/core/java/android/service/controls/flags/flags.aconfig
+++ b/core/java/android/service/controls/flags/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "home_panel_dream"
+ is_exported: true
namespace: "systemui"
description: "Enables the home controls dream feature."
bug: "298025023"
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index c5acc2c..35cd3ed 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -10,6 +10,7 @@
flag {
name: "redact_sensitive_notifications_from_untrusted_listeners"
+ is_exported: true
namespace: "systemui"
description: "This flag controls the redacting of sensitive notifications from untrusted NotificationListenerServices"
bug: "306271190"
@@ -18,6 +19,7 @@
flag {
name: "callstyle_callback_api"
+ is_exported: true
namespace: "systemui"
description: "Guards the new CallStyleNotificationEventsCallback"
bug: "305095040"
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
index 6dbff71..908ab5f 100644
--- a/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
@@ -41,7 +41,9 @@
void getFeatureDetails(int callerUid, in Feature feature, in IFeatureDetailsCallback featureDetailsCallback);
void getReadOnlyFileDescriptor(in String fileName, in AndroidFuture<ParcelFileDescriptor> future);
void getReadOnlyFeatureFileDescriptorMap(in Feature feature, in RemoteCallback remoteCallback);
- void requestFeatureDownload(int callerUid, in Feature feature, in ICancellationSignal cancellationSignal, in IDownloadCallback downloadCallback);
+ void requestFeatureDownload(int callerUid, in Feature feature,
+ in AndroidFuture<ICancellationSignal> cancellationSignal,
+ in IDownloadCallback downloadCallback);
void registerRemoteServices(in IRemoteProcessingService remoteProcessingService);
void notifyInferenceServiceConnected();
void notifyInferenceServiceDisconnected();
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl
index 799c7545..4213a09 100644
--- a/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceSandboxedInferenceService.aidl
@@ -24,6 +24,7 @@
import android.os.ICancellationSignal;
import android.os.PersistableBundle;
import android.os.Bundle;
+import com.android.internal.infra.AndroidFuture;
import android.service.ondeviceintelligence.IRemoteStorageService;
import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
@@ -34,13 +35,16 @@
*/
oneway interface IOnDeviceSandboxedInferenceService {
void registerRemoteStorageService(in IRemoteStorageService storageService);
- void requestTokenInfo(int callerUid, in Feature feature, in Bundle request, in ICancellationSignal cancellationSignal,
+ void requestTokenInfo(int callerUid, in Feature feature, in Bundle request,
+ in AndroidFuture<ICancellationSignal> cancellationSignal,
in ITokenInfoCallback tokenInfoCallback);
void processRequest(int callerUid, in Feature feature, in Bundle request, in int requestType,
- in ICancellationSignal cancellationSignal, in IProcessingSignal processingSignal,
+ in AndroidFuture<ICancellationSignal> cancellationSignal,
+ in AndroidFuture<IProcessingSignal> processingSignal,
in IResponseCallback callback);
void processRequestStreaming(int callerUid, in Feature feature, in Bundle request, in int requestType,
- in ICancellationSignal cancellationSignal, in IProcessingSignal processingSignal,
+ in AndroidFuture<ICancellationSignal> cancellationSignal,
+ in AndroidFuture<IProcessingSignal> processingSignal,
in IStreamingResponseCallback callback);
void updateProcessingState(in Bundle processingState,
in IProcessingUpdateStatusCallback callback);
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
index 9321318..86320b8 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
@@ -148,14 +148,18 @@
@Override
public void requestFeatureDownload(int callerUid, Feature feature,
- ICancellationSignal cancellationSignal,
+ AndroidFuture cancellationSignalFuture,
IDownloadCallback downloadCallback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(downloadCallback);
-
+ ICancellationSignal transport = null;
+ if (cancellationSignalFuture != null) {
+ transport = CancellationSignal.createTransport();
+ cancellationSignalFuture.complete(transport);
+ }
OnDeviceIntelligenceService.this.onDownloadFeature(callerUid,
feature,
- CancellationSignal.fromTransport(cancellationSignal),
+ CancellationSignal.fromTransport(transport),
wrapDownloadCallback(downloadCallback));
}
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
index fc7a4c8..96c45ee 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
@@ -122,46 +122,72 @@
@Override
public void requestTokenInfo(int callerUid, Feature feature, Bundle request,
- ICancellationSignal cancellationSignal,
+ AndroidFuture cancellationSignalFuture,
ITokenInfoCallback tokenInfoCallback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(tokenInfoCallback);
+ ICancellationSignal transport = null;
+ if (cancellationSignalFuture != null) {
+ transport = CancellationSignal.createTransport();
+ cancellationSignalFuture.complete(transport);
+ }
OnDeviceSandboxedInferenceService.this.onTokenInfoRequest(callerUid,
feature,
request,
- CancellationSignal.fromTransport(cancellationSignal),
+ CancellationSignal.fromTransport(transport),
wrapTokenInfoCallback(tokenInfoCallback));
}
@Override
public void processRequestStreaming(int callerUid, Feature feature, Bundle request,
- int requestType, ICancellationSignal cancellationSignal,
- IProcessingSignal processingSignal,
+ int requestType,
+ AndroidFuture cancellationSignalFuture,
+ AndroidFuture processingSignalFuture,
IStreamingResponseCallback callback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(callback);
+ ICancellationSignal transport = null;
+ if (cancellationSignalFuture != null) {
+ transport = CancellationSignal.createTransport();
+ cancellationSignalFuture.complete(transport);
+ }
+ IProcessingSignal processingSignalTransport = null;
+ if (processingSignalFuture != null) {
+ processingSignalTransport = ProcessingSignal.createTransport();
+ processingSignalFuture.complete(processingSignalTransport);
+ }
OnDeviceSandboxedInferenceService.this.onProcessRequestStreaming(callerUid,
feature,
request,
requestType,
- CancellationSignal.fromTransport(cancellationSignal),
- ProcessingSignal.fromTransport(processingSignal),
+ CancellationSignal.fromTransport(transport),
+ ProcessingSignal.fromTransport(processingSignalTransport),
wrapStreamingResponseCallback(callback));
}
@Override
public void processRequest(int callerUid, Feature feature, Bundle request,
- int requestType, ICancellationSignal cancellationSignal,
- IProcessingSignal processingSignal,
+ int requestType,
+ AndroidFuture cancellationSignalFuture,
+ AndroidFuture processingSignalFuture,
IResponseCallback callback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(callback);
-
+ ICancellationSignal transport = null;
+ if (cancellationSignalFuture != null) {
+ transport = CancellationSignal.createTransport();
+ cancellationSignalFuture.complete(transport);
+ }
+ IProcessingSignal processingSignalTransport = null;
+ if (processingSignalFuture != null) {
+ processingSignalTransport = ProcessingSignal.createTransport();
+ processingSignalFuture.complete(processingSignalTransport);
+ }
OnDeviceSandboxedInferenceService.this.onProcessRequest(callerUid, feature,
request, requestType,
- CancellationSignal.fromTransport(cancellationSignal),
- ProcessingSignal.fromTransport(processingSignal),
+ CancellationSignal.fromTransport(transport),
+ ProcessingSignal.fromTransport(processingSignalTransport),
wrapResponseCallback(callback));
}
@@ -206,7 +232,8 @@
* Invoked when caller provides a request for a particular feature to be processed in a
* streaming manner. The expectation from the implementation is that when processing the
* request,
- * it periodically populates the {@link StreamingProcessingCallback#onPartialResult} to continuously
+ * it periodically populates the {@link StreamingProcessingCallback#onPartialResult} to
+ * continuously
* provide partial Bundle results for the caller to utilize. Optionally the implementation can
* provide the complete response in the {@link StreamingProcessingCallback#onResult} upon
* processing completion.
diff --git a/core/java/android/service/voice/VisualQueryDetectionService.java b/core/java/android/service/voice/VisualQueryDetectionService.java
index 887b575..b9f4c32 100644
--- a/core/java/android/service/voice/VisualQueryDetectionService.java
+++ b/core/java/android/service/voice/VisualQueryDetectionService.java
@@ -262,7 +262,6 @@
public void onStopDetection() {
}
- // TODO(b/324341724): Properly deprecate this API.
/**
* Informs the system that the attention is gained for the interaction intention
* {@link VisualQueryAttentionResult#INTERACTION_INTENTION_AUDIO_VISUAL} with
@@ -343,7 +342,6 @@
}
}
- // TODO(b/324341724): Properly deprecate this API.
/**
* Informs the {@link VisualQueryDetector} with the text content being captured about the
* query from the audio source. {@code partialQuery} is provided to the
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index bf8de06..11858e8 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -301,8 +301,15 @@
}
/**
- * A class that lets a VoiceInteractionService implementation interact with
- * visual query detection APIs.
+ * A class that lets a VoiceInteractionService implementation interact with visual query
+ * detection APIs.
+ *
+ * Note that methods in this callbacks are not thread-safe so the invocation of each
+ * methods will have different order from how they are called in the
+ * {@link VisualQueryDetectionService}. It is expected to pass a single thread executor or a
+ * serial executor as the callback executor when creating the {@link VisualQueryDetector}
+ * with {@link VoiceInteractionService#createVisualQueryDetector(
+ * PersistableBundle, SharedMemory, Executor, Callback)}.
*/
public interface Callback {
@@ -456,7 +463,7 @@
Slog.v(TAG, "BinderCallback#onResultDetected");
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
- mCallback.onQueryDetected(partialResult);
+ mExecutor.execute(()->mCallback.onQueryDetected(partialResult));
}
});
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 306410c..2f2a670 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -932,7 +932,10 @@
* @param sharedMemory The unrestricted data blob to be provided to the
* {@link VisualQueryDetectionService}. Use this to provide models or other such data to the
* sandboxed process.
- * @param callback The callback to notify of detection events.
+ * @param callback The callback to notify of detection events. Single threaded or sequential
+ * executors are recommended for the callback are not guaranteed to be executed
+ * in the order of how they were called from the
+ * {@link VisualQueryDetectionService}.
* @return An instanece of {@link VisualQueryDetector}.
* @throws IllegalStateException when there is an existing {@link VisualQueryDetector}, or when
* there is a non-trusted hotword detector running.
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index 22e8cdd..633304b 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "allow_training_data_egress_from_hds"
+ is_exported: true
namespace: "machine_learning"
description: "This flag allows the hotword detection service to egress training data to the default assistant."
bug: "296074924"
@@ -9,6 +10,7 @@
flag {
name: "allow_hotword_bump_egress"
+ is_exported: true
namespace: "machine_learning"
description: "This flag allows hotword detection service to egress reason code for hotword bump."
bug: "290951024"
@@ -16,6 +18,7 @@
flag {
name: "allow_foreground_activities_in_on_show"
+ is_exported: true
namespace: "machine_learning"
description: "This flag allows providing foreground app component along with onShow args."
bug: "319409708"
@@ -23,6 +26,7 @@
flag {
name: "allow_various_attention_types"
+ is_exported: true
namespace: "visual_query"
description: "This flag allows visual query detection service to set different attention types."
bug: "318617199"
@@ -30,6 +34,7 @@
flag {
name: "allow_complex_results_egress_from_vqds"
+ is_exported: true
namespace: "visual_query"
description: "This flag allows visual query detection service egress detailed results. "
bug: "318617199"
@@ -37,6 +42,7 @@
flag {
name: "allow_speaker_id_egress"
+ is_exported: true
namespace: "machine_learning"
description: "This flag allows hotword detection service and visual query detection service to egress current speaker profile id."
bug: "318617199"
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bbda068..f6d197c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -102,6 +102,7 @@
import android.view.WindowLayout;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import android.window.ScreenCapture;
@@ -211,7 +212,7 @@
* @hide
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public static final long WEAROS_WALLPAPER_HANDLES_SCALING = 272527315L;
static final class WallpaperCommand {
@@ -459,7 +460,8 @@
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
- int syncSeqId, boolean dragResizing) {
+ int syncSeqId, boolean dragResizing,
+ @Nullable ActivityWindowInfo activityWindowInfo) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
diff --git a/core/java/android/speech/flags/speech_flags.aconfig b/core/java/android/speech/flags/speech_flags.aconfig
index fd80127..fa33592 100644
--- a/core/java/android/speech/flags/speech_flags.aconfig
+++ b/core/java/android/speech/flags/speech_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "multilang_extra_launch"
+ is_exported: true
namespace: "machine_learning"
description: "Feature flag for adding new extra for multi-lang feature"
bug: "312489931"
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index e95b216..9db8aa1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -28,7 +28,6 @@
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.text.LineBreakConfig;
-import android.os.Trace;
import android.text.style.ParagraphStyle;
/**
@@ -568,59 +567,49 @@
public static @Nullable Metrics isBoring(@NonNull CharSequence text, @NonNull TextPaint paint,
@NonNull TextDirectionHeuristic textDir, boolean useFallbackLineSpacing,
@Nullable Paint.FontMetrics minimumFontMetrics, @Nullable Metrics metrics) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("BoringLayout#isBoring");
- Trace.setCounter("BoringLayout#textLength", text.length());
+ final int textLength = text.length();
+ if (hasAnyInterestingChars(text, textLength)) {
+ return null; // There are some interesting characters. Not boring.
}
- try {
- final int textLength = text.length();
- if (hasAnyInterestingChars(text, textLength)) {
- return null; // There are some interesting characters. Not boring.
- }
- if (textDir != null && textDir.isRtl(text, 0, textLength)) {
- return null; // The heuristic considers the whole text RTL. Not boring.
- }
- if (text instanceof Spanned) {
- Spanned sp = (Spanned) text;
- Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
- if (styles.length > 0) {
- return null; // There are some ParagraphStyle spans. Not boring.
- }
- }
-
- Metrics fm = metrics;
- if (fm == null) {
- fm = new Metrics();
- } else {
- fm.reset();
- }
-
- if (ClientFlags.fixLineHeightForLocale()) {
- if (minimumFontMetrics != null) {
- fm.set(minimumFontMetrics);
- // Because the font metrics is provided by public APIs, adjust the top/bottom
- // with ascent/descent: top must be smaller than ascent, bottom must be larger
- // than descent.
- fm.top = Math.min(fm.top, fm.ascent);
- fm.bottom = Math.max(fm.bottom, fm.descent);
- }
- }
-
- TextLine line = TextLine.obtain();
- line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
- Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
- 0 /* ellipsisStart, 0 since text has not been ellipsized at this point */,
- 0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */,
- useFallbackLineSpacing);
- fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false, null));
- TextLine.recycle(line);
-
- return fm;
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
+ if (textDir != null && textDir.isRtl(text, 0, textLength)) {
+ return null; // The heuristic considers the whole text RTL. Not boring.
+ }
+ if (text instanceof Spanned) {
+ Spanned sp = (Spanned) text;
+ Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
+ if (styles.length > 0) {
+ return null; // There are some ParagraphStyle spans. Not boring.
}
}
+
+ Metrics fm = metrics;
+ if (fm == null) {
+ fm = new Metrics();
+ } else {
+ fm.reset();
+ }
+
+ if (ClientFlags.fixLineHeightForLocale()) {
+ if (minimumFontMetrics != null) {
+ fm.set(minimumFontMetrics);
+ // Because the font metrics is provided by public APIs, adjust the top/bottom with
+ // ascent/descent: top must be smaller than ascent, bottom must be larger than
+ // descent.
+ fm.top = Math.min(fm.top, fm.ascent);
+ fm.bottom = Math.max(fm.bottom, fm.descent);
+ }
+ }
+
+ TextLine line = TextLine.obtain();
+ line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
+ Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
+ 0 /* ellipsisStart, 0 since text has not been ellipsized at this point */,
+ 0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */,
+ useFallbackLineSpacing);
+ fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false, null));
+ TextLine.recycle(line);
+
+ return fm;
}
@Override
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 99ce0ef..cce4f7b 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -31,7 +31,6 @@
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
import android.os.Build;
-import android.os.Trace;
import android.text.method.OffsetMapping;
import android.text.style.ReplacementSpan;
import android.text.style.UpdateLayout;
@@ -637,224 +636,207 @@
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public void reflow(CharSequence s, int where, int before, int after) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("DynamicLayout#reflow");
+ if (s != mBase)
+ return;
+
+ CharSequence text = mDisplay;
+ int len = text.length();
+
+ // seek back to the start of the paragraph
+
+ int find = TextUtils.lastIndexOf(text, '\n', where - 1);
+ if (find < 0)
+ find = 0;
+ else
+ find = find + 1;
+
+ {
+ int diff = where - find;
+ before += diff;
+ after += diff;
+ where -= diff;
}
- try {
- if (s != mBase) {
- return;
- }
- CharSequence text = mDisplay;
- int len = text.length();
+ // seek forward to the end of the paragraph
- // seek back to the start of the paragraph
+ int look = TextUtils.indexOf(text, '\n', where + after);
+ if (look < 0)
+ look = len;
+ else
+ look++; // we want the index after the \n
- int find = TextUtils.lastIndexOf(text, '\n', where - 1);
- if (find < 0) {
- find = 0;
- } else {
- find = find + 1;
- }
+ int change = look - (where + after);
+ before += change;
+ after += change;
- {
- int diff = where - find;
- before += diff;
- after += diff;
- where -= diff;
- }
+ // seek further out to cover anything that is forced to wrap together
- // seek forward to the end of the paragraph
+ if (text instanceof Spanned) {
+ Spanned sp = (Spanned) text;
+ boolean again;
- int look = TextUtils.indexOf(text, '\n', where + after);
- if (look < 0) {
- look = len;
- } else {
- look++; // we want the index after the \n
- }
+ do {
+ again = false;
- int change = look - (where + after);
- before += change;
- after += change;
+ Object[] force = sp.getSpans(where, where + after,
+ WrapTogetherSpan.class);
- // seek further out to cover anything that is forced to wrap together
+ for (int i = 0; i < force.length; i++) {
+ int st = sp.getSpanStart(force[i]);
+ int en = sp.getSpanEnd(force[i]);
- if (text instanceof Spanned) {
- Spanned sp = (Spanned) text;
- boolean again;
+ if (st < where) {
+ again = true;
- do {
- again = false;
-
- Object[] force = sp.getSpans(where, where + after,
- WrapTogetherSpan.class);
-
- for (int i = 0; i < force.length; i++) {
- int st = sp.getSpanStart(force[i]);
- int en = sp.getSpanEnd(force[i]);
-
- if (st < where) {
- again = true;
-
- int diff = where - st;
- before += diff;
- after += diff;
- where -= diff;
- }
-
- if (en > where + after) {
- again = true;
-
- int diff = en - (where + after);
- before += diff;
- after += diff;
- }
+ int diff = where - st;
+ before += diff;
+ after += diff;
+ where -= diff;
}
- } while (again);
- }
- // find affected region of old layout
+ if (en > where + after) {
+ again = true;
- int startline = getLineForOffset(where);
- int startv = getLineTop(startline);
+ int diff = en - (where + after);
+ before += diff;
+ after += diff;
+ }
+ }
+ } while (again);
+ }
- int endline = getLineForOffset(where + before);
- if (where + after == len) {
- endline = getLineCount();
- }
- int endv = getLineTop(endline);
- boolean islast = (endline == getLineCount());
+ // find affected region of old layout
- // generate new layout for affected text
+ int startline = getLineForOffset(where);
+ int startv = getLineTop(startline);
- StaticLayout reflowed;
- StaticLayout.Builder b;
+ int endline = getLineForOffset(where + before);
+ if (where + after == len)
+ endline = getLineCount();
+ int endv = getLineTop(endline);
+ boolean islast = (endline == getLineCount());
- synchronized (sLock) {
- reflowed = sStaticLayout;
- b = sBuilder;
- sStaticLayout = null;
- sBuilder = null;
- }
+ // generate new layout for affected text
- if (b == null) {
- b = StaticLayout.Builder.obtain(text, where, where + after, getPaint(), getWidth());
- }
+ StaticLayout reflowed;
+ StaticLayout.Builder b;
- b.setText(text, where, where + after)
- .setPaint(getPaint())
- .setWidth(getWidth())
- .setTextDirection(getTextDirectionHeuristic())
- .setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
- .setUseLineSpacingFromFallbacks(mFallbackLineSpacing)
- .setEllipsizedWidth(mEllipsizedWidth)
- .setEllipsize(mEllipsizeAt)
- .setBreakStrategy(mBreakStrategy)
- .setHyphenationFrequency(mHyphenationFrequency)
- .setJustificationMode(mJustificationMode)
- .setLineBreakConfig(mLineBreakConfig)
- .setAddLastLineLineSpacing(!islast)
- .setIncludePad(false)
- .setUseBoundsForWidth(mUseBoundsForWidth)
- .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
- .setMinimumFontMetrics(mMinimumFontMetrics)
- .setCalculateBounds(true);
+ synchronized (sLock) {
+ reflowed = sStaticLayout;
+ b = sBuilder;
+ sStaticLayout = null;
+ sBuilder = null;
+ }
- reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */,
- reflowed);
- int n = reflowed.getLineCount();
- // If the new layout has a blank line at the end, but it is not
- // the very end of the buffer, then we already have a line that
- // starts there, so disregard the blank line.
+ if (b == null) {
+ b = StaticLayout.Builder.obtain(text, where, where + after, getPaint(), getWidth());
+ }
- if (where + after != len && reflowed.getLineStart(n - 1) == where + after) {
- n--;
- }
+ b.setText(text, where, where + after)
+ .setPaint(getPaint())
+ .setWidth(getWidth())
+ .setTextDirection(getTextDirectionHeuristic())
+ .setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
+ .setUseLineSpacingFromFallbacks(mFallbackLineSpacing)
+ .setEllipsizedWidth(mEllipsizedWidth)
+ .setEllipsize(mEllipsizeAt)
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency)
+ .setJustificationMode(mJustificationMode)
+ .setLineBreakConfig(mLineBreakConfig)
+ .setAddLastLineLineSpacing(!islast)
+ .setIncludePad(false)
+ .setUseBoundsForWidth(mUseBoundsForWidth)
+ .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
+ .setMinimumFontMetrics(mMinimumFontMetrics)
+ .setCalculateBounds(true);
- // remove affected lines from old layout
- mInts.deleteAt(startline, endline - startline);
- mObjects.deleteAt(startline, endline - startline);
+ reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */, reflowed);
+ int n = reflowed.getLineCount();
+ // If the new layout has a blank line at the end, but it is not
+ // the very end of the buffer, then we already have a line that
+ // starts there, so disregard the blank line.
- // adjust offsets in layout for new height and offsets
+ if (where + after != len && reflowed.getLineStart(n - 1) == where + after)
+ n--;
- int ht = reflowed.getLineTop(n);
- int toppad = 0, botpad = 0;
+ // remove affected lines from old layout
+ mInts.deleteAt(startline, endline - startline);
+ mObjects.deleteAt(startline, endline - startline);
- if (mIncludePad && startline == 0) {
- toppad = reflowed.getTopPadding();
- mTopPadding = toppad;
- ht -= toppad;
- }
- if (mIncludePad && islast) {
- botpad = reflowed.getBottomPadding();
- mBottomPadding = botpad;
- ht += botpad;
- }
+ // adjust offsets in layout for new height and offsets
- mInts.adjustValuesBelow(startline, START, after - before);
- mInts.adjustValuesBelow(startline, TOP, startv - endv + ht);
+ int ht = reflowed.getLineTop(n);
+ int toppad = 0, botpad = 0;
- // insert new layout
+ if (mIncludePad && startline == 0) {
+ toppad = reflowed.getTopPadding();
+ mTopPadding = toppad;
+ ht -= toppad;
+ }
+ if (mIncludePad && islast) {
+ botpad = reflowed.getBottomPadding();
+ mBottomPadding = botpad;
+ ht += botpad;
+ }
- int[] ints;
+ mInts.adjustValuesBelow(startline, START, after - before);
+ mInts.adjustValuesBelow(startline, TOP, startv - endv + ht);
+
+ // insert new layout
+
+ int[] ints;
+
+ if (mEllipsize) {
+ ints = new int[COLUMNS_ELLIPSIZE];
+ ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED;
+ } else {
+ ints = new int[COLUMNS_NORMAL];
+ }
+
+ Directions[] objects = new Directions[1];
+
+ for (int i = 0; i < n; i++) {
+ final int start = reflowed.getLineStart(i);
+ ints[START] = start;
+ ints[DIR] |= reflowed.getParagraphDirection(i) << DIR_SHIFT;
+ ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;
+
+ int top = reflowed.getLineTop(i) + startv;
+ if (i > 0)
+ top -= toppad;
+ ints[TOP] = top;
+
+ int desc = reflowed.getLineDescent(i);
+ if (i == n - 1)
+ desc += botpad;
+
+ ints[DESCENT] = desc;
+ ints[EXTRA] = reflowed.getLineExtra(i);
+ objects[0] = reflowed.getLineDirections(i);
+
+ final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
+ ints[HYPHEN] = StaticLayout.packHyphenEdit(
+ reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i));
+ ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |=
+ contentMayProtrudeFromLineTopOrBottom(text, start, end) ?
+ MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;
if (mEllipsize) {
- ints = new int[COLUMNS_ELLIPSIZE];
- ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED;
- } else {
- ints = new int[COLUMNS_NORMAL];
+ ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
+ ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
}
- Directions[] objects = new Directions[1];
+ mInts.insertAt(startline + i, ints);
+ mObjects.insertAt(startline + i, objects);
+ }
- for (int i = 0; i < n; i++) {
- final int start = reflowed.getLineStart(i);
- ints[START] = start;
- ints[DIR] |= reflowed.getParagraphDirection(i) << DIR_SHIFT;
- ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;
+ updateBlocks(startline, endline - 1, n);
- int top = reflowed.getLineTop(i) + startv;
- if (i > 0) {
- top -= toppad;
- }
- ints[TOP] = top;
-
- int desc = reflowed.getLineDescent(i);
- if (i == n - 1) {
- desc += botpad;
- }
-
- ints[DESCENT] = desc;
- ints[EXTRA] = reflowed.getLineExtra(i);
- objects[0] = reflowed.getLineDirections(i);
-
- final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
- ints[HYPHEN] = StaticLayout.packHyphenEdit(
- reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i));
- ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |=
- contentMayProtrudeFromLineTopOrBottom(text, start, end)
- ? MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;
-
- if (mEllipsize) {
- ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
- ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
- }
-
- mInts.insertAt(startline + i, ints);
- mObjects.insertAt(startline + i, objects);
- }
-
- updateBlocks(startline, endline - 1, n);
-
- b.finish();
- synchronized (sLock) {
- sStaticLayout = reflowed;
- sBuilder = b;
- }
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
+ b.finish();
+ synchronized (sLock) {
+ sStaticLayout = reflowed;
+ sBuilder = b;
}
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index ce238a7..8dee4b1 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -39,7 +39,6 @@
import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
-import android.os.Trace;
import android.text.method.TextKeyListener;
import android.text.style.AlignmentSpan;
import android.text.style.LeadingMarginSpan;
@@ -71,11 +70,6 @@
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
-
- /** @hide */
- protected static final boolean TRACE_LAYOUT = Build.isDebuggable();
-
-
/** @hide */
@IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
LineBreaker.BREAK_STRATEGY_SIMPLE,
@@ -478,51 +472,40 @@
@Nullable Path selectionPath,
@Nullable Paint selectionPaint,
int cursorOffsetVertical) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("Layout#draw");
+ float leftShift = 0;
+ if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
+ RectF drawingRect = computeDrawingBoundingBox();
+ if (drawingRect.left < 0) {
+ leftShift = -drawingRect.left;
+ canvas.translate(leftShift, 0);
+ }
}
- try {
- float leftShift = 0;
- if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
- RectF drawingRect = computeDrawingBoundingBox();
- if (drawingRect.left < 0) {
- leftShift = -drawingRect.left;
- canvas.translate(leftShift, 0);
- }
- }
- final long lineRange = getLineRangeForDraw(canvas);
- int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
- int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
- if (lastLine < 0) return;
+ final long lineRange = getLineRangeForDraw(canvas);
+ int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
+ int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
+ if (lastLine < 0) return;
- if (shouldDrawHighlightsOnTop(canvas)) {
- drawBackground(canvas, firstLine, lastLine);
- } else {
- drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath,
- selectionPaint,
- cursorOffsetVertical, firstLine, lastLine);
- }
+ if (shouldDrawHighlightsOnTop(canvas)) {
+ drawBackground(canvas, firstLine, lastLine);
+ } else {
+ drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
+ cursorOffsetVertical, firstLine, lastLine);
+ }
- drawText(canvas, firstLine, lastLine);
+ drawText(canvas, firstLine, lastLine);
- // Since high contrast text draws a solid rectangle background behind the text, it
- // covers up the highlights and selections. In this case we draw over the top of the
- // text with a blend mode that ensures the text stays high-contrast.
- if (shouldDrawHighlightsOnTop(canvas)) {
- drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath,
- selectionPaint,
- cursorOffsetVertical, firstLine, lastLine);
- }
+ // Since high contrast text draws a solid rectangle background behind the text, it covers up
+ // the highlights and selections. In this case we draw over the top of the text with a
+ // blend mode that ensures the text stays high-contrast.
+ if (shouldDrawHighlightsOnTop(canvas)) {
+ drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
+ cursorOffsetVertical, firstLine, lastLine);
+ }
- if (leftShift != 0) {
- // Manually translate back to the original position because of b/324498002, using
- // save/restore disappears the toggle switch drawables.
- canvas.translate(-leftShift, 0);
- }
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
+ if (leftShift != 0) {
+ // Manually translate back to the original position because of b/324498002, using
+ // save/restore disappears the toggle switch drawables.
+ canvas.translate(-leftShift, 0);
}
}
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 14401a6..5f6a9bd 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -25,8 +25,6 @@
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.MeasuredText;
-import android.os.Build;
-import android.os.Trace;
import android.text.style.MetricAffectingSpan;
import com.android.internal.util.Preconditions;
@@ -80,8 +78,6 @@
public class PrecomputedText implements Spannable {
private static final char LINE_FEED = '\n';
- private static final boolean TRACE_PCT = Build.isDebuggable();
-
/**
* The information required for building {@link PrecomputedText}.
*
@@ -451,47 +447,35 @@
private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText(
@NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) {
- if (TRACE_PCT) {
- Trace.beginSection("PrecomputedText#createMeasuredParagraphsFromPrecomputedText");
- Trace.setCounter("PrecomputedText#textCharCount", pct.length());
+ final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
+ && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+ final int hyphenationMode;
+ if (needHyphenation) {
+ hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+ ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+ MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+ } else {
+ hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
}
- try {
- final boolean needHyphenation =
- params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
- && params.getHyphenationFrequency()
- != Layout.HYPHENATION_FREQUENCY_NONE;
- final int hyphenationMode;
- if (needHyphenation) {
- hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
- ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
- MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
- } else {
- hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
- }
- LineBreakConfig config = params.getLineBreakConfig();
- if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
- && pct.getParagraphCount() != 1) {
- // If the text has multiple paragraph, resolve line break word style auto to none.
- config = new LineBreakConfig.Builder()
- .merge(config)
- .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
- .build();
- }
- ArrayList<ParagraphInfo> result = new ArrayList<>();
- for (int i = 0; i < pct.getParagraphCount(); ++i) {
- final int paraStart = pct.getParagraphStart(i);
- final int paraEnd = pct.getParagraphEnd(i);
- result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
- params.getTextPaint(), config, pct, paraStart, paraEnd,
- params.getTextDirection(), hyphenationMode, computeLayout, true,
- pct.getMeasuredParagraph(i), null /* no recycle */)));
- }
- return result.toArray(new ParagraphInfo[result.size()]);
- } finally {
- if (TRACE_PCT) {
- Trace.endSection();
- }
+ LineBreakConfig config = params.getLineBreakConfig();
+ if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
+ && pct.getParagraphCount() != 1) {
+ // If the text has multiple paragraph, resolve line break word style auto to none.
+ config = new LineBreakConfig.Builder()
+ .merge(config)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .build();
}
+ ArrayList<ParagraphInfo> result = new ArrayList<>();
+ for (int i = 0; i < pct.getParagraphCount(); ++i) {
+ final int paraStart = pct.getParagraphStart(i);
+ final int paraEnd = pct.getParagraphEnd(i);
+ result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
+ params.getTextPaint(), config, pct, paraStart, paraEnd,
+ params.getTextDirection(), hyphenationMode, computeLayout, true,
+ pct.getMeasuredParagraph(i), null /* no recycle */)));
+ }
+ return result.toArray(new ParagraphInfo[result.size()]);
}
/** @hide */
@@ -499,65 +483,53 @@
@NonNull CharSequence text, @NonNull Params params,
@IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean computeLayout,
boolean computeBounds) {
- if (TRACE_PCT) {
- Trace.beginSection("PrecomputedText#createMeasuredParagraphs");
- Trace.setCounter("PrecomputedText#textCharCount", text.length());
- }
- try {
- ArrayList<ParagraphInfo> result = new ArrayList<>();
+ ArrayList<ParagraphInfo> result = new ArrayList<>();
- Preconditions.checkNotNull(text);
- Preconditions.checkNotNull(params);
- final boolean needHyphenation =
- params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
- && params.getHyphenationFrequency()
- != Layout.HYPHENATION_FREQUENCY_NONE;
- final int hyphenationMode;
- if (needHyphenation) {
- hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
- ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
- MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+ Preconditions.checkNotNull(text);
+ Preconditions.checkNotNull(params);
+ final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
+ && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+ final int hyphenationMode;
+ if (needHyphenation) {
+ hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+ ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+ MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+ } else {
+ hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+ }
+
+ LineBreakConfig config = null;
+ int paraEnd = 0;
+ for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
+ paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
+ if (paraEnd < 0) {
+ // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
+ // end.
+ paraEnd = end;
} else {
- hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+ paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph.
}
- LineBreakConfig config = null;
- int paraEnd = 0;
- for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
- paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
- if (paraEnd < 0) {
- // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
- // end.
- paraEnd = end;
- } else {
- paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph.
+ if (config == null) {
+ config = params.getLineBreakConfig();
+ if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
+ && !(paraStart == start && paraEnd == end)) {
+ // If the text has multiple paragraph, resolve line break word style auto to
+ // none.
+ config = new LineBreakConfig.Builder()
+ .merge(config)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+ .build();
}
-
- if (config == null) {
- config = params.getLineBreakConfig();
- if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
- && !(paraStart == start && paraEnd == end)) {
- // If the text has multiple paragraph, resolve line break word style auto to
- // none.
- config = new LineBreakConfig.Builder()
- .merge(config)
- .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
- .build();
- }
- }
-
- result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
- params.getTextPaint(), config, text, paraStart, paraEnd,
- params.getTextDirection(), hyphenationMode, computeLayout, computeBounds,
- null /* no hint */,
- null /* no recycle */)));
}
- return result.toArray(new ParagraphInfo[result.size()]);
- } finally {
- if (TRACE_PCT) {
- Trace.endSection();
- }
+
+ result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
+ params.getTextPaint(), config, text, paraStart, paraEnd,
+ params.getTextDirection(), hyphenationMode, computeLayout, computeBounds,
+ null /* no hint */,
+ null /* no recycle */)));
}
+ return result.toArray(new ParagraphInfo[result.size()]);
}
// Use PrecomputedText.create instead.
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index d1b14d1..3dd3a9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -542,20 +542,10 @@
*/
@NonNull
public StaticLayout build() {
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#build");
- Trace.setCounter("StaticLayout#textLength", mText.length());
- }
- try {
- StaticLayout result = new StaticLayout(this, mIncludePad, mEllipsize != null
- ? COLUMNS_ELLIPSIZE : COLUMNS_NORMAL);
- Builder.recycle(this);
- return result;
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
- }
+ StaticLayout result = new StaticLayout(this, mIncludePad, mEllipsize != null
+ ? COLUMNS_ELLIPSIZE : COLUMNS_NORMAL);
+ Builder.recycle(this);
+ return result;
}
/**
@@ -572,21 +562,16 @@
*/
/* package */ @NonNull StaticLayout buildPartialStaticLayoutForDynamicLayout(
boolean trackpadding, StaticLayout recycle) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#forDynamicLayout");
- Trace.setCounter("StaticLayout#textLength", mText.length());
+ if (recycle == null) {
+ recycle = new StaticLayout();
}
+ Trace.beginSection("Generating StaticLayout For DynamicLayout");
try {
- if (recycle == null) {
- recycle = new StaticLayout();
- }
recycle.generate(this, mIncludePad, trackpadding);
- return recycle;
} finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
+ Trace.endSection();
}
+ return recycle;
}
private CharSequence mText;
@@ -742,7 +727,12 @@
mLeftIndents = b.mLeftIndents;
mRightIndents = b.mRightIndents;
- generate(b, b.mIncludePad, trackPadding);
+ Trace.beginSection("Constructing StaticLayout");
+ try {
+ generate(b, b.mIncludePad, trackPadding);
+ } finally {
+ Trace.endSection();
+ }
}
private static int getBaseHyphenationFrequency(int frequency) {
@@ -852,23 +842,14 @@
case PrecomputedText.Params.UNUSABLE:
break;
case PrecomputedText.Params.NEED_RECOMPUTE:
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#recomputePct");
- }
- try {
- final PrecomputedText.Params newParams =
- new PrecomputedText.Params.Builder(paint)
- .setBreakStrategy(b.mBreakStrategy)
- .setHyphenationFrequency(b.mHyphenationFrequency)
- .setTextDirection(textDir)
- .setLineBreakConfig(b.mLineBreakConfig)
- .build();
- precomputed = PrecomputedText.create(precomputed, newParams);
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
- }
+ final PrecomputedText.Params newParams =
+ new PrecomputedText.Params.Builder(paint)
+ .setBreakStrategy(b.mBreakStrategy)
+ .setHyphenationFrequency(b.mHyphenationFrequency)
+ .setTextDirection(textDir)
+ .setLineBreakConfig(b.mLineBreakConfig)
+ .build();
+ precomputed = PrecomputedText.create(precomputed, newParams);
paragraphInfo = precomputed.getParagraphInfo();
break;
case PrecomputedText.Params.USABLE:
@@ -879,261 +860,232 @@
}
if (paragraphInfo == null) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#computePct");
- }
- try {
- final PrecomputedText.Params param = new PrecomputedText.Params(paint,
- b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency);
- paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart,
- bufEnd, false /* computeLayout */, b.mCalculateBounds);
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
- }
+ final PrecomputedText.Params param = new PrecomputedText.Params(paint,
+ b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency);
+ paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart,
+ bufEnd, false /* computeLayout */, b.mCalculateBounds);
}
for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#processParagraph");
- Trace.setCounter("StaticLayout#paragraph", paraIndex);
+ final int paraStart = paraIndex == 0
+ ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
+ final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
+
+ int firstWidthLineCount = 1;
+ int firstWidth = outerWidth;
+ int restWidth = outerWidth;
+
+ LineHeightSpan[] chooseHt = null;
+ if (spanned != null) {
+ LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
+ LeadingMarginSpan.class);
+ for (int i = 0; i < sp.length; i++) {
+ LeadingMarginSpan lms = sp[i];
+ firstWidth -= sp[i].getLeadingMargin(true);
+ restWidth -= sp[i].getLeadingMargin(false);
+
+ // LeadingMarginSpan2 is odd. The count affects all
+ // leading margin spans, not just this particular one
+ if (lms instanceof LeadingMarginSpan2) {
+ LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
+ firstWidthLineCount = Math.max(firstWidthLineCount,
+ lms2.getLeadingMarginLineCount());
+ }
+ }
+
+ chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+
+ if (chooseHt.length == 0) {
+ chooseHt = null; // So that out() would not assume it has any contents
+ } else {
+ if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
+ chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
+ }
+
+ for (int i = 0; i < chooseHt.length; i++) {
+ int o = spanned.getSpanStart(chooseHt[i]);
+
+ if (o < paraStart) {
+ // starts in this layout, before the
+ // current paragraph
+
+ chooseHtv[i] = getLineTop(getLineForOffset(o));
+ } else {
+ // starts in this paragraph
+
+ chooseHtv[i] = v;
+ }
+ }
+ }
}
- try {
- final int paraStart = paraIndex == 0
- ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
- final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
-
- int firstWidthLineCount = 1;
- int firstWidth = outerWidth;
- int restWidth = outerWidth;
-
- LineHeightSpan[] chooseHt = null;
- if (spanned != null) {
- LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
- LeadingMarginSpan.class);
- for (int i = 0; i < sp.length; i++) {
- LeadingMarginSpan lms = sp[i];
- firstWidth -= sp[i].getLeadingMargin(true);
- restWidth -= sp[i].getLeadingMargin(false);
-
- // LeadingMarginSpan2 is odd. The count affects all
- // leading margin spans, not just this particular one
- if (lms instanceof LeadingMarginSpan2) {
- LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
- firstWidthLineCount = Math.max(firstWidthLineCount,
- lms2.getLeadingMarginLineCount());
- }
+ // tab stop locations
+ float[] variableTabStops = null;
+ if (spanned != null) {
+ TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ float[] stops = new float[spans.length];
+ for (int i = 0; i < spans.length; i++) {
+ stops[i] = (float) spans[i].getTabStop();
}
+ Arrays.sort(stops, 0, stops.length);
+ variableTabStops = stops;
+ }
+ }
- chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+ final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
+ final char[] chs = measuredPara.getChars();
+ final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
+ final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
- if (chooseHt.length == 0) {
- chooseHt = null; // So that out() would not assume it has any contents
+ constraints.setWidth(restWidth);
+ constraints.setIndent(firstWidth, firstWidthLineCount);
+ constraints.setTabStops(variableTabStops, TAB_INCREMENT);
+
+ LineBreaker.Result res = lineBreaker.computeLineBreaks(
+ measuredPara.getMeasuredText(), constraints, mLineCount);
+ int breakCount = res.getLineCount();
+ if (lineBreakCapacity < breakCount) {
+ lineBreakCapacity = breakCount;
+ breaks = new int[lineBreakCapacity];
+ lineWidths = new float[lineBreakCapacity];
+ ascents = new float[lineBreakCapacity];
+ descents = new float[lineBreakCapacity];
+ hasTabs = new boolean[lineBreakCapacity];
+ hyphenEdits = new int[lineBreakCapacity];
+ }
+
+ for (int i = 0; i < breakCount; ++i) {
+ breaks[i] = res.getLineBreakOffset(i);
+ lineWidths[i] = res.getLineWidth(i);
+ ascents[i] = res.getLineAscent(i);
+ descents[i] = res.getLineDescent(i);
+ hasTabs[i] = res.hasLineTab(i);
+ hyphenEdits[i] =
+ packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i));
+ }
+
+ final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
+ final boolean ellipsisMayBeApplied = ellipsize != null
+ && (ellipsize == TextUtils.TruncateAt.END
+ || (mMaximumVisibleLineCount == 1
+ && ellipsize != TextUtils.TruncateAt.MARQUEE));
+ if (0 < remainingLineCount && remainingLineCount < breakCount
+ && ellipsisMayBeApplied) {
+ // Calculate width
+ float width = 0;
+ boolean hasTab = false; // XXX May need to also have starting hyphen edit
+ for (int i = remainingLineCount - 1; i < breakCount; i++) {
+ if (i == breakCount - 1) {
+ width += lineWidths[i];
} else {
- if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
- chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
- }
-
- for (int i = 0; i < chooseHt.length; i++) {
- int o = spanned.getSpanStart(chooseHt[i]);
-
- if (o < paraStart) {
- // starts in this layout, before the
- // current paragraph
-
- chooseHtv[i] = getLineTop(getLineForOffset(o));
- } else {
- // starts in this paragraph
-
- chooseHtv[i] = v;
- }
+ for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
+ width += measuredPara.getCharWidthAt(j);
}
}
+ hasTab |= hasTabs[i];
}
- // tab stop locations
- float[] variableTabStops = null;
- if (spanned != null) {
- TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
- paraEnd, TabStopSpan.class);
- if (spans.length > 0) {
- float[] stops = new float[spans.length];
- for (int i = 0; i < spans.length; i++) {
- stops[i] = (float) spans[i].getTabStop();
+ // Treat the last line and overflowed lines as a single line.
+ breaks[remainingLineCount - 1] = breaks[breakCount - 1];
+ lineWidths[remainingLineCount - 1] = width;
+ hasTabs[remainingLineCount - 1] = hasTab;
+
+ breakCount = remainingLineCount;
+ }
+
+ // here is the offset of the starting character of the line we are currently
+ // measuring
+ int here = paraStart;
+
+ int fmTop = defaultTop;
+ int fmBottom = defaultBottom;
+ int fmAscent = defaultAscent;
+ int fmDescent = defaultDescent;
+ int fmCacheIndex = 0;
+ int spanEndCacheIndex = 0;
+ int breakIndex = 0;
+ for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+ // retrieve end of span
+ spanEnd = spanEndCache[spanEndCacheIndex++];
+
+ // retrieve cached metrics, order matches above
+ fm.top = fmCache[fmCacheIndex * 4 + 0];
+ fm.bottom = fmCache[fmCacheIndex * 4 + 1];
+ fm.ascent = fmCache[fmCacheIndex * 4 + 2];
+ fm.descent = fmCache[fmCacheIndex * 4 + 3];
+ fmCacheIndex++;
+
+ if (fm.top < fmTop) {
+ fmTop = fm.top;
+ }
+ if (fm.ascent < fmAscent) {
+ fmAscent = fm.ascent;
+ }
+ if (fm.descent > fmDescent) {
+ fmDescent = fm.descent;
+ }
+ if (fm.bottom > fmBottom) {
+ fmBottom = fm.bottom;
+ }
+
+ // skip breaks ending before current span range
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
+ breakIndex++;
+ }
+
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
+ int endPos = paraStart + breaks[breakIndex];
+
+ boolean moreChars = (endPos < bufEnd);
+
+ final int ascent = isFallbackLineSpacing
+ ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
+ : fmAscent;
+ final int descent = isFallbackLineSpacing
+ ? Math.max(fmDescent, Math.round(descents[breakIndex]))
+ : fmDescent;
+
+ // The fallback ascent/descent may be larger than top/bottom of the default font
+ // metrics. Adjust top/bottom with ascent/descent for avoiding unexpected
+ // clipping.
+ if (isFallbackLineSpacing) {
+ if (ascent < fmTop) {
+ fmTop = ascent;
}
- Arrays.sort(stops, 0, stops.length);
- variableTabStops = stops;
- }
- }
-
- final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
- final char[] chs = measuredPara.getChars();
- final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
- final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
-
- constraints.setWidth(restWidth);
- constraints.setIndent(firstWidth, firstWidthLineCount);
- constraints.setTabStops(variableTabStops, TAB_INCREMENT);
-
- if (TRACE_LAYOUT) {
- Trace.beginSection("LineBreaker#computeLineBreaks");
- }
- LineBreaker.Result res;
- try {
- res = lineBreaker.computeLineBreaks(
- measuredPara.getMeasuredText(), constraints, mLineCount);
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
- }
- int breakCount = res.getLineCount();
- if (lineBreakCapacity < breakCount) {
- lineBreakCapacity = breakCount;
- breaks = new int[lineBreakCapacity];
- lineWidths = new float[lineBreakCapacity];
- ascents = new float[lineBreakCapacity];
- descents = new float[lineBreakCapacity];
- hasTabs = new boolean[lineBreakCapacity];
- hyphenEdits = new int[lineBreakCapacity];
- }
-
- for (int i = 0; i < breakCount; ++i) {
- breaks[i] = res.getLineBreakOffset(i);
- lineWidths[i] = res.getLineWidth(i);
- ascents[i] = res.getLineAscent(i);
- descents[i] = res.getLineDescent(i);
- hasTabs[i] = res.hasLineTab(i);
- hyphenEdits[i] =
- packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i));
- }
-
- final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
- final boolean ellipsisMayBeApplied = ellipsize != null
- && (ellipsize == TextUtils.TruncateAt.END
- || (mMaximumVisibleLineCount == 1
- && ellipsize != TextUtils.TruncateAt.MARQUEE));
- if (0 < remainingLineCount && remainingLineCount < breakCount
- && ellipsisMayBeApplied) {
- // Calculate width
- float width = 0;
- boolean hasTab = false; // XXX May need to also have starting hyphen edit
- for (int i = remainingLineCount - 1; i < breakCount; i++) {
- if (i == breakCount - 1) {
- width += lineWidths[i];
- } else {
- for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
- width += measuredPara.getCharWidthAt(j);
- }
- }
- hasTab |= hasTabs[i];
- }
- // Treat the last line and overflowed lines as a single line.
- breaks[remainingLineCount - 1] = breaks[breakCount - 1];
- lineWidths[remainingLineCount - 1] = width;
- hasTabs[remainingLineCount - 1] = hasTab;
-
- breakCount = remainingLineCount;
- }
-
- // here is the offset of the starting character of the line we are currently
- // measuring
- int here = paraStart;
-
- int fmTop = defaultTop;
- int fmBottom = defaultBottom;
- int fmAscent = defaultAscent;
- int fmDescent = defaultDescent;
- int fmCacheIndex = 0;
- int spanEndCacheIndex = 0;
- int breakIndex = 0;
- for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
- // retrieve end of span
- spanEnd = spanEndCache[spanEndCacheIndex++];
-
- // retrieve cached metrics, order matches above
- fm.top = fmCache[fmCacheIndex * 4 + 0];
- fm.bottom = fmCache[fmCacheIndex * 4 + 1];
- fm.ascent = fmCache[fmCacheIndex * 4 + 2];
- fm.descent = fmCache[fmCacheIndex * 4 + 3];
- fmCacheIndex++;
-
- if (fm.top < fmTop) {
- fmTop = fm.top;
- }
- if (fm.ascent < fmAscent) {
- fmAscent = fm.ascent;
- }
- if (fm.descent > fmDescent) {
- fmDescent = fm.descent;
- }
- if (fm.bottom > fmBottom) {
- fmBottom = fm.bottom;
- }
-
- // skip breaks ending before current span range
- while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
- breakIndex++;
- }
-
- while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
- int endPos = paraStart + breaks[breakIndex];
-
- boolean moreChars = (endPos < bufEnd);
-
- final int ascent = isFallbackLineSpacing
- ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
- : fmAscent;
- final int descent = isFallbackLineSpacing
- ? Math.max(fmDescent, Math.round(descents[breakIndex]))
- : fmDescent;
-
- // The fallback ascent/descent may be larger than top/bottom of the default
- // font metrics. Adjust top/bottom with ascent/descent for avoiding
- // unexpected clipping.
- if (isFallbackLineSpacing) {
- if (ascent < fmTop) {
- fmTop = ascent;
- }
- if (descent > fmBottom) {
- fmBottom = descent;
- }
- }
-
- v = out(source, here, endPos,
- ascent, descent, fmTop, fmBottom,
- v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
- hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply,
- measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,
- paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
- paint, moreChars);
-
- if (endPos < spanEnd) {
- // preserve metrics for current span
- fmTop = Math.min(defaultTop, fm.top);
- fmBottom = Math.max(defaultBottom, fm.bottom);
- fmAscent = Math.min(defaultAscent, fm.ascent);
- fmDescent = Math.max(defaultDescent, fm.descent);
- } else {
- fmTop = fmBottom = fmAscent = fmDescent = 0;
- }
-
- here = endPos;
- breakIndex++;
-
- if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
- return;
+ if (descent > fmBottom) {
+ fmBottom = descent;
}
}
- }
- if (paraEnd == bufEnd) {
- break;
+ v = out(source, here, endPos,
+ ascent, descent, fmTop, fmBottom,
+ v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
+ hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply,
+ measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,
+ paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
+ paint, moreChars);
+
+ if (endPos < spanEnd) {
+ // preserve metrics for current span
+ fmTop = Math.min(defaultTop, fm.top);
+ fmBottom = Math.max(defaultBottom, fm.bottom);
+ fmAscent = Math.min(defaultAscent, fm.ascent);
+ fmDescent = Math.max(defaultDescent, fm.descent);
+ } else {
+ fmTop = fmBottom = fmAscent = fmDescent = 0;
+ }
+
+ here = endPos;
+ breakIndex++;
+
+ if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
+ return;
+ }
}
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
+ }
+
+ if (paraEnd == bufEnd) {
+ break;
}
}
@@ -1227,18 +1179,9 @@
(!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
ellipsize == TextUtils.TruncateAt.END);
if (doEllipsis) {
- if (TRACE_LAYOUT) {
- Trace.beginSection("StaticLayout#calculateEllipsis");
- }
- try {
- calculateEllipsis(start, end, measured, widthStart,
- ellipsisWidth, ellipsize, j,
- textWidth, paint, forceEllipsis);
- } finally {
- if (TRACE_LAYOUT) {
- Trace.endSection();
- }
- }
+ calculateEllipsis(start, end, measured, widthStart,
+ ellipsisWidth, ellipsize, j,
+ textWidth, paint, forceEllipsis);
} else {
mLines[mColumns * j + ELLIPSIS_START] = 0;
mLines[mColumns * j + ELLIPSIS_COUNT] = 0;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index a439478..bde9c77 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -28,7 +28,6 @@
import android.graphics.text.PositionedGlyphs;
import android.graphics.text.TextRunShaper;
import android.os.Build;
-import android.os.Trace;
import android.text.Layout.Directions;
import android.text.Layout.TabStops;
import android.text.style.CharacterStyle;
@@ -57,8 +56,6 @@
public class TextLine {
private static final boolean DEBUG = false;
- private static final boolean TRACE_TEXTLINE = Build.isDebuggable();
-
private static final char TAB_CHAR = '\t';
private TextPaint mPaint;
@@ -433,37 +430,28 @@
* @param bottom the bottom of the line
*/
void draw(Canvas c, float x, int top, int y, int bottom) {
- if (TRACE_TEXTLINE) {
- Trace.beginSection("TextLine#draw");
- }
- try {
- float h = 0;
- final int runCount = mDirections.getRunCount();
- for (int runIndex = 0; runIndex < runCount; runIndex++) {
- final int runStart = mDirections.getRunStart(runIndex);
- if (runStart > mLen) break;
- final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
- final boolean runIsRtl = mDirections.isRunRtl(runIndex);
+ float h = 0;
+ final int runCount = mDirections.getRunCount();
+ for (int runIndex = 0; runIndex < runCount; runIndex++) {
+ final int runStart = mDirections.getRunStart(runIndex);
+ if (runStart > mLen) break;
+ final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
+ final boolean runIsRtl = mDirections.isRunRtl(runIndex);
- final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
+ final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
- int segStart = runStart;
- for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
- if (j == runLimit || charAt(j) == TAB_CHAR) {
- h += drawRun(c, segStart, j, runIsRtl, x + h, top, y, bottom,
- runIndex != (runCount - 1) || j != mLen, runFlag);
+ int segStart = runStart;
+ for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+ if (j == runLimit || charAt(j) == TAB_CHAR) {
+ h += drawRun(c, segStart, j, runIsRtl, x + h, top, y, bottom,
+ runIndex != (runCount - 1) || j != mLen, runFlag);
- if (j != runLimit) { // charAt(j) == TAB_CHAR
- h = mDir * nextTab(h * mDir);
- }
- segStart = j + 1;
+ if (j != runLimit) { // charAt(j) == TAB_CHAR
+ h = mDir * nextTab(h * mDir);
}
+ segStart = j + 1;
}
}
- } finally {
- if (TRACE_TEXTLINE) {
- Trace.endSection();
- }
}
}
@@ -576,76 +564,63 @@
*/
public float measure(@IntRange(from = 0) int offset, boolean trailing,
@NonNull FontMetricsInt fmi, @Nullable RectF drawBounds, @Nullable LineInfo lineInfo) {
- if (TRACE_TEXTLINE) {
- Trace.beginSection("TextLine#measure");
+ if (offset > mLen) {
+ throw new IndexOutOfBoundsException(
+ "offset(" + offset + ") should be less than line limit(" + mLen + ")");
}
- try {
- if (offset > mLen) {
- throw new IndexOutOfBoundsException(
- "offset(" + offset + ") should be less than line limit(" + mLen + ")");
- }
- if (lineInfo != null) {
- lineInfo.setClusterCount(0);
- }
- final int target = trailing ? offset - 1 : offset;
- if (target < 0) {
- return 0;
- }
+ if (lineInfo != null) {
+ lineInfo.setClusterCount(0);
+ }
+ final int target = trailing ? offset - 1 : offset;
+ if (target < 0) {
+ return 0;
+ }
- float h = 0;
- final int runCount = mDirections.getRunCount();
- for (int runIndex = 0; runIndex < runCount; runIndex++) {
- final int runStart = mDirections.getRunStart(runIndex);
- if (runStart > mLen) break;
- final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
- final boolean runIsRtl = mDirections.isRunRtl(runIndex);
- final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
+ float h = 0;
+ final int runCount = mDirections.getRunCount();
+ for (int runIndex = 0; runIndex < runCount; runIndex++) {
+ final int runStart = mDirections.getRunStart(runIndex);
+ if (runStart > mLen) break;
+ final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
+ final boolean runIsRtl = mDirections.isRunRtl(runIndex);
+ final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
- int segStart = runStart;
- for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
- if (j == runLimit || charAt(j) == TAB_CHAR) {
- final boolean targetIsInThisSegment = target >= segStart && target < j;
- final boolean sameDirection =
- (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+ int segStart = runStart;
+ for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+ if (j == runLimit || charAt(j) == TAB_CHAR) {
+ final boolean targetIsInThisSegment = target >= segStart && target < j;
+ final boolean sameDirection = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
- if (targetIsInThisSegment && sameDirection) {
- return h + measureRun(segStart, offset, j, runIsRtl, fmi, drawBounds,
- null,
- 0, h, lineInfo, runFlag);
- }
-
- final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi,
- drawBounds,
- null, 0, h, lineInfo, runFlag);
- h += sameDirection ? segmentWidth : -segmentWidth;
-
- if (targetIsInThisSegment) {
- return h + measureRun(segStart, offset, j, runIsRtl, null, null, null,
- 0,
- h, lineInfo, runFlag);
- }
-
- if (j != runLimit) { // charAt(j) == TAB_CHAR
- if (offset == j) {
- return h;
- }
- h = mDir * nextTab(h * mDir);
- if (target == j) {
- return h;
- }
- }
-
- segStart = j + 1;
+ if (targetIsInThisSegment && sameDirection) {
+ return h + measureRun(segStart, offset, j, runIsRtl, fmi, drawBounds, null,
+ 0, h, lineInfo, runFlag);
}
+
+ final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi, drawBounds,
+ null, 0, h, lineInfo, runFlag);
+ h += sameDirection ? segmentWidth : -segmentWidth;
+
+ if (targetIsInThisSegment) {
+ return h + measureRun(segStart, offset, j, runIsRtl, null, null, null, 0,
+ h, lineInfo, runFlag);
+ }
+
+ if (j != runLimit) { // charAt(j) == TAB_CHAR
+ if (offset == j) {
+ return h;
+ }
+ h = mDir * nextTab(h * mDir);
+ if (target == j) {
+ return h;
+ }
+ }
+
+ segStart = j + 1;
}
}
-
- return h;
- } finally {
- if (TRACE_TEXTLINE) {
- Trace.endSection();
- }
}
+
+ return h;
}
/**
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index aff1d4a..8e1ac63 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -10,6 +10,7 @@
flag {
name: "new_fonts_fallback_xml"
+ is_exported: true
namespace: "text"
description: "Feature flag for deprecating fonts.xml. By setting true for this feature flag, the new font configuration XML, /system/etc/font_fallback.xml is used. The new XML has a new syntax and flexibility of variable font declarations, but it is not compatible with the apps that reads fonts.xml. So, fonts.xml is maintained as a subset of the font_fallback.xml"
# Make read only, as it could be used before the Settings provider is initialized.
@@ -26,6 +27,7 @@
flag {
name: "fix_line_height_for_locale"
+ is_exported: true
namespace: "text"
description: "Feature flag that preserve the line height of the TextView and EditText even if the the locale is different from Latin"
bug: "303326708"
@@ -33,6 +35,7 @@
flag {
name: "no_break_no_hyphenation_span"
+ is_exported: true
namespace: "text"
description: "A feature flag that adding new spans that prevents line breaking and hyphenation."
bug: "283193586"
@@ -57,6 +60,7 @@
flag {
name: "use_bounds_for_width"
+ is_exported: true
namespace: "text"
description: "Feature flag for preventing horizontal clipping."
bug: "63938206"
@@ -71,6 +75,7 @@
flag {
name: "word_style_auto"
+ is_exported: true
namespace: "text"
description: "A feature flag that implements line break word style auto."
bug: "280005585"
@@ -78,6 +83,7 @@
flag {
name: "letter_spacing_justification"
+ is_exported: true
namespace: "text"
description: "A feature flag that implement inter character justification."
bug: "283193133"
@@ -121,8 +127,22 @@
}
flag {
+ name: "handwriting_end_of_line_tap"
+ namespace: "text"
+ description: "Initiate handwriting when stylus taps at the end of a line in a focused non-empty TextView with the cursor at the end of that line"
+ bug: "323376217"
+}
+
+flag {
name: "handwriting_cursor_position"
namespace: "text"
description: "When handwriting is initiated in an unfocused TextView, cursor is placed at the end of the closest paragraph."
bug: "323376217"
}
+
+flag {
+ name: "handwriting_unsupported_message"
+ namespace: "text"
+ description: "Feature flag for showing error message when user tries stylus handwriting on a text field which doesn't support it"
+ bug: "297962571"
+}
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 29c8350..f4dadbb 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -34,7 +34,9 @@
import android.widget.EditText;
import android.widget.Editor;
import android.widget.TextView;
+import android.widget.Toast;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.ref.WeakReference;
@@ -223,24 +225,43 @@
View candidateView = findBestCandidateView(mState.mStylusDownX,
mState.mStylusDownY, /* isHover */ false);
if (candidateView != null && candidateView.isEnabled()) {
- if (candidateView == getConnectedOrFocusedView()) {
- if (!mInitiateWithoutConnection && !candidateView.hasFocus()) {
+ boolean candidateHasFocus = candidateView.hasFocus();
+ if (shouldShowHandwritingUnavailableMessageForView(candidateView)) {
+ int messagesResId = (candidateView instanceof TextView tv
+ && tv.isAnyPasswordInputType())
+ ? R.string.error_handwriting_unsupported_password
+ : R.string.error_handwriting_unsupported;
+ Toast.makeText(candidateView.getContext(), messagesResId,
+ Toast.LENGTH_SHORT).show();
+ if (!candidateView.hasFocus()) {
+ requestFocusWithoutReveal(candidateView);
+ }
+ mImm.showSoftInput(candidateView, 0);
+ mState.mHandled = true;
+ mState.mShouldInitHandwriting = false;
+ motionEvent.setAction((motionEvent.getAction()
+ & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ | MotionEvent.ACTION_CANCEL);
+ candidateView.getRootView().dispatchTouchEvent(motionEvent);
+ } else if (candidateView == getConnectedOrFocusedView()) {
+ if (!candidateHasFocus) {
requestFocusWithoutReveal(candidateView);
}
startHandwriting(candidateView);
} else if (candidateView.getHandwritingDelegatorCallback() != null) {
prepareDelegation(candidateView);
} else {
- if (!mInitiateWithoutConnection) {
+ if (mInitiateWithoutConnection) {
+ if (!candidateHasFocus) {
+ // schedule for view focus.
+ mState.mPendingFocusedView = new WeakReference<>(candidateView);
+ requestFocusWithoutReveal(candidateView);
+ }
+ } else {
mState.mPendingConnectedView = new WeakReference<>(candidateView);
- }
- if (!candidateView.hasFocus()) {
- requestFocusWithoutReveal(candidateView);
- }
- if (mInitiateWithoutConnection
- && updateFocusedView(candidateView,
- /* fromTouchEvent */ true)) {
- startHandwriting(candidateView);
+ if (!candidateHasFocus) {
+ requestFocusWithoutReveal(candidateView);
+ }
}
}
}
@@ -266,6 +287,9 @@
* gained focus.
*/
public void onDelegateViewFocused(@NonNull View view) {
+ if (mInitiateWithoutConnection) {
+ onEditorFocused(view);
+ }
if (view == getConnectedView()) {
tryAcceptStylusHandwritingDelegation(view);
}
@@ -313,6 +337,33 @@
}
/**
+ * Notify HandwritingInitiator that a new editor is focused.
+ * @param view the view that received focus.
+ */
+ @VisibleForTesting
+ public void onEditorFocused(@NonNull View view) {
+ if (!mInitiateWithoutConnection) {
+ return;
+ }
+
+ if (!view.isAutoHandwritingEnabled()) {
+ clearFocusedView(view);
+ return;
+ }
+
+ final View focusedView = getFocusedView();
+ if (focusedView == view) {
+ return;
+ }
+ updateFocusedView(view);
+
+ if (mState != null && mState.mPendingFocusedView != null
+ && mState.mPendingFocusedView.get() == view) {
+ startHandwriting(view);
+ }
+ }
+
+ /**
* Notify HandwritingInitiator that the InputConnection has closed for the given view.
* The caller of this method should guarantee that each onInputConnectionClosed call
* is paired with a onInputConnectionCreated call.
@@ -359,7 +410,7 @@
* @return {@code true} if handwriting can initiate for given view.
*/
@VisibleForTesting
- public boolean updateFocusedView(@NonNull View view, boolean fromTouchEvent) {
+ public boolean updateFocusedView(@NonNull View view) {
if (!view.shouldInitiateHandwriting()) {
mFocusedView = null;
return false;
@@ -371,9 +422,7 @@
// A new view just gain focus. By default, we should show hover icon for it.
mShowHoverIconForConnectedView = true;
}
- if (!fromTouchEvent && view.isHandwritingDelegate()) {
- tryAcceptStylusHandwritingDelegation(view);
- }
+
return true;
}
@@ -484,6 +533,15 @@
return view.isStylusHandwritingAvailable();
}
+ private static boolean shouldShowHandwritingUnavailableMessageForView(@NonNull View view) {
+ return (view instanceof TextView) && !shouldTriggerStylusHandwritingForView(view);
+ }
+
+ private static boolean shouldTriggerHandwritingOrShowUnavailableMessageForView(
+ @NonNull View view) {
+ return (view instanceof TextView) || shouldTriggerStylusHandwritingForView(view);
+ }
+
/**
* Returns the pointer icon for the motion event, or null if it doesn't specify the icon.
* This gives HandwritingInitiator a chance to show the stylus handwriting icon over a
@@ -491,7 +549,7 @@
*/
public PointerIcon onResolvePointerIcon(Context context, MotionEvent event) {
final View hoverView = findHoverView(event);
- if (hoverView == null) {
+ if (hoverView == null || !shouldTriggerStylusHandwritingForView(hoverView)) {
return null;
}
@@ -594,7 +652,7 @@
/**
* Given the location of the stylus event, return the best candidate view to initialize
- * handwriting mode.
+ * handwriting mode or show the handwriting unavailable error message.
*
* @param x the x coordinates of the stylus event, in the coordinates of the window.
* @param y the y coordinates of the stylus event, in the coordinates of the window.
@@ -610,7 +668,8 @@
Rect handwritingArea = mTempRect;
if (getViewHandwritingArea(connectedOrFocusedView, handwritingArea)
&& isInHandwritingArea(handwritingArea, x, y, connectedOrFocusedView, isHover)
- && shouldTriggerStylusHandwritingForView(connectedOrFocusedView)) {
+ && shouldTriggerHandwritingOrShowUnavailableMessageForView(
+ connectedOrFocusedView)) {
if (!isHover && mState != null) {
mState.mStylusDownWithinEditorBounds =
contains(handwritingArea, x, y, 0f, 0f, 0f, 0f);
@@ -628,7 +687,7 @@
final View view = viewInfo.getView();
final Rect handwritingArea = viewInfo.getHandwritingArea();
if (!isInHandwritingArea(handwritingArea, x, y, view, isHover)
- || !shouldTriggerStylusHandwritingForView(view)) {
+ || !shouldTriggerHandwritingOrShowUnavailableMessageForView(view)) {
continue;
}
@@ -832,6 +891,12 @@
*/
private WeakReference<View> mPendingConnectedView = null;
+ /**
+ * A view which has requested focus and is yet to receive it.
+ * When view receives focus, a handwriting session should be started for the view.
+ */
+ private WeakReference<View> mPendingFocusedView = null;
+
/** The pointer id of the stylus pointer that is being tracked. */
private final int mStylusPointerId;
/** The time stamp when the stylus pointer goes down. */
@@ -856,7 +921,7 @@
/** The helper method to check if the given view is still active for handwriting. */
private static boolean isViewActive(@Nullable View view) {
return view != null && view.isAttachedToWindow() && view.isAggregatedVisible()
- && view.shouldInitiateHandwriting();
+ && view.shouldTrackHandwritingArea();
}
private CursorAnchorInfo getCursorAnchorInfoForConnectionless(View view) {
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 5ee526e..1c0834f 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -30,6 +30,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import com.android.internal.os.IResultReceiver;
@@ -61,7 +62,8 @@
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
- int syncSeqId, boolean dragResizing);
+ int syncSeqId, boolean dragResizing,
+ in @nullable ActivityWindowInfo activityWindowInfo);
/**
* Called when this window retrieved control over a specified set of insets sources.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index e126836..3a90841 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -47,6 +47,19 @@
* {@hide}
*/
interface IWindowSession {
+
+ /**
+ * Bundle key to store the latest sync seq id for the relayout configuration.
+ * @see #relayout
+ */
+ const String KEY_RELAYOUT_BUNDLE_SEQID = "seqid";
+ /**
+ * Bundle key to store the latest ActivityWindowInfo associated with the relayout configuration.
+ * Will only be set if the relayout window is an activity window.
+ * @see #relayout
+ */
+ const String KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO = "activity_window_info";
+
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, int requestedVisibleTypes,
out InputChannel outInputChannel, out InsetsState insetsState,
@@ -92,7 +105,7 @@
* @param outSurfaceControl Object in which is placed the new display surface.
* @param insetsState The current insets state in the system.
* @param activeControls Objects which allow controlling {@link InsetsSource}s.
- * @param bundle A temporary object to obtain the latest SyncSeqId.
+ * @param bundle A Bundle to contain the latest SyncSeqId and any extra relayout optional infos.
* @return int Result flags, defined in {@link WindowManagerGlobal}.
*/
int relayout(IWindow window, in WindowManager.LayoutParams attrs,
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1920fa3..2fcffd0 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -737,15 +737,17 @@
@Override
public void onIdMatch(InsetsSource source1, InsetsSource source2) {
- final @InsetsType int type = source1.getType();
- if ((type & Type.systemBars()) == 0
+ final Rect frame1 = source1.getFrame();
+ final Rect frame2 = source2.getFrame();
+ if (!source1.hasFlags(InsetsSource.FLAG_ANIMATE_RESIZING)
+ || !source2.hasFlags(InsetsSource.FLAG_ANIMATE_RESIZING)
|| !source1.isVisible() || !source2.isVisible()
- || source1.getFrame().equals(source2.getFrame())
+ || frame1.equals(frame2) || frame1.isEmpty() || frame2.isEmpty()
|| !(Rect.intersects(mFrame, source1.getFrame())
|| Rect.intersects(mFrame, source2.getFrame()))) {
return;
}
- mTypes |= type;
+ mTypes |= source1.getType();
if (mToState == null) {
mToState = new InsetsState();
}
@@ -877,7 +879,6 @@
return false;
}
if (DEBUG) Log.d(TAG, "onStateChanged: " + state);
- mLastDispatchedState.set(state, true /* copySources */);
final InsetsState lastState = new InsetsState(mState, true /* copySources */);
updateState(state);
@@ -888,10 +889,13 @@
true /* excludesInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
- if (lastState.getDisplayFrame().equals(mState.getDisplayFrame())) {
- InsetsState.traverse(lastState, mState, mStartResizingAnimationIfNeeded);
+ if (mLastDispatchedState.getDisplayFrame().equals(state.getDisplayFrame())) {
+ // Here compares the raw states instead of the overridden ones because we don't want
+ // to animate an insets source that its mServerVisible is false.
+ InsetsState.traverse(mLastDispatchedState, state, mStartResizingAnimationIfNeeded);
}
}
+ mLastDispatchedState.set(state, true /* copySources */);
return true;
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 4ac78f5..5c10db1 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -99,11 +99,17 @@
*/
public static final int FLAG_FORCE_CONSUMING = 1 << 2;
+ /**
+ * Controls whether the insets source will play an animation when resizing.
+ */
+ public static final int FLAG_ANIMATE_RESIZING = 1 << 3;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = "FLAG_", value = {
FLAG_SUPPRESS_SCRIM,
FLAG_INSETS_ROUNDED_CORNER,
FLAG_FORCE_CONSUMING,
+ FLAG_ANIMATE_RESIZING,
})
public @interface Flags {}
@@ -546,6 +552,9 @@
if ((flags & FLAG_FORCE_CONSUMING) != 0) {
joiner.add("FORCE_CONSUMING");
}
+ if ((flags & FLAG_ANIMATE_RESIZING) != 0) {
+ joiner.add("ANIMATE_RESIZING");
+ }
return joiner.toString();
}
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index a2f767d..07d05a4 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -75,12 +75,14 @@
per-file View.java = file:/services/core/java/com/android/server/input/OWNERS
per-file View.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file View.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file View.java = file:/core/java/android/text/OWNERS
per-file ViewRootImpl.java = file:/services/accessibility/OWNERS
per-file ViewRootImpl.java = file:/core/java/android/service/autofill/OWNERS
per-file ViewRootImpl.java = file:/graphics/java/android/graphics/OWNERS
per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS
per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file ViewRootImpl.java = file:/core/java/android/text/OWNERS
per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
per-file OnReceiveContentListener.java = file:/core/java/android/service/autofill/OWNERS
per-file OnReceiveContentListener.java = file:/core/java/android/widget/OWNERS
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 4f5b51d..cfdf8fa 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2099,6 +2099,65 @@
}
}
+ /**
+ * Contains information of the idle time of the screen after which the refresh rate is to be
+ * reduced.
+ *
+ * @hide
+ */
+ public static final class IdleScreenRefreshRateConfig {
+ /**
+ * The time(in ms) after which the refresh rate is to be reduced. Defaults to -1, which
+ * means no timeout has been configured for the current conditions
+ */
+ public int timeoutMillis;
+
+ public IdleScreenRefreshRateConfig() {
+ timeoutMillis = -1;
+ }
+
+ public IdleScreenRefreshRateConfig(int timeoutMillis) {
+ this.timeoutMillis = timeoutMillis;
+ }
+
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof IdleScreenRefreshRateConfig) || other == null) {
+ return false;
+ }
+
+ IdleScreenRefreshRateConfig
+ idleScreenRefreshRateConfig = (IdleScreenRefreshRateConfig) other;
+ return timeoutMillis == idleScreenRefreshRateConfig.timeoutMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(timeoutMillis);
+ }
+
+ @Override
+ public String toString() {
+ return "timeoutMillis: " + timeoutMillis;
+ }
+
+ /**
+ * Copies the supplied object's values to this object.
+ */
+ public void copyFrom(IdleScreenRefreshRateConfig other) {
+ if (other != null) {
+ this.timeoutMillis = other.timeoutMillis;
+ }
+ }
+ }
+
/**
* Contains information about desired display configuration.
@@ -2132,6 +2191,15 @@
*/
public final RefreshRateRanges appRequestRanges;
+ /**
+ * Represents the idle time of the screen after which the associated display's refresh rate
+ * is to be reduced to preserve power
+ * Defaults to null, meaning that the device is not configured to have a timeout.
+ * Timeout value of -1 refers that the current conditions require no timeout
+ */
+ @Nullable
+ public IdleScreenRefreshRateConfig idleScreenRefreshRateConfig;
+
public DesiredDisplayModeSpecs() {
this.primaryRanges = new RefreshRateRanges();
this.appRequestRanges = new RefreshRateRanges();
@@ -2144,13 +2212,17 @@
}
public DesiredDisplayModeSpecs(int defaultMode, boolean allowGroupSwitching,
- RefreshRateRanges primaryRanges, RefreshRateRanges appRequestRanges) {
+ RefreshRateRanges primaryRanges, RefreshRateRanges appRequestRanges,
+ @Nullable IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) {
this.defaultMode = defaultMode;
this.allowGroupSwitching = allowGroupSwitching;
this.primaryRanges =
new RefreshRateRanges(primaryRanges.physical, primaryRanges.render);
this.appRequestRanges =
new RefreshRateRanges(appRequestRanges.physical, appRequestRanges.render);
+ this.idleScreenRefreshRateConfig =
+ (idleScreenRefreshRateConfig == null) ? null : new IdleScreenRefreshRateConfig(
+ idleScreenRefreshRateConfig.timeoutMillis);
}
@Override
@@ -2165,7 +2237,9 @@
return other != null && defaultMode == other.defaultMode
&& allowGroupSwitching == other.allowGroupSwitching
&& primaryRanges.equals(other.primaryRanges)
- && appRequestRanges.equals(other.appRequestRanges);
+ && appRequestRanges.equals(other.appRequestRanges)
+ && Objects.equals(
+ idleScreenRefreshRateConfig, other.idleScreenRefreshRateConfig);
}
@Override
@@ -2181,6 +2255,7 @@
allowGroupSwitching = other.allowGroupSwitching;
primaryRanges.copyFrom(other.primaryRanges);
appRequestRanges.copyFrom(other.appRequestRanges);
+ copyIdleScreenRefreshRateConfig(other.idleScreenRefreshRateConfig);
}
@Override
@@ -2188,7 +2263,21 @@
return "defaultMode=" + defaultMode
+ " allowGroupSwitching=" + allowGroupSwitching
+ " primaryRanges=" + primaryRanges
- + " appRequestRanges=" + appRequestRanges;
+ + " appRequestRanges=" + appRequestRanges
+ + " idleScreenRefreshRate=" + String.valueOf(idleScreenRefreshRateConfig);
+ }
+
+ private void copyIdleScreenRefreshRateConfig(IdleScreenRefreshRateConfig other) {
+ if (idleScreenRefreshRateConfig == null) {
+ if (other != null) {
+ idleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(other.timeoutMillis);
+ }
+ } else if (other == null) {
+ idleScreenRefreshRateConfig = null;
+ } else {
+ idleScreenRefreshRateConfig.copyFrom(other);
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0a75f4e..736e815 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,10 +40,13 @@
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout;
import static android.view.flags.Flags.sensitiveContentAppProtection;
+import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
+import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.flags.Flags.viewVelocityApi;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
+import static android.view.inputmethod.Flags.initiationWithoutInputConnection;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS;
@@ -8496,8 +8499,9 @@
* hierarchy
* @param refocus when propagate is true, specifies whether to request the
* root view place new focus
+ * @hide
*/
- void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
+ public void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
mPrivateFlags &= ~PFLAG_FOCUSED;
clearParentsWantFocus();
@@ -8668,11 +8672,12 @@
onFocusLost();
} else if (hasWindowFocus()) {
notifyFocusChangeToImeFocusController(true /* hasFocus */);
-
- if (mIsHandwritingDelegate) {
- ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
+ ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ if (mIsHandwritingDelegate) {
viewRoot.getHandwritingInitiator().onDelegateViewFocused(this);
+ } else if (initiationWithoutInputConnection() && onCheckIsTextEditor()) {
+ viewRoot.getHandwritingInitiator().onEditorFocused(this);
}
}
}
@@ -12695,7 +12700,7 @@
if (getSystemGestureExclusionRects().isEmpty()
&& collectPreferKeepClearRects().isEmpty()
&& collectUnrestrictedPreferKeepClearRects().isEmpty()
- && (info.mHandwritingArea == null || !shouldInitiateHandwriting())) {
+ && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) {
if (info.mPositionUpdateListener != null) {
mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener);
info.mPositionUpdateListener = null;
@@ -13062,7 +13067,7 @@
void updateHandwritingArea() {
// If autoHandwritingArea is not enabled, do nothing.
- if (!shouldInitiateHandwriting()) return;
+ if (!shouldTrackHandwritingArea()) return;
final AttachInfo ai = mAttachInfo;
if (ai != null) {
ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this);
@@ -13080,6 +13085,16 @@
}
/**
+ * Returns whether the handwriting initiator should track the handwriting area for this view,
+ * either to initiate handwriting mode, or to prepare handwriting delegation, or to show the
+ * handwriting unsupported message.
+ * @hide
+ */
+ public boolean shouldTrackHandwritingArea() {
+ return shouldInitiateHandwriting();
+ }
+
+ /**
* Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this
* view's bounds. The callback will be called from the UI thread.
*
@@ -16691,6 +16706,10 @@
onFocusLost();
} else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
notifyFocusChangeToImeFocusController(true /* hasFocus */);
+ ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null && initiationWithoutInputConnection() && onCheckIsTextEditor()) {
+ viewRoot.getHandwritingInitiator().onEditorFocused(this);
+ }
}
refreshDrawableState();
@@ -33779,9 +33798,13 @@
|| heightDp <= FRAME_RATE_NARROW_THRESHOLD
|| (widthDp <= FRAME_RATE_SMALL_SIZE_THRESHOLD
&& heightDp <= FRAME_RATE_SMALL_SIZE_THRESHOLD)) {
- return FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_SMALL;
+ int category = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ return category | FRAME_RATE_CATEGORY_REASON_SMALL;
} else {
- return FRAME_RATE_CATEGORY_HIGH | FRAME_RATE_CATEGORY_REASON_LARGE;
+ int category = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ return category | FRAME_RATE_CATEGORY_REASON_LARGE;
}
}
@@ -33829,8 +33852,10 @@
frameRateCategory = FRAME_RATE_CATEGORY_HIGH
| FRAME_RATE_CATEGORY_REASON_REQUESTED;
} else {
- // invalid frame rate, default to HIGH
- frameRateCategory = FRAME_RATE_CATEGORY_HIGH
+ // invalid frame rate, use default
+ int category = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ frameRateCategory = category
| FRAME_RATE_CATEGORY_REASON_INVALID;
}
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cae6672..3c61854 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -114,7 +114,9 @@
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import static com.android.input.flags.Flags.enablePointerChoreographer;
+import static com.android.window.flags.Flags.activityWindowInfoFlag;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
+import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -233,6 +235,7 @@
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
+import android.window.ActivityWindowInfo;
import android.window.BackEvent;
import android.window.ClientWindowFrames;
import android.window.CompatOnBackInvokedCallback;
@@ -435,13 +438,27 @@
* Callback for notifying activities.
*/
public interface ActivityConfigCallback {
-
/**
* Notifies about override config change and/or move to different display.
* @param overrideConfig New override config to apply to activity.
* @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
*/
- void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
+ default void onConfigurationChanged(@NonNull Configuration overrideConfig,
+ int newDisplayId) {
+ // Must override one of the #onConfigurationChanged.
+ throw new IllegalStateException("Not implemented");
+ }
+
+ /**
+ * Notifies about override config change and/or move to different display.
+ * @param overrideConfig New override config to apply to activity.
+ * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
+ * @param activityWindowInfo New ActivityWindowInfo to apply to activity.
+ */
+ default void onConfigurationChanged(@NonNull Configuration overrideConfig,
+ int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
+ onConfigurationChanged(overrideConfig, newDisplayId);
+ }
/**
* Notify the corresponding activity about the request to show or hide a camera compat
@@ -467,7 +484,7 @@
* In that case we receive a call back from {@link ActivityThread} and this flag is used to
* preserve the initial value.
*
- * @see #performConfigurationChange(MergedConfiguration, boolean, int)
+ * @see #performConfigurationChange
*/
private boolean mForceNextConfigUpdate;
@@ -814,6 +831,13 @@
/** Configurations waiting to be applied. */
private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
+ /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
+ @Nullable
+ private ActivityWindowInfo mPendingActivityWindowInfo;
+ /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */
+ @Nullable
+ private ActivityWindowInfo mLastReportedActivityWindowInfo;
+
boolean mScrollMayChange;
@SoftInputModeFlags
int mSoftInputMode;
@@ -1260,8 +1284,18 @@
* Add activity config callback to be notified about override config changes and camera
* compat control state updates.
*/
- public void setActivityConfigCallback(ActivityConfigCallback callback) {
+ public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) {
mActivityConfigCallback = callback;
+ if (!activityWindowInfoFlag()) {
+ return;
+ }
+ if (callback == null) {
+ mPendingActivityWindowInfo = null;
+ mLastReportedActivityWindowInfo = null;
+ } else {
+ mPendingActivityWindowInfo = new ActivityWindowInfo();
+ mLastReportedActivityWindowInfo = new ActivityWindowInfo();
+ }
}
public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
@@ -2096,7 +2130,8 @@
/** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */
private void handleResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
+ @Nullable ActivityWindowInfo activityWindowInfo) {
if (!mAdded) {
return;
}
@@ -2114,7 +2149,14 @@
mInsetsController.onStateChanged(insetsState);
final float compatScale = frames.compatScale;
final boolean frameChanged = !mWinFrame.equals(frame);
- final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
+ final boolean shouldReportActivityWindowInfoChanged =
+ // Can be null if callbacks is not set
+ mLastReportedActivityWindowInfo != null
+ // Can be null if not activity window
+ && activityWindowInfo != null
+ && !mLastReportedActivityWindowInfo.equals(activityWindowInfo);
+ final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration)
+ || shouldReportActivityWindowInfoChanged;
final boolean attachedFrameChanged =
!Objects.equals(mTmpFrames.attachedFrame, attachedFrame);
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
@@ -2133,7 +2175,8 @@
if (configChanged) {
// If configuration changed - notify about that and, maybe, about move to display.
performConfigurationChange(mergedConfiguration, false /* force */,
- displayChanged ? displayId : INVALID_DISPLAY /* same display */);
+ displayChanged ? displayId : INVALID_DISPLAY /* same display */,
+ activityWindowInfo);
} else if (displayChanged) {
// Moved to display without config change - report last applied one.
onMovedToDisplay(displayId, mLastConfigurationFromResources);
@@ -3522,6 +3565,16 @@
mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl,
Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply();
}
+
+ if (setScPropertiesInClient()) {
+ if (surfaceControlChanged || windowAttributesChanged) {
+ boolean colorSpaceAgnostic = (lp.privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC)
+ != 0;
+ mTransaction.setColorSpaceAgnostic(mSurfaceControl, colorSpaceAgnostic)
+ .apply();
+ }
+ }
}
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -3532,12 +3585,18 @@
// WindowManagerService has reported back a frame from a configuration not yet
// handled by the client. In this case, we need to accept the configuration so we
// do not lay out and draw with the wrong configuration.
- if (mRelayoutRequested
- && !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
+ boolean shouldPerformConfigurationUpdate =
+ !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)
+ || !Objects.equals(mPendingActivityWindowInfo,
+ mLastReportedActivityWindowInfo);
+ if (mRelayoutRequested && shouldPerformConfigurationUpdate) {
if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
+ mPendingMergedConfiguration.getMergedConfiguration());
performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
- !mFirst, INVALID_DISPLAY /* same display */);
+ !mFirst, INVALID_DISPLAY /* same display */,
+ mPendingActivityWindowInfo != null
+ ? new ActivityWindowInfo(mPendingActivityWindowInfo)
+ : null);
updatedConfiguration = true;
}
final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
@@ -6063,9 +6122,11 @@
* @param force Flag indicating if we should force apply the config.
* @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
* changed.
+ * @param activityWindowInfo New activity window info. {@code null} if it is non-app window, or
+ * this is not a Configuration change to the activity window (global).
*/
- private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
- int newDisplayId) {
+ private void performConfigurationChange(@NonNull MergedConfiguration mergedConfiguration,
+ boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) {
if (mergedConfiguration == null) {
throw new IllegalArgumentException("No merged config provided.");
}
@@ -6105,6 +6166,9 @@
}
mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+ if (mLastReportedActivityWindowInfo != null && activityWindowInfo != null) {
+ mLastReportedActivityWindowInfo.set(activityWindowInfo);
+ }
mForceNextConfigUpdate = force;
if (mActivityConfigCallback != null) {
@@ -6112,7 +6176,8 @@
// This basically initiates a round trip to ActivityThread and back, which will ensure
// that corresponding activity and resources are updated before updating inner state of
// ViewRootImpl. Eventually it will call #updateConfiguration().
- mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
+ mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId,
+ activityWindowInfo);
} else {
// There is no activity callback - update the configuration right away.
updateConfiguration(newDisplayId);
@@ -6354,13 +6419,15 @@
final boolean reportDraw = msg.what == MSG_RESIZED_REPORT;
final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
final InsetsState insetsState = (InsetsState) args.arg3;
+ final ActivityWindowInfo activityWindowInfo = (ActivityWindowInfo) args.arg4;
final boolean forceLayout = args.argi1 != 0;
final boolean alwaysConsumeSystemBars = args.argi2 != 0;
final int displayId = args.argi3;
final int syncSeqId = args.argi4;
final boolean dragResizing = args.argi5 != 0;
handleResized(frames, reportDraw, mergedConfiguration, insetsState, forceLayout,
- alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
+ alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
+ activityWindowInfo);
args.recycle();
break;
}
@@ -6504,7 +6571,8 @@
mLastReportedMergedConfiguration.getOverrideConfiguration());
performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
- false /* force */, INVALID_DISPLAY /* same display */);
+ false /* force */, INVALID_DISPLAY /* same display */,
+ mLastReportedActivityWindowInfo);
} break;
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
setAccessibilityFocus(null, null);
@@ -8933,10 +9001,19 @@
mTempInsets, mTempControls, mRelayoutBundle);
mRelayoutRequested = true;
- final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
+ final int maybeSyncSeqId = mRelayoutBundle.getInt(
+ IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID);
if (maybeSyncSeqId > 0) {
mSyncSeqId = maybeSyncSeqId;
}
+ if (activityWindowInfoFlag() && mPendingActivityWindowInfo != null) {
+ final ActivityWindowInfo outInfo = mRelayoutBundle.getParcelable(
+ IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO,
+ ActivityWindowInfo.class);
+ if (outInfo != null) {
+ mPendingActivityWindowInfo.set(outInfo);
+ }
+ }
mWinFrameInScreen.set(mTmpFrames.frame);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
@@ -9357,6 +9434,10 @@
+ mLastReportedMergedConfiguration);
writer.println(innerPrefix + "mLastConfigurationFromResources="
+ mLastConfigurationFromResources);
+ if (mLastReportedActivityWindowInfo != null) {
+ writer.println(innerPrefix + "mLastReportedActivityWindowInfo="
+ + mLastReportedActivityWindowInfo);
+ }
writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode);
writer.println(innerPrefix + "mUnbufferedInputSource="
+ Integer.toHexString(mUnbufferedInputSource));
@@ -9570,12 +9651,14 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing,
+ @Nullable ActivityWindowInfo activityWindowInfo) {
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
SomeArgs args = SomeArgs.obtain();
args.arg1 = frames;
args.arg2 = mergedConfiguration;
args.arg3 = insetsState;
+ args.arg4 = activityWindowInfo;
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId;
@@ -11028,7 +11111,7 @@
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
- boolean dragResizing) {
+ boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {
final boolean isFromResizeItem = mIsFromResizeItem;
mIsFromResizeItem = false;
// Although this is a AIDL method, it will only be triggered in local process through
@@ -11047,7 +11130,8 @@
if (isFromResizeItem && viewAncestor.mHandler.getLooper()
== ActivityThread.currentActivityThread().getLooper()) {
viewAncestor.handleResized(frames, reportDraw, mergedConfiguration, insetsState,
- forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
+ forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
+ activityWindowInfo);
return;
}
// The the parameters from WindowStateResizeItem are already copied.
@@ -11059,7 +11143,8 @@
mergedConfiguration = new MergedConfiguration(mergedConfiguration);
}
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState,
- forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing);
+ forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing,
+ activityWindowInfo);
}
@Override
@@ -12715,7 +12800,10 @@
}
private boolean shouldEnableDvrr() {
- return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
+ // uncomment this when we are ready for enabling dVRR
+ // return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
+ return false;
+
}
private void checkIdleness() {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 22d8ed9..7309080 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -638,7 +638,7 @@
mTmpConfig.setConfiguration(mConfiguration, mConfiguration);
s.mClient.resized(mTmpFrames, false /* reportDraw */, mTmpConfig, state,
false /* forceLayout */, false /* alwaysConsumeSystemBars */, s.mDisplayId,
- Integer.MAX_VALUE, false /* dragResizing */);
+ Integer.MAX_VALUE, false /* dragResizing */, null /* activityWindowInfo */);
} catch (RemoteException e) {
// Too bad
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 5b99c71f..91bd4ea 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -4,6 +4,7 @@
flag {
name: "a11y_overlay_callbacks"
+ is_exported: true
namespace: "accessibility"
description: "Whether to allow the passing of result callbacks when attaching a11y overlays."
bug: "304478691"
@@ -26,6 +27,7 @@
flag {
namespace: "accessibility"
name: "braille_display_hid"
+ is_exported: true
description: "Enables new APIs for an AccessibilityService to communicate with a HID Braille display"
bug: "303522222"
}
@@ -40,6 +42,7 @@
flag {
namespace: "accessibility"
name: "collection_info_item_counts"
+ is_exported: true
description: "Fields for total items and the number of important for accessibility items in a collection"
bug: "302376158"
}
@@ -61,6 +64,7 @@
flag {
namespace: "accessibility"
name: "flash_notification_system_api"
+ is_exported: true
description: "Makes flash notification APIs as system APIs for calling from mainline module"
bug: "303131332"
}
@@ -74,6 +78,7 @@
flag {
name: "motion_event_observing"
+ is_exported: true
namespace: "accessibility"
description: "Allows accessibility services to intercept but not consume motion events from specified sources."
bug: "297595990"
@@ -82,6 +87,7 @@
flag {
namespace: "accessibility"
name: "granular_scrolling"
+ is_exported: true
description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
bug: "302376158"
}
@@ -103,6 +109,7 @@
flag {
namespace: "accessibility"
name: "add_type_window_control"
+ is_exported: true
description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
bug: "320445550"
}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 644a7a9..5cdcf0a 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -255,6 +255,17 @@
public static final String DEVICE_CONFIG_IGNORE_RELAYOUT_WHEN_AUTH_PENDING =
"ignore_relayout_auth_pending";
+ /**
+ * Bugfix flag, Autofill should only fill in value from current session.
+ *
+ * See frameworks/base/services/autofill/bugfixes.aconfig#fill_fields_from_current_session_only
+ * for more information
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_FILL_FIELDS_FROM_CURRENT_SESSION_ONLY =
+ "fill_fields_from_current_session_only";
+
// END AUTOFILL FOR ALL APPS FLAGS //
@@ -532,6 +543,14 @@
false);
}
+ /** @hide **/
+ public static boolean shouldFillFieldsFromCurrentSessionOnly() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_FILL_FIELDS_FROM_CURRENT_SESSION_ONLY,
+ false);
+ }
+
/**
* Whether should enable multi-line filter
*
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index 5d3153c..4de0f29 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -23,6 +23,7 @@
flag {
name: "create_accessibility_overlay_app_op_enabled"
+ is_exported: true
namespace: "content_protection"
description: "If true, an appop is logged on creation of accessibility overlays."
bug: "289081465"
@@ -30,6 +31,7 @@
flag {
name: "rapid_clear_notifications_by_listener_app_op_enabled"
+ is_exported: true
namespace: "content_protection"
description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
bug: "289080543"
@@ -37,6 +39,7 @@
flag {
name: "manage_device_policy_enabled"
+ is_exported: true
namespace: "content_protection"
description: "If true, the APIs to manage content protection device policy will be enabled."
bug: "319477846"
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 05cabd5..06598b3 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "view_velocity_api"
+ is_exported: true
namespace: "toolkit"
description: "Feature flag for view content velocity api"
bug: "293513816"
@@ -16,6 +17,7 @@
flag {
name: "toolkit_set_frame_rate_read_only"
+ is_exported: true
namespace: "toolkit"
description: "Feature flag for toolkit to set frame rate"
bug: "293512962"
@@ -24,6 +26,7 @@
flag {
name: "expected_presentation_time_api"
+ is_exported: true
namespace: "toolkit"
description: "Feature flag for using expected presentation time of the Choreographer"
bug: "278730197"
@@ -31,6 +34,7 @@
flag {
name: "expected_presentation_time_read_only"
+ is_exported: true
namespace: "toolkit"
description: "Feature flag for using expected presentation time of the Choreographer"
bug: "278730197"
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index d1d871c2..a7c4104 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -3,6 +3,7 @@
flag {
namespace: "toolkit"
name: "scroll_feedback_api"
+ is_exported: true
description: "Enable the scroll feedback APIs"
bug: "239594271"
}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 6cf89d6..c482f8b 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -28,6 +28,7 @@
flag {
name: "sensitive_content_app_protection_api"
+ is_exported: true
namespace: "permissions"
description: "This flag controls the new sensitive content protection API,"
" The API will be used by other ui toolkits (i.e. compose, webview, custom virtual views)."
diff --git a/core/java/android/view/flags/window_insets.aconfig b/core/java/android/view/flags/window_insets.aconfig
index 201b7ad..bf6df5c 100644
--- a/core/java/android/view/flags/window_insets.aconfig
+++ b/core/java/android/view/flags/window_insets.aconfig
@@ -2,6 +2,7 @@
flag {
name: "customizable_window_headers"
+ is_exported: true
namespace: "lse_desktop_experience"
description: "Flag to control the caption bar appearance and to fit app content in its empty space"
bug: "316387515"
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 985f542..8efb201 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -3499,10 +3499,6 @@
return false;
}
mServedView = mNextServedView;
- if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) {
- mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused(
- mServedView);
- }
if (mServedInputConnection != null) {
mServedInputConnection.finishComposingTextFromImm();
}
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index 8d3920f..be74a65 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -10,6 +10,7 @@
flag {
name: "editorinfo_handwriting_enabled"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for adding EditorInfo#mStylusHandwritingEnabled"
bug: "293898187"
@@ -18,6 +19,7 @@
flag {
name: "imm_userhandle_hostsidetests"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for replacing UserIdInt with UserHandle in some helper IMM functions"
bug: "301713309"
@@ -26,6 +28,7 @@
flag {
name: "concurrent_input_methods"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for concurrent multi-session IME"
bug: "284527000"
@@ -34,6 +37,7 @@
flag {
name: "home_screen_handwriting_delegator"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for supporting stylus handwriting delegation from RemoteViews on the home screen"
bug: "279959705"
@@ -49,6 +53,7 @@
flag {
name: "use_zero_jank_proxy"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for using a proxy that uses async calls to achieve zero jank for IMMS calls."
bug: "293640003"
@@ -57,6 +62,7 @@
flag {
name: "ime_switcher_revamp"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for revamping the Input Method Switcher menu"
bug: "311791923"
@@ -73,6 +79,7 @@
flag {
name: "connectionless_handwriting"
+ is_exported: true
namespace: "input_method"
description: "Feature flag for connectionless stylus handwriting APIs"
bug: "300979854"
diff --git a/core/java/android/webkit/flags.aconfig b/core/java/android/webkit/flags.aconfig
index 6938b29..2d834a8 100644
--- a/core/java/android/webkit/flags.aconfig
+++ b/core/java/android/webkit/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "update_service_ipc_wrapper"
+ is_exported: true
namespace: "webview"
description: "New API: proper wrapper for IWebViewUpdateService"
bug: "319292658"
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0373539..fbb5116 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9733,7 +9733,7 @@
return KEY_EVENT_HANDLED;
}
if (hasFocus()) {
- clearFocus();
+ clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
InputMethodManager imm = getInputMethodManager();
if (imm != null) {
imm.hideSoftInputFromView(this, 0);
@@ -13118,6 +13118,16 @@
return superResult;
}
+ // At this point, the event is not a long press, otherwise it would be handled above.
+ if (Flags.handwritingEndOfLineTap() && action == MotionEvent.ACTION_UP
+ && shouldStartHandwritingForEndOfLineTap(event)) {
+ InputMethodManager imm = getInputMethodManager();
+ if (imm != null) {
+ imm.startStylusHandwriting(this);
+ return true;
+ }
+ }
+
final boolean touchIsFinished = (action == MotionEvent.ACTION_UP)
&& (mEditor == null || !mEditor.mIgnoreActionUpEvent) && isFocused();
@@ -13167,6 +13177,46 @@
}
/**
+ * If handwriting is supported, the TextView is already focused and not empty, and the cursor is
+ * at the end of a line, a stylus tap after the end of the line will trigger handwriting.
+ */
+ private boolean shouldStartHandwritingForEndOfLineTap(MotionEvent actionUpEvent) {
+ if (!onCheckIsTextEditor()
+ || !isEnabled()
+ || !isAutoHandwritingEnabled()
+ || TextUtils.isEmpty(mText)
+ || didTouchFocusSelect()
+ || mLayout == null
+ || !actionUpEvent.isStylusPointer()) {
+ return false;
+ }
+ int cursorOffset = getSelectionStart();
+ if (cursorOffset < 0 || getSelectionEnd() != cursorOffset) {
+ return false;
+ }
+ int cursorLine = mLayout.getLineForOffset(cursorOffset);
+ int cursorLineEnd = mLayout.getLineEnd(cursorLine);
+ if (cursorLine != mLayout.getLineCount() - 1) {
+ cursorLineEnd--;
+ }
+ if (cursorLineEnd != cursorOffset) {
+ return false;
+ }
+ // Check that the stylus down point is within the same line as the cursor.
+ if (getLineAtCoordinate(actionUpEvent.getY()) != cursorLine) {
+ return false;
+ }
+ // Check that the stylus down point is after the end of the line.
+ float localX = convertToLocalHorizontalCoordinate(actionUpEvent.getX());
+ if (mLayout.getParagraphDirection(cursorLine) == Layout.DIR_RIGHT_TO_LEFT
+ ? localX >= mLayout.getLineLeft(cursorLine)
+ : localX <= mLayout.getLineRight(cursorLine)) {
+ return false;
+ }
+ return isStylusHandwritingAvailable();
+ }
+
+ /**
* Returns true when need to show UIs, e.g. floating toolbar, etc, for finger based interaction.
*
* @return true if UIs need to show for finger interaciton. false if UIs are not necessary.
@@ -13565,6 +13615,15 @@
/** @hide */
@Override
+ public boolean shouldTrackHandwritingArea() {
+ // The handwriting initiator tracks all editable TextViews regardless of whether handwriting
+ // is supported, so that it can show an error message for unsupported editable TextViews.
+ return super.shouldTrackHandwritingArea()
+ || (Flags.handwritingUnsupportedMessage() && onCheckIsTextEditor());
+ }
+
+ /** @hide */
+ @Override
public boolean isStylusHandwritingAvailable() {
if (mTextOperationUser == null) {
return super.isStylusHandwritingAvailable();
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index 7e77f15..43df4f9 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -112,10 +112,13 @@
/**
* Creates a decor surface in the parent Task of the TaskFragment. The created decor surface
* will be provided in {@link TaskFragmentTransaction#TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED}
- * event callback. The decor surface can be used to draw the divider between TaskFragments or
- * other decorations.
+ * event callback. If a decor surface already exists in the parent Task, the current
+ * TaskFragment will become the new owner of the decor surface and the decor surface will be
+ * moved above the TaskFragment.
+ *
+ * The decor surface can be used to draw the divider between TaskFragments or other decorations.
*/
- public static final int OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE = 14;
+ public static final int OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE = 14;
/**
* Removes the decor surface in the parent Task of the TaskFragment.
@@ -162,7 +165,7 @@
OP_TYPE_SET_ISOLATED_NAVIGATION,
OP_TYPE_REORDER_TO_BOTTOM_OF_TASK,
OP_TYPE_REORDER_TO_TOP_OF_TASK,
- OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE,
+ OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE,
OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE,
OP_TYPE_SET_DIM_ON_TASK,
OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH,
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 3685bba..5227724 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -542,6 +542,9 @@
// independent either.
if (change.getMode() == TRANSIT_CHANGE) return false;
+ // Always fold the activity embedding change into the parent change.
+ if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) return false;
+
TransitionInfo.Change parentChg = info.getChange(change.getParent());
while (parentChg != null) {
// If the parent is a visibility change, it will include the results of all child
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 7f5331b..4a3aba1 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -165,7 +165,8 @@
Log.d(TAG, "Configuration not dispatch to IME because configuration is up"
+ " to date. Current config=" + context.getResources().getConfiguration()
+ ", reported config=" + currentConfig
- + ", updated config=" + newConfig);
+ + ", updated config=" + newConfig
+ + ", updated display ID=" + newDisplayId);
}
// Update display first. In case callers want to obtain display information(
// ex: DisplayMetrics) in #onConfigurationChanged callback.
@@ -190,13 +191,18 @@
if (mShouldDumpConfigForIme) {
if (!shouldReportConfigChange) {
Log.d(TAG, "Only apply configuration update to Resources because "
- + "shouldReportConfigChange is false.\n" + Debug.getCallers(5));
+ + "shouldReportConfigChange is false. "
+ + "context=" + context
+ + ", config=" + context.getResources().getConfiguration()
+ + ", display ID=" + context.getDisplayId() + "\n"
+ + Debug.getCallers(5));
} else if (diff == 0) {
Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
+ " public difference with updated config. "
+ " Current config=" + context.getResources().getConfiguration()
+ ", reported config=" + currentConfig
- + ", updated config=" + newConfig);
+ + ", updated config=" + newConfig
+ + ", display ID=" + context.getDisplayId());
}
}
}
diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig
index 90b54bd..590e88b 100644
--- a/core/java/android/window/flags/accessibility.aconfig
+++ b/core/java/android/window/flags/accessibility.aconfig
@@ -13,6 +13,16 @@
description: "Always draw fullscreen orange border in fullscreen magnification"
bug: "291891390"
metadata {
- purpose: PURPOSE_BUGFIX
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "use_window_original_touchable_region_when_magnification_recompute_bounds"
+ namespace: "accessibility"
+ description: "The flag controls whether to use the window original touchable regions in accessibilityController recomputeBounds"
+ bug: "323366243"
+ metadata {
+ purpose: PURPOSE_BUGFIX
}
}
\ No newline at end of file
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 254f4f7..7fbec67 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -18,6 +18,7 @@
flag {
name: "density_390_api"
+ is_exported: true
namespace: "large_screen_experiences_app_compat"
description: "Whether the API DisplayMetrics.DENSITY_390 is available"
bug: "297550533"
@@ -26,6 +27,7 @@
flag {
name: "app_compat_properties_api"
+ is_exported: true
namespace: "large_screen_experiences_app_compat"
description: "Whether app compat property APIs are public. Which includes: /n"
"WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE,/n"
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index ed1d434..b9d74e1 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -21,3 +21,10 @@
description: "Enables policy for modals activities"
bug: "319492844"
}
+
+flag {
+ name: "enable_windowing_dynamic_initial_bounds"
+ namespace: "lse_desktop_experience"
+ description: "Enables new initial bounds for desktop windowing which adjust depending on app constraints"
+ bug: "324377962"
+}
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index ea9da96..dea9497 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -2,6 +2,7 @@
flag {
name: "always_update_wallpaper_permission"
+ is_exported: true
namespace: "wear_frameworks"
description: "Allow out of focus process to update wallpaper complications"
bug: "271132915"
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 3f48341..5c31048 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -45,6 +45,7 @@
flag {
namespace: "window_surfaces"
name: "trusted_presentation_listener_for_window"
+ is_exported: true
description: "Enable trustedPresentationListener on windows public API"
is_fixed_read_only: true
bug: "278027319"
@@ -53,6 +54,7 @@
flag {
namespace: "window_surfaces"
name: "sdk_desired_present_time"
+ is_exported: true
description: "Feature flag for the new SDK API to set desired present time"
is_fixed_read_only: true
bug: "295038072"
@@ -61,6 +63,7 @@
flag {
namespace: "window_surfaces"
name: "surface_control_input_receiver"
+ is_exported: true
description: "Enable public API to register an InputReceiver for a SurfaceControl"
is_fixed_read_only: true
bug: "278757236"
@@ -69,6 +72,7 @@
flag {
namespace: "window_surfaces"
name: "screen_recording_callbacks"
+ is_exported: true
description: "Enable screen recording callbacks public API"
is_fixed_read_only: true
bug: "304574518"
@@ -92,3 +96,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "set_sc_properties_in_client"
+ description: "Set VRI SC properties in the client instead of system server"
+ is_fixed_read_only: true
+ bug: "308662081"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 14fb17c..a5c209d 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -16,6 +16,7 @@
flag {
name: "enforce_edge_to_edge"
+ is_exported: true
namespace: "windowing_frontend"
description: "Make app go edge-to-edge when targeting SDK level 35 or greater"
bug: "309578419"
@@ -31,6 +32,17 @@
}
flag {
+ name: "remove_prepare_surface_in_placement"
+ namespace: "windowing_frontend"
+ description: "Reduce unnecessary invocation to improve performance"
+ bug: "330721336"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "close_to_square_config_includes_status_bar"
namespace: "windowing_frontend"
description: "On close to square display, when necessary, configuration includes status bar"
@@ -38,6 +50,17 @@
}
flag {
+ name: "skip_sleeping_when_switching_display"
+ namespace: "windowing_frontend"
+ description: "Reduce unnecessary visibility or lifecycle changes when changing fold state"
+ bug: "303241079"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "introduce_smoother_dimmer"
namespace: "windowing_frontend"
description: "Refactor dim to fix flickers"
@@ -77,6 +100,7 @@
flag {
name: "supports_multi_instance_system_ui"
+ is_exported: true
namespace: "multitasking"
description: "Feature flag to enable a multi-instance system ui component property."
bug: "262864589"
@@ -85,6 +109,7 @@
flag {
name: "delegate_unhandled_drags"
+ is_exported: true
namespace: "multitasking"
description: "Enables delegating unhandled drags to SystemUI"
bug: "320797628"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 82e613e..4b3d8e8 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -43,6 +43,7 @@
flag {
namespace: "windowing_sdk"
name: "untrusted_embedding_any_app_permission"
+ is_exported: true
description: "Feature flag to enable the permission to embed any app in untrusted mode."
bug: "293647332"
is_fixed_read_only: true
@@ -59,6 +60,7 @@
flag {
namespace: "windowing_sdk"
name: "untrusted_embedding_state_sharing"
+ is_exported: true
description: "Feature flag to enable state sharing in untrusted embedding when apps opt in."
bug: "293647332"
is_fixed_read_only: true
@@ -74,6 +76,7 @@
flag {
namespace: "windowing_sdk"
name: "cover_display_opt_in"
+ is_exported: true
description: "Properties to allow apps and activities to opt-in to cover display rendering"
bug: "312530526"
is_fixed_read_only: true
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 2e80b7e..c70febb 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -20,7 +20,6 @@
import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
-import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted;
@@ -115,39 +114,22 @@
private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
final AccessibilityTarget target = mTargets.get(position);
- if (Flags.cleanupAccessibilityWarningDialog()) {
- if (target instanceof AccessibilityServiceTarget serviceTarget) {
- if (sendRestrictedDialogIntentIfNeeded(target)) {
- return;
- }
- final AccessibilityManager am = getSystemService(AccessibilityManager.class);
- if (am.isAccessibilityServiceWarningRequired(
- serviceTarget.getAccessibilityServiceInfo())) {
- showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
- position, mTargetAdapter);
- return;
- }
+ if (target instanceof AccessibilityServiceTarget serviceTarget) {
+ if (sendRestrictedDialogIntentIfNeeded(target)) {
+ return;
}
- if (target instanceof AccessibilityActivityTarget activityTarget) {
- if (!activityTarget.isShortcutEnabled()
- && sendRestrictedDialogIntentIfNeeded(activityTarget)) {
- return;
- }
+ final AccessibilityManager am = getSystemService(AccessibilityManager.class);
+ if (am.isAccessibilityServiceWarningRequired(
+ serviceTarget.getAccessibilityServiceInfo())) {
+ showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
+ position, mTargetAdapter);
+ return;
}
- } else {
- if (!target.isShortcutEnabled()) {
- if (target instanceof AccessibilityServiceTarget
- || target instanceof AccessibilityActivityTarget) {
- if (sendRestrictedDialogIntentIfNeeded(target)) {
- return;
- }
- }
-
- if (target instanceof AccessibilityServiceTarget) {
- showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
- position, mTargetAdapter);
- return;
- }
+ }
+ if (target instanceof AccessibilityActivityTarget activityTarget) {
+ if (!activityTarget.isShortcutEnabled()
+ && sendRestrictedDialogIntentIfNeeded(activityTarget)) {
+ return;
}
}
@@ -178,37 +160,25 @@
return;
}
- if (Flags.cleanupAccessibilityWarningDialog()) {
- mPermissionDialog = AccessibilityServiceWarning
- .createAccessibilityServiceWarningDialog(context,
- serviceTarget.getAccessibilityServiceInfo(),
- v -> {
- serviceTarget.onCheckedChanged(true);
- targetAdapter.notifyDataSetChanged();
- mPermissionDialog.dismiss();
- }, v -> {
- serviceTarget.onCheckedChanged(false);
- mPermissionDialog.dismiss();
- },
- v -> {
- mTargets.remove(position);
- context.getPackageManager().getPackageInstaller().uninstall(
- serviceTarget.getComponentName().getPackageName(), null);
- targetAdapter.notifyDataSetChanged();
- mPermissionDialog.dismiss();
- });
- mPermissionDialog.setOnDismissListener(dialog -> mPermissionDialog = null);
- } else {
- mPermissionDialog = new AlertDialog.Builder(context)
- .setView(createEnableDialogContentView(context, serviceTarget,
- v -> {
- mPermissionDialog.dismiss();
- targetAdapter.notifyDataSetChanged();
- },
- v -> mPermissionDialog.dismiss()))
- .setOnDismissListener(dialog -> mPermissionDialog = null)
- .create();
- }
+ mPermissionDialog = AccessibilityServiceWarning
+ .createAccessibilityServiceWarningDialog(context,
+ serviceTarget.getAccessibilityServiceInfo(),
+ v -> {
+ serviceTarget.onCheckedChanged(true);
+ targetAdapter.notifyDataSetChanged();
+ mPermissionDialog.dismiss();
+ }, v -> {
+ serviceTarget.onCheckedChanged(false);
+ mPermissionDialog.dismiss();
+ },
+ v -> {
+ mTargets.remove(position);
+ context.getPackageManager().getPackageInstaller().uninstall(
+ serviceTarget.getComponentName().getPackageName(), null);
+ targetAdapter.notifyDataSetChanged();
+ mPermissionDialog.dismiss();
+ });
+ mPermissionDialog.setOnDismissListener(dialog -> mPermissionDialog = null);
mPermissionDialog.show();
}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index 3d3db47..0d82d63 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -37,14 +37,8 @@
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
-import android.text.BidiFormatter;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.ShortcutType;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -52,7 +46,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Locale;
/**
* Collection of utilities for accessibility target.
@@ -298,50 +291,6 @@
}
/**
- * @deprecated Use {@link AccessibilityServiceWarning}.
- */
- @Deprecated
- static View createEnableDialogContentView(Context context,
- AccessibilityServiceTarget target, View.OnClickListener allowListener,
- View.OnClickListener denyListener) {
- final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
-
- final View content = inflater.inflate(
- R.layout.accessibility_enable_service_warning, /* root= */ null);
-
- final ImageView dialogIcon = content.findViewById(
- R.id.accessibility_permissionDialog_icon);
- dialogIcon.setImageDrawable(target.getIcon());
-
- final TextView dialogTitle = content.findViewById(
- R.id.accessibility_permissionDialog_title);
- dialogTitle.setText(context.getString(R.string.accessibility_enable_service_title,
- getServiceName(context, target.getLabel())));
-
- final Button allowButton = content.findViewById(
- R.id.accessibility_permission_enable_allow_button);
- final Button denyButton = content.findViewById(
- R.id.accessibility_permission_enable_deny_button);
- allowButton.setOnClickListener((view) -> {
- target.onCheckedChanged(/* isChecked= */ true);
- allowListener.onClick(view);
- });
- denyButton.setOnClickListener((view) -> {
- target.onCheckedChanged(/* isChecked= */ false);
- denyListener.onClick(view);
- });
-
- return content;
- }
-
- // Gets the service name and bidi wrap it to protect from bidi side effects.
- private static CharSequence getServiceName(Context context, CharSequence label) {
- final Locale locale = context.getResources().getConfiguration().getLocales().get(0);
- return BidiFormatter.getInstance(locale).unicodeWrap(label);
- }
-
- /**
* Determines if the{@link AccessibilityTarget} is allowed.
*/
public static boolean isAccessibilityTargetAllowed(Context context, String packageName,
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 29669d3..ab456a8 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,7 +96,6 @@
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.service.chooser.ChooserTarget;
-import android.service.chooser.Flags;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.HashedStringCache;
@@ -1801,54 +1800,6 @@
return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
}
- private void showTargetDetails(TargetInfo targetInfo) {
- if (targetInfo == null) return;
-
- ArrayList<DisplayResolveInfo> targetList;
- ChooserTargetActionsDialogFragment fragment = new ChooserTargetActionsDialogFragment();
- Bundle bundle = new Bundle();
-
- if (targetInfo instanceof SelectableTargetInfo) {
- SelectableTargetInfo selectableTargetInfo = (SelectableTargetInfo) targetInfo;
- if (selectableTargetInfo.getDisplayResolveInfo() == null
- || selectableTargetInfo.getChooserTarget() == null) {
- Log.e(TAG, "displayResolveInfo or chooserTarget in selectableTargetInfo are null");
- return;
- }
- targetList = new ArrayList<>();
- targetList.add(selectableTargetInfo.getDisplayResolveInfo());
- bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_ID_KEY,
- selectableTargetInfo.getChooserTarget().getIntentExtras().getString(
- Intent.EXTRA_SHORTCUT_ID));
- bundle.putBoolean(ChooserTargetActionsDialogFragment.IS_SHORTCUT_PINNED_KEY,
- selectableTargetInfo.isPinned());
- bundle.putParcelable(ChooserTargetActionsDialogFragment.INTENT_FILTER_KEY,
- getTargetIntentFilter());
- if (selectableTargetInfo.getDisplayLabel() != null) {
- bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_TITLE_KEY,
- selectableTargetInfo.getDisplayLabel().toString());
- }
- } else if (targetInfo instanceof MultiDisplayResolveInfo) {
- // For multiple targets, include info on all targets
- MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo;
- targetList = mti.getTargets();
- } else {
- targetList = new ArrayList<DisplayResolveInfo>();
- targetList.add((DisplayResolveInfo) targetInfo);
- }
- // Adding userHandle from ResolveInfo allows the app icon in Dialog Box to be
- // resolved correctly.
- bundle.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY,
- getResolveInfoUserHandle(
- targetInfo.getResolveInfo(),
- mChooserMultiProfilePagerAdapter.getCurrentUserHandle()));
- bundle.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY,
- targetList);
- fragment.setArguments(bundle);
-
- fragment.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
- }
-
private void modifyTargetIntent(Intent in) {
if (isSendAction(in)) {
in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
@@ -2544,10 +2495,7 @@
@Override
public boolean isComponentPinned(ComponentName name) {
- if (Flags.legacyChooserPinningRemoval()) {
- return false;
- }
- return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
+ return false;
}
@Override
@@ -3135,34 +3083,10 @@
if (isClickable) {
itemView.setOnClickListener(v -> startSelected(mListPosition,
false/* always */, true/* filterd */));
-
- itemView.setOnLongClickListener(v -> {
- final TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter()
- .targetInfoForPosition(mListPosition, /* filtered */ true);
-
- // This should always be the case for ItemViewHolder, check for validity
- if (ti instanceof DisplayResolveInfo && shouldShowTargetDetails(ti)) {
- showTargetDetails((DisplayResolveInfo) ti);
- }
- return true;
- });
}
}
}
- private boolean shouldShowTargetDetails(TargetInfo ti) {
- if (Flags.legacyChooserPinningRemoval()) {
- // Never show the long press menu if we've removed pinning.
- return false;
- }
- ComponentName nearbyShare = getNearbySharingComponent();
- // Suppress target details for nearby share to hide pin/unpin action
- boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
- ti.getResolvedComponentName()) && shouldNearbyShareBeFirstInRankedRow();
- return ti instanceof SelectableTargetInfo
- || (ti instanceof DisplayResolveInfo && !isNearbyShare);
- }
-
/**
* Add a footer to the list, to support scrolling behavior below the navbar.
*/
@@ -3517,16 +3441,6 @@
}
});
- // Show menu for both direct share and app share targets after long click.
- v.setOnLongClickListener(v1 -> {
- TargetInfo ti = mChooserListAdapter.targetInfoForPosition(
- holder.getItemIndex(column), true);
- if (shouldShowTargetDetails(ti)) {
- showTargetDetails(ti);
- }
- return true;
- });
-
holder.addView(i, v);
// Force Direct Share to be 2 lines and auto-wrap to second line via hoz scroll =
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 467cd49..751368f 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -16,6 +16,7 @@
package com.android.internal.app;
+import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS;
@@ -59,6 +60,7 @@
public static final String EXTRA_SUSPENDED_PACKAGE = PACKAGE_NAME + ".extra.SUSPENDED_PACKAGE";
public static final String EXTRA_SUSPENDING_PACKAGE =
PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE";
+ public static final String EXTRA_SUSPENDING_USER = PACKAGE_NAME + ".extra.SUSPENDING_USER";
public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO";
public static final String EXTRA_ACTIVITY_OPTIONS = PACKAGE_NAME + ".extra.ACTIVITY_OPTIONS";
public static final String EXTRA_UNSUSPEND_INTENT = PACKAGE_NAME + ".extra.UNSUSPEND_INTENT";
@@ -67,6 +69,7 @@
private IntentSender mOnUnsuspend;
private String mSuspendedPackage;
private String mSuspendingPackage;
+ private int mSuspendingUserId;
private int mNeutralButtonAction;
private int mUserId;
private PackageManager mPm;
@@ -117,7 +120,7 @@
.setPackage(mSuspendingPackage);
final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent,
- MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mUserId);
+ MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mSuspendingUserId);
if (resolvedInfo != null && resolvedInfo.activityInfo != null
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage)
@@ -231,12 +234,17 @@
}
mSuspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
mSuspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
+ if (crossUserSuspensionEnabled()) {
+ mSuspendingUserId = intent.getIntExtra(EXTRA_SUSPENDING_USER, mUserId);
+ } else {
+ mSuspendingUserId = mUserId;
+ }
mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO, android.content.pm.SuspendDialogInfo.class);
mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT, android.content.IntentSender.class);
if (mSuppliedDialogInfo != null) {
try {
mSuspendingAppResources = createContextAsUser(
- UserHandle.of(mUserId), /* flags */ 0).getPackageManager()
+ UserHandle.of(mSuspendingUserId), /* flags */ 0).getPackageManager()
.getResourcesForApplication(mSuspendingPackage);
} catch (PackageManager.NameNotFoundException ne) {
Slog.e(TAG, "Could not find resources for " + mSuspendingPackage, ne);
@@ -299,7 +307,7 @@
case BUTTON_ACTION_MORE_DETAILS:
if (mMoreDetailsIntent != null) {
startActivityAsUser(mMoreDetailsIntent, mOptions,
- UserHandle.of(mUserId));
+ UserHandle.of(mSuspendingUserId));
} else {
Slog.wtf(TAG, "Neutral button should not have existed!");
}
@@ -324,7 +332,7 @@
.putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage)
.setPackage(mSuspendingPackage)
.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mUserId));
+ sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mSuspendingUserId));
if (mOnUnsuspend != null) {
Bundle activityOptions =
@@ -365,6 +373,9 @@
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ if (crossUserSuspensionEnabled()) {
+ intent.putExtra(EXTRA_SUSPENDING_USER, suspendingPackage.userId);
+ }
return intent;
}
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 3662d69..d2a533c 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -124,10 +124,13 @@
public static final int CUJ_BACK_PANEL_ARROW = 88;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK = 89;
public static final int CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH = 90;
+ public static final int CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE = 91;
+ public static final int CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR = 92;
+ public static final int CUJ_LAUNCHER_SAVE_APP_PAIR = 93;
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
@VisibleForTesting
- static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH;
+ static final int LAST_CUJ = CUJ_LAUNCHER_SAVE_APP_PAIR;
/** @hide */
@IntDef({
@@ -212,6 +215,9 @@
CUJ_BACK_PANEL_ARROW,
CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK,
CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH,
+ CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE,
+ CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR,
+ CUJ_LAUNCHER_SAVE_APP_PAIR
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -306,6 +312,9 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_BACK_PANEL_ARROW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BACK_PANEL_ARROW;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_BACK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_WEB_SEARCH;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SAVE_APP_PAIR] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SAVE_APP_PAIR;
}
private Cuj() {
@@ -484,6 +493,12 @@
return "LAUNCHER_CLOSE_ALL_APPS_BACK";
case CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH:
return "LAUNCHER_SEARCH_QSB_WEB_SEARCH";
+ case CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE:
+ return "LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE";
+ case CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR:
+ return "LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR";
+ case CUJ_LAUNCHER_SAVE_APP_PAIR:
+ return "LAUNCHER_SAVE_APP_PAIR";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 0ec8b74..a288fb7 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -165,6 +165,9 @@
@Deprecated public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY;
@Deprecated public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = Cuj.CUJ_PREDICTIVE_BACK_CROSS_TASK;
@Deprecated public static final int CUJ_PREDICTIVE_BACK_HOME = Cuj.CUJ_PREDICTIVE_BACK_HOME;
+ @Deprecated public static final int CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE = Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
+ @Deprecated public static final int CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR = Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
+ @Deprecated public static final int CUJ_LAUNCHER_SAVE_APP_PAIR = Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR;
private static class InstanceHolder {
public static final InteractionJankMonitor INSTANCE =
diff --git a/core/java/com/android/internal/net/ConnectivityBlobStore.java b/core/java/com/android/internal/net/ConnectivityBlobStore.java
new file mode 100644
index 0000000..1b18485
--- /dev/null
+++ b/core/java/com/android/internal/net/ConnectivityBlobStore.java
@@ -0,0 +1,173 @@
+/*
+ * 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.internal.net;
+
+import android.annotation.NonNull;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Binder;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Database for storing blobs with a key of name strings.
+ * @hide
+ */
+public class ConnectivityBlobStore {
+ private static final String TAG = ConnectivityBlobStore.class.getSimpleName();
+ private static final String TABLENAME = "blob_table";
+ private static final String ROOT_DIR = "/data/misc/connectivityblobdb/";
+
+ private static final String CREATE_TABLE =
+ "CREATE TABLE IF NOT EXISTS " + TABLENAME + " ("
+ + "owner INTEGER,"
+ + "name BLOB,"
+ + "blob BLOB,"
+ + "UNIQUE(owner, name));";
+
+ private final SQLiteDatabase mDb;
+
+ /**
+ * Construct a ConnectivityBlobStore object.
+ *
+ * @param dbName the filename of the database to create/access.
+ */
+ public ConnectivityBlobStore(String dbName) {
+ this(new File(ROOT_DIR + dbName));
+ }
+
+ @VisibleForTesting
+ public ConnectivityBlobStore(File file) {
+ final SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY)
+ .addOpenFlags(SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING)
+ .build();
+ mDb = SQLiteDatabase.openDatabase(file, params);
+ mDb.execSQL(CREATE_TABLE);
+ }
+
+ /**
+ * Stores the blob under the name in the database. Existing blobs by the same name will be
+ * replaced.
+ *
+ * @param name The name of the blob
+ * @param blob The blob.
+ * @return true if the blob was successfully added. False otherwise.
+ * @hide
+ */
+ public boolean put(@NonNull String name, @NonNull byte[] blob) {
+ final int ownerUid = Binder.getCallingUid();
+ final ContentValues values = new ContentValues();
+ values.put("owner", ownerUid);
+ values.put("name", name);
+ values.put("blob", blob);
+
+ // No need for try-catch since it is done within db.replace
+ // nullColumnHack is for the case where values may be empty since SQL does not allow
+ // inserting a completely empty row. Since values is never empty, set this to null.
+ final long res = mDb.replace(TABLENAME, null /* nullColumnHack */, values);
+ return res > 0;
+ }
+
+ /**
+ * Retrieves a blob by the name from the database.
+ *
+ * @param name Name of the blob to retrieve.
+ * @return The unstructured blob, that is the blob that was stored using
+ * {@link com.android.internal.net.ConnectivityBlobStore#put}.
+ * Returns null if no blob was found.
+ * @hide
+ */
+ public byte[] get(@NonNull String name) {
+ final int ownerUid = Binder.getCallingUid();
+ try (Cursor cursor = mDb.query(TABLENAME,
+ new String[] {"blob"} /* columns */,
+ "owner=? AND name=?" /* selection */,
+ new String[] {Integer.toString(ownerUid), name} /* selectionArgs */,
+ null /* groupBy */,
+ null /* having */,
+ null /* orderBy */)) {
+ if (cursor.moveToFirst()) {
+ return cursor.getBlob(0);
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in getting " + name + ": " + e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes a blob by the name from the database.
+ *
+ * @param name Name of the blob to be removed.
+ * @return True if a blob was removed. False if no such name was found.
+ * @hide
+ */
+ public boolean remove(@NonNull String name) {
+ final int ownerUid = Binder.getCallingUid();
+ try {
+ final int res = mDb.delete(TABLENAME,
+ "owner=? AND name=?" /* whereClause */,
+ new String[] {Integer.toString(ownerUid), name} /* whereArgs */);
+ return res > 0;
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in removing " + name + ": " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Lists the name suffixes stored in the database matching the given prefix, sorted in
+ * ascending order.
+ *
+ * @param prefix String of prefix to list from the stored names.
+ * @return An array of strings representing the name suffixes stored in the database
+ * matching the given prefix, sorted in ascending order.
+ * The return value may be empty but never null.
+ * @hide
+ */
+ public String[] list(@NonNull String prefix) {
+ final int ownerUid = Binder.getCallingUid();
+ final List<String> names = new ArrayList<String>();
+ try (Cursor cursor = mDb.query(TABLENAME,
+ new String[] {"name"} /* columns */,
+ "owner=? AND name LIKE ?" /* selection */,
+ new String[] {Integer.toString(ownerUid), prefix + "%"} /* selectionArgs */,
+ null /* groupBy */,
+ null /* having */,
+ "name ASC" /* orderBy */)) {
+ if (cursor.moveToFirst()) {
+ do {
+ final String name = cursor.getString(0);
+ names.add(name.substring(prefix.length()));
+ } while (cursor.moveToNext());
+ }
+ } catch (SQLException e) {
+ Log.e(TAG, "Error in listing " + prefix + ": " + e);
+ }
+
+ return names.toArray(new String[names.size()]);
+ }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index a22232a..f5b1a47 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -388,9 +388,9 @@
*/
void showMediaOutputSwitcher(String packageName);
- /** Enters desktop mode.
+ /** Enters desktop mode from the current focused app.
*
* @param displayId the id of the current display.
*/
- void enterDesktop(int displayId);
+ void moveFocusedTaskToDesktop(int displayId);
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 600058e..e33704b 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -33,6 +33,7 @@
import android.view.ScrollCaptureResponse;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import com.android.internal.os.IResultReceiver;
@@ -53,7 +54,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing,
+ @Nullable ActivityWindowInfo activityWindowInfo) {
if (reportDraw) {
try {
mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
diff --git a/core/java/com/android/internal/widget/ConversationAvatarData.java b/core/java/com/android/internal/widget/ConversationAvatarData.java
index e04772f..bc9cd40 100644
--- a/core/java/com/android/internal/widget/ConversationAvatarData.java
+++ b/core/java/com/android/internal/widget/ConversationAvatarData.java
@@ -21,9 +21,9 @@
/**
* @hide
*/
-interface ConversationAvatarData {
+public interface ConversationAvatarData {
final class OneToOneConversationAvatarData implements ConversationAvatarData {
- final Drawable mDrawable;
+ public final Drawable mDrawable;
OneToOneConversationAvatarData(Drawable drawable) {
mDrawable = drawable;
diff --git a/core/java/com/android/internal/widget/ConversationHeaderData.java b/core/java/com/android/internal/widget/ConversationHeaderData.java
index 0953b39..ea92155 100644
--- a/core/java/com/android/internal/widget/ConversationHeaderData.java
+++ b/core/java/com/android/internal/widget/ConversationHeaderData.java
@@ -21,7 +21,7 @@
/**
* @hide
*/
-final class ConversationHeaderData {
+public final class ConversationHeaderData {
private final CharSequence mConversationText;
private final ConversationAvatarData mConversationAvatarData;
@@ -38,7 +38,7 @@
}
@Nullable
- ConversationAvatarData getConversationAvatar() {
+ public ConversationAvatarData getConversationAvatar() {
return mConversationAvatarData;
}
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 6d5a96a..b6066ba 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -162,6 +162,8 @@
private TouchDelegateComposite mTouchDelegate = new TouchDelegateComposite(this);
private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
private boolean mPrecomputedTextEnabled = false;
+ @Nullable
+ private ConversationHeaderData mConversationHeaderData;
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -651,6 +653,7 @@
private void setConversationAvatarAndNameFromData(
ConversationHeaderData conversationHeaderData) {
+ mConversationHeaderData = conversationHeaderData;
final OneToOneConversationAvatarData oneToOneConversationDrawable;
final GroupConversationAvatarData groupConversationAvatarData;
final ConversationAvatarData conversationAvatar =
@@ -804,7 +807,10 @@
bottomBackground.setLayoutParams(layoutParams);
}
- private void bindFacePileWithDrawable(ImageView bottomBackground, ImageView bottomView,
+ /**
+ * Binds group avatar drawables to face pile.
+ */
+ public void bindFacePileWithDrawable(ImageView bottomBackground, ImageView bottomView,
ImageView topView, GroupConversationAvatarData groupConversationAvatarData) {
applyNotificationBackgroundColor(bottomBackground);
bottomView.setImageDrawable(groupConversationAvatarData.mLastIcon);
@@ -1573,6 +1579,11 @@
return mConversationIcon;
}
+ @Nullable
+ public ConversationHeaderData getConversationHeaderData() {
+ return mConversationHeaderData;
+ }
+
private static class TouchDelegateComposite extends TouchDelegate {
private final ArrayList<TouchDelegate> mDelegates = new ArrayList<>();
diff --git a/core/java/com/android/internal/widget/EmphasizedNotificationButton.java b/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
index 01b4569..65d5a1f 100644
--- a/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
+++ b/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
@@ -229,7 +229,8 @@
+ "gluedLayoutDirection = " + mGluedLayoutDirection);
}
- if (layoutDirection != mGluedLayoutDirection) {
+ final boolean alreadyGlued = mGluedLayoutDirection != LAYOUT_DIRECTION_UNDEFINED;
+ if (alreadyGlued && layoutDirection != mGluedLayoutDirection) {
if (DEBUG_NEW_ACTION_LAYOUT) {
Log.d(TAG, "onRtlPropertiesChanged: layout direction changed; regluing");
}
@@ -278,11 +279,6 @@
// be ready to glue. This can only happen if the button is initialized and displayed and
// *then* someone calls glueIcon or glueLabel.
- if (mIconToGlue == null) {
- Log.w(TAG, "glueIconAndLabelIfNeeded: label glued without icon; doing nothing");
- return;
- }
-
if (mLabelToGlue == null) {
Log.w(TAG, "glueIconAndLabelIfNeeded: icon glued without label; doing nothing");
return;
@@ -318,6 +314,14 @@
private static final String POP_DIRECTIONAL_ISOLATE = "\u2069";
private void glueIconAndLabel(int layoutDirection) {
+ if (mIconToGlue == null) {
+ if (DEBUG_NEW_ACTION_LAYOUT) {
+ Log.d(TAG, "glueIconAndLabel: null icon, setting text to label");
+ }
+ setText(mLabelToGlue);
+ return;
+ }
+
final boolean rtlLayout = layoutDirection == LAYOUT_DIRECTION_RTL;
if (DEBUG_NEW_ACTION_LAYOUT) {
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 3aca751..2a4f062 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -27,6 +27,7 @@
# WindowManager
per-file android_graphics_BLASTBufferQueue.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file android_view_Surface* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file android_view_WindowManagerGlobal.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file android_window_* = file:/services/core/java/com/android/server/wm/OWNERS
# Resources
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 5223798..d48cdc4 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -161,6 +161,7 @@
jfieldID mMixType;
jfieldID mCallbackFlags;
jfieldID mToken;
+ jfieldID mVirtualDeviceId;
} gAudioMixFields;
static jclass gAudioFormatClass;
@@ -2312,7 +2313,7 @@
jstring deviceAddress = env->NewStringUTF(nAudioMix.mDeviceAddress.c_str());
*jAudioMix = env->NewObject(gAudioMixClass, gAudioMixCstor, jAudioMixingRule, jAudioFormat,
nAudioMix.mRouteFlags, nAudioMix.mCbFlags, nAudioMix.mDeviceType,
- deviceAddress, jBinderToken);
+ deviceAddress, jBinderToken, nAudioMix.mVirtualDeviceId);
return AUDIO_JAVA_SUCCESS;
}
@@ -2347,6 +2348,7 @@
aiBinder(AIBinder_fromJavaBinder(env, jToken), &AIBinder_decStrong);
nAudioMix->mToken = AIBinder_toPlatformBinder(aiBinder.get());
+ nAudioMix->mVirtualDeviceId = env->GetIntField(jAudioMix, gAudioMixFields.mVirtualDeviceId);
jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria));
env->DeleteLocalRef(jRule);
@@ -3676,7 +3678,7 @@
gAudioMixCstor =
GetMethodIDOrDie(env, audioMixClass, "<init>",
"(Landroid/media/audiopolicy/AudioMixingRule;Landroid/"
- "media/AudioFormat;IIILjava/lang/String;Landroid/os/IBinder;)V");
+ "media/AudioFormat;IIILjava/lang/String;Landroid/os/IBinder;I)V");
}
gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
"Landroid/media/audiopolicy/AudioMixingRule;");
@@ -3689,6 +3691,7 @@
gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
gAudioMixFields.mToken = GetFieldIDOrDie(env, audioMixClass, "mToken", "Landroid/os/IBinder;");
+ gAudioMixFields.mVirtualDeviceId = GetFieldIDOrDie(env, audioMixClass, "mVirtualDeviceId", "I");
jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 3539476..584ebaa 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -661,6 +661,35 @@
return;
}
+static jboolean android_os_Parcel_hasBinders(JNIEnv* env, jclass clazz, jlong nativePtr) {
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel != NULL) {
+ bool result;
+ status_t err = parcel->hasBinders(&result);
+ if (err != NO_ERROR) {
+ signalExceptionForError(env, clazz, err);
+ return JNI_FALSE;
+ }
+ return result ? JNI_TRUE : JNI_FALSE;
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_os_Parcel_hasBindersInRange(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jint offset, jint length) {
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel != NULL) {
+ bool result;
+ status_t err = parcel->hasBindersInRange(offset, length, &result);
+ if (err != NO_ERROR) {
+ signalExceptionForError(env, clazz, err);
+ return JNI_FALSE;
+ }
+ return result ? JNI_TRUE : JNI_FALSE;
+ }
+ return JNI_FALSE;
+}
+
static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
{
jboolean ret = JNI_FALSE;
@@ -806,7 +835,7 @@
}
// ----------------------------------------------------------------------------
-
+// clang-format off
static const JNINativeMethod gParcelMethods[] = {
// @CriticalNative
{"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
@@ -886,6 +915,9 @@
// @CriticalNative
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
{"nativeHasFileDescriptorsInRange", "(JII)Z", (void*)android_os_Parcel_hasFileDescriptorsInRange},
+
+ {"nativeHasBinders", "(J)Z", (void*)android_os_Parcel_hasBinders},
+ {"nativeHasBindersInRange", "(JII)Z", (void*)android_os_Parcel_hasBindersInRange},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
{"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
@@ -900,6 +932,7 @@
// @CriticalNative
{"nativeReplaceCallingWorkSourceUid", "(JI)Z", (void*)android_os_Parcel_replaceCallingWorkSourceUid},
};
+// clang-format on
const char* const kParcelPathName = "android/os/Parcel";
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index b579daf..4387a4c 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -124,8 +124,8 @@
});
}
-static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv* env) {
- return tracing_perfetto::getEnabledCategories();
+static jboolean android_os_Trace_nativeIsTagEnabled(jlong tag) {
+ return tracing_perfetto::isTagEnabled(tag);
}
static void android_os_Trace_nativeRegisterWithPerfetto(JNIEnv* env) {
@@ -157,7 +157,7 @@
{"nativeRegisterWithPerfetto", "()V", (void*)android_os_Trace_nativeRegisterWithPerfetto},
// ----------- @CriticalNative ----------------
- {"nativeGetEnabledTags", "()J", (void*)android_os_Trace_nativeGetEnabledTags},
+ {"nativeIsTagEnabled", "(J)Z", (void*)android_os_Trace_nativeIsTagEnabled},
};
int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index d2e58bb..982189e 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -1137,6 +1137,41 @@
}
}
+void android_os_Process_sendSignalThrows(JNIEnv* env, jobject clazz, jint pid, jint sig) {
+ if (pid <= 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid argument: pid(%d)",
+ pid);
+ return;
+ }
+ int ret = kill(pid, sig);
+ if (ret < 0) {
+ if (errno == ESRCH) {
+ jniThrowExceptionFmt(env, "java/util/NoSuchElementException",
+ "Process with pid %d not found", pid);
+ } else {
+ signalExceptionForError(env, errno, pid);
+ }
+ }
+}
+
+void android_os_Process_sendTgSignalThrows(JNIEnv* env, jobject clazz, jint tgid, jint tid,
+ jint sig) {
+ if (tgid <= 0 || tid <= 0) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Invalid argument: tgid(%d), tid(%d)", tid, tgid);
+ return;
+ }
+ int ret = tgkill(tgid, tid, sig);
+ if (ret < 0) {
+ if (errno == ESRCH) {
+ jniThrowExceptionFmt(env, "java/util/NoSuchElementException",
+ "Process with tid %d and tgid %d not found", tid, tgid);
+ } else {
+ signalExceptionForError(env, errno, tid);
+ }
+ }
+}
+
static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
{
struct timespec ts;
@@ -1357,6 +1392,8 @@
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
+ {"sendSignalThrows", "(II)V", (void*)android_os_Process_sendSignalThrows},
+ {"sendTgSignalThrows", "(III)V", (void*)android_os_Process_sendTgSignalThrows},
{"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen},
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1eab991..1aa635c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -208,10 +208,17 @@
static struct {
jclass clazz;
jmethodID ctor;
+ jfieldID timeoutMillis;
+} gIdleScreenRefreshRateConfigClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID defaultMode;
jfieldID allowGroupSwitching;
jfieldID primaryRanges;
jfieldID appRequestRanges;
+ jfieldID idleScreenRefreshRateConfig;
} gDesiredDisplayModeSpecsClassInfo;
static struct {
@@ -1407,6 +1414,18 @@
return ranges;
};
+ const auto makeIdleScreenRefreshRateConfig = [env](jobject obj)
+ -> std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig> {
+ if (obj == NULL) {
+ return std::nullopt;
+ }
+ gui::DisplayModeSpecs::IdleScreenRefreshRateConfig idleScreenRefreshRateConfig;
+ idleScreenRefreshRateConfig.timeoutMillis =
+ env->GetIntField(obj, gIdleScreenRefreshRateConfigClassInfo.timeoutMillis);
+
+ return idleScreenRefreshRateConfig;
+ };
+
gui::DisplayModeSpecs specs;
specs.defaultMode = env->GetIntField(DesiredDisplayModeSpecs,
gDesiredDisplayModeSpecsClassInfo.defaultMode);
@@ -1421,6 +1440,10 @@
makeRanges(env->GetObjectField(DesiredDisplayModeSpecs,
gDesiredDisplayModeSpecsClassInfo.appRequestRanges));
+ specs.idleScreenRefreshRateConfig = makeIdleScreenRefreshRateConfig(
+ env->GetObjectField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.idleScreenRefreshRateConfig));
+
size_t result = SurfaceComposerClient::setDesiredDisplayModeSpecs(token, specs);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
@@ -1440,6 +1463,17 @@
rangeToJava(ranges.physical), rangeToJava(ranges.render));
};
+ const auto idleScreenRefreshRateConfigToJava =
+ [env](const std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig>&
+ idleScreenRefreshRateConfig) -> jobject {
+ if (!idleScreenRefreshRateConfig.has_value()) {
+ return NULL; // Return null if input config is null
+ }
+ return env->NewObject(gIdleScreenRefreshRateConfigClassInfo.clazz,
+ gIdleScreenRefreshRateConfigClassInfo.ctor,
+ idleScreenRefreshRateConfig->timeoutMillis);
+ };
+
gui::DisplayModeSpecs specs;
if (SurfaceComposerClient::getDesiredDisplayModeSpecs(token, &specs) != NO_ERROR) {
return nullptr;
@@ -1448,7 +1482,8 @@
return env->NewObject(gDesiredDisplayModeSpecsClassInfo.clazz,
gDesiredDisplayModeSpecsClassInfo.ctor, specs.defaultMode,
specs.allowGroupSwitching, rangesToJava(specs.primaryRanges),
- rangesToJava(specs.appRequestRanges));
+ rangesToJava(specs.appRequestRanges),
+ idleScreenRefreshRateConfigToJava(specs.idleScreenRefreshRateConfig));
}
static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject tokenObj) {
@@ -2607,13 +2642,23 @@
GetFieldIDOrDie(env, RefreshRateRangesClazz, "render",
"Landroid/view/SurfaceControl$RefreshRateRange;");
+ jclass IdleScreenRefreshRateConfigClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$IdleScreenRefreshRateConfig");
+ gIdleScreenRefreshRateConfigClassInfo.clazz =
+ MakeGlobalRefOrDie(env, IdleScreenRefreshRateConfigClazz);
+ gIdleScreenRefreshRateConfigClassInfo.ctor =
+ GetMethodIDOrDie(env, gIdleScreenRefreshRateConfigClassInfo.clazz, "<init>", "(I)V");
+ gIdleScreenRefreshRateConfigClassInfo.timeoutMillis =
+ GetFieldIDOrDie(env, gIdleScreenRefreshRateConfigClassInfo.clazz, "timeoutMillis", "I");
+
jclass DesiredDisplayModeSpecsClazz =
FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayModeSpecs");
gDesiredDisplayModeSpecsClassInfo.clazz = MakeGlobalRefOrDie(env, DesiredDisplayModeSpecsClazz);
gDesiredDisplayModeSpecsClassInfo.ctor =
GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>",
"(IZLandroid/view/SurfaceControl$RefreshRateRanges;Landroid/view/"
- "SurfaceControl$RefreshRateRanges;)V");
+ "SurfaceControl$RefreshRateRanges;Landroid/view/"
+ "SurfaceControl$IdleScreenRefreshRateConfig;)V");
gDesiredDisplayModeSpecsClassInfo.defaultMode =
GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "defaultMode", "I");
gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching =
@@ -2624,6 +2669,9 @@
gDesiredDisplayModeSpecsClassInfo.appRequestRanges =
GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRanges",
"Landroid/view/SurfaceControl$RefreshRateRanges;");
+ gDesiredDisplayModeSpecsClassInfo.idleScreenRefreshRateConfig =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "idleScreenRefreshRateConfig",
+ "Landroid/view/SurfaceControl$IdleScreenRefreshRateConfig;");
jclass jankDataClazz =
FindClassOrDie(env, "android/view/SurfaceControl$JankData");
diff --git a/core/jni/android_view_WindowManagerGlobal.cpp b/core/jni/android_view_WindowManagerGlobal.cpp
index b03ac88..abc621d 100644
--- a/core/jni/android_view_WindowManagerGlobal.cpp
+++ b/core/jni/android_view_WindowManagerGlobal.cpp
@@ -48,7 +48,7 @@
surfaceControlObj(env,
android_view_SurfaceControl_getJavaSurfaceControl(env,
surfaceControl));
- jobject clientTokenObj = javaObjectForIBinder(env, clientToken);
+ ScopedLocalRef<jobject> clientTokenObj(env, javaObjectForIBinder(env, clientToken));
ScopedLocalRef<jobject> clientInputTransferTokenObj(
env,
android_window_InputTransferToken_getJavaInputTransferToken(env,
@@ -57,7 +57,7 @@
inputChannelObj(env,
env->CallStaticObjectMethod(gWindowManagerGlobal.clazz,
gWindowManagerGlobal.createInputChannel,
- clientTokenObj,
+ clientTokenObj.get(),
hostInputTransferTokenObj.get(),
surfaceControlObj.get(),
clientInputTransferTokenObj.get()));
@@ -68,9 +68,9 @@
void removeInputChannel(const sp<IBinder>& clientToken) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject clientTokenObj(javaObjectForIBinder(env, clientToken));
+ ScopedLocalRef<jobject> clientTokenObj(env, javaObjectForIBinder(env, clientToken));
env->CallStaticObjectMethod(gWindowManagerGlobal.clazz, gWindowManagerGlobal.removeInputChannel,
- clientTokenObj);
+ clientTokenObj.get());
}
int register_android_view_WindowManagerGlobal(JNIEnv* env) {
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 763d9ce..fcc85b7 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -102,6 +102,7 @@
optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto accessibility_pinch_to_zoom_anywhere_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto accessibility_single_finger_panning_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto accessibility_floating_menu_targets = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
@@ -143,9 +144,11 @@
optional SettingProto gesture_setup_complete = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto touch_gesture_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto long_press_home_enabled = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto search_long_press_home_enabled = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Deprecated - use search_all_entrypoints_enabled instead
+ optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
+ optional SettingProto search_long_press_home_enabled = 13 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
optional SettingProto visual_query_accessibility_detection_enabled = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto search_all_entrypoints_enabled = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Assist assist = 7;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 068f4dd..d30f195 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -142,6 +142,7 @@
// UTC timestamp of first install for the user
optional int32 first_install_time_ms = 11;
optional ArchiveState archive_state = 12;
+ repeated int32 suspending_user = 13;
}
message InstallSourceProto {
diff --git a/core/res/res/drawable/activity_embedding_divider_handle.xml b/core/res/res/drawable/activity_embedding_divider_handle.xml
new file mode 100644
index 0000000..d9f363c
--- /dev/null
+++ b/core/res/res/drawable/activity_embedding_divider_handle.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/activity_embedding_divider_handle_pressed" />
+ <item android:drawable="@drawable/activity_embedding_divider_handle_default" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/activity_embedding_divider_handle_default.xml b/core/res/res/drawable/activity_embedding_divider_handle_default.xml
new file mode 100644
index 0000000..565f671
--- /dev/null
+++ b/core/res/res/drawable/activity_embedding_divider_handle_default.xml
@@ -0,0 +1,23 @@
+<!--
+ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/activity_embedding_divider_handle_radius" />
+ <size
+ android:width="@dimen/activity_embedding_divider_handle_width"
+ android:height="@dimen/activity_embedding_divider_handle_height" />
+ <solid android:color="@color/activity_embedding_divider_color" />
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/activity_embedding_divider_handle_pressed.xml b/core/res/res/drawable/activity_embedding_divider_handle_pressed.xml
new file mode 100644
index 0000000..e5cca239
--- /dev/null
+++ b/core/res/res/drawable/activity_embedding_divider_handle_pressed.xml
@@ -0,0 +1,23 @@
+<!--
+ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/activity_embedding_divider_handle_radius_pressed" />
+ <size
+ android:width="@dimen/activity_embedding_divider_handle_width_pressed"
+ android:height="@dimen/activity_embedding_divider_handle_height_pressed" />
+ <solid android:color="@color/activity_embedding_divider_color_pressed" />
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/autofill_dataset_picker_background.xml b/core/res/res/drawable/autofill_dataset_picker_background.xml
index d574970..6c4ef11 100644
--- a/core/res/res/drawable/autofill_dataset_picker_background.xml
+++ b/core/res/res/drawable/autofill_dataset_picker_background.xml
@@ -16,7 +16,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
- <corners android:radius="@dimen/config_bottomDialogCornerRadius" />
+ <corners android:radius="@dimen/config_buttonCornerRadius" />
<solid android:color="?attr/colorBackground" />
</shape>
</inset>
diff --git a/core/res/res/layout/transient_notification_with_icon.xml b/core/res/res/layout/transient_notification_with_icon.xml
index 0dfb3ad..04518b2 100644
--- a/core/res/res/layout/transient_notification_with_icon.xml
+++ b/core/res/res/layout/transient_notification_with_icon.xml
@@ -22,7 +22,7 @@
android:orientation="horizontal"
android:gravity="center_vertical"
android:maxWidth="@dimen/toast_width"
- android:background="?android:attr/colorBackground"
+ android:background="@android:drawable/toast_frame"
android:elevation="@dimen/toast_elevation"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
@@ -31,8 +31,11 @@
<ImageView
android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp"
+ android:layout_marginEnd="10dp" />
<TextView
android:id="@android:id/message"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 5e43512..ed05041 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Kan nie selnetwerk bereik nie"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probeer die voorkeurnetwerk verander. Tik om te verander."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Noodoproepe is onbeskikbaar"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Kan nie noodoproepe oor Wi-Fi maak nie"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Opletberigte"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Oproepaanstuur"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Noodterugbel-modus"</string>
@@ -137,7 +138,7 @@
<string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"Wi-Fi-oproepe | <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wfcSpnFormat_spn_vowifi" msgid="6865214948822061486">"<xliff:g id="SPN">%s</xliff:g>-VoWifi"</string>
<string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Wi-Fi-oproepe"</string>
- <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-oproepe"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
<string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-fi-oproep"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Vee uit"</string>
<string name="inputMethod" msgid="1784759500516314751">"Invoermetode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Teksaksies"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Terug"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Wissel invoermetode"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Bergingspasie word min"</string>
@@ -1339,7 +1344,7 @@
<string name="network_switch_metered_toast" msgid="501662047275723743">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
<string-array name="network_switch_type_name">
<item msgid="2255670471736226365">"mobiele data"</item>
- <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="5520925862115353992">"Wi-fi"</item>
<item msgid="1055487873974272842">"Bluetooth"</item>
<item msgid="1616528372438698248">"Ethernet"</item>
<item msgid="9177085807664964627">"VPN"</item>
@@ -1900,7 +1905,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige apps om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n App wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Een minuut lank (tot {formattedTime})}other{# minute lank (tot {formattedTime})}}"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a06d4d4..a127ad7 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ášáá£áá á áá³áš áášá¥á ááµášáµ á áá°á»áá"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"á°áá«á á áá³áš áášá¥á ááááᥠáááá©á¢ ááááᥠáá³ á«áµááá¢"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ášá á°á áá á¥áª á áááá"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"á WiâFi á á©á ášá á°á áá á¥áªááœá ááµášá á ááœáá"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"áááá«ááœ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"á¥áª ááµá°ááá"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ášá á°á áá á¥áª ááá³"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"á°áá"</string>
<string name="inputMethod" msgid="1784759500516314751">"áá€áµ áµááµ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ášá
áá á¥áááááœ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"á°áááµ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ášáá€áµ áµááµá ááá"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ášáášáá» áŠá³ á¥á«áá áá"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 894371c..d67443a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -88,7 +88,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÙØªØ¹Ø°Ùر اÙÙØµÙ٠إÙÙ ØŽØšÙØ© Ø§ÙØ¬ÙÙØ§Ù."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ØØ§Ù٠تغÙÙØ± Ø§ÙØŽØšÙØ© اÙÙ
ÙØ¶ÙØ©. اÙÙØ± ÙØªØºÙÙØ±Ùا."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÙØ§ تتÙÙØ± Ø¥Ù
ÙØ§ÙÙØ© Ø§ÙØ§ØªØµØ§Ù ÙÙ ØØ§Ùات Ø§ÙØ·Ùار؊."</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ÙØªØ¹Ø°Ùر إجراء Ù
ÙØ§ÙÙ
ات Ø·ÙØ§Ø±ØŠ عؚر WiâFi."</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ø§ÙØªÙØšÙÙØ§Øª"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"إعادة ØªÙØ¬Ù٠اÙÙ
ÙØ§ÙÙ
Ø©"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ÙØ¶Ø¹ Ù
Ø¹Ø§ÙØ¯Ø© Ø§ÙØ§ØªØµØ§Ù ØšØ§ÙØ·Ùار؊"</string>
@@ -1187,6 +1188,10 @@
<string name="deleteText" msgid="4200807474529938112">"ØØ°Ù"</string>
<string name="inputMethod" msgid="1784759500516314751">"طرÙÙØ© Ø§ÙØ¥Ø±Ø³Ø§Ù"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"إجراءات اÙÙØµ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Ø±Ø¬ÙØ¹"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"تؚدÙ٠أسÙÙØš Ø§ÙØ¥Ø¯Ø®Ø§Ù"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ù
Ø³Ø§ØØ© Ø§ÙØªØ®Ø²ÙÙ Ù
ÙØ®Ùضة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b1af54f..6117086 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"àŠ®’àŠ¬àŠŸàŠàв àŠšà§àŠà§±à§°à§àŠà§° àŠ²àŠàŠ€ àŠžàŠàНà§àŠ àŠà§°àŠ¿àŠ¬ àŠªà§°àŠŸ àŠšàŠŸàŠ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"àŠªàŠàŠšà§àŠŠà§° àŠšà§àŠà§±à§°à§àŠ àŠžàŠ²àŠšàŠ¿ àŠà§°àŠ¿ àŠà§àŠ·à§àŠàŠŸ àŠà§°àŠ¿ àŠàŠŸàŠàŠà¥€ àŠžàŠ²àŠšàŠ¿ àŠà§°àŠ¿àŠ¬àŠ²à§ àŠàŠ¿àŠªàŠà¥€"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àŠà§°à§à§°à§àŠàŠŸàŠ²à§àŠš àŠàв àŠà§°àŠŸà§° àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠàŠªàŠ²àŠ¬à§àЧ àŠšàŠ¹àŠ¯àŠŒ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"à§±àŠŸàŠ-àŠ«àŠŸàŠà§° àŠà§°àŠ¿àŠ¯àŠŒàŠ€à§ àŠà§°à§à§°à§àŠàŠŸàŠ²à§àŠš àŠàв àŠà§°àŠ¿àŠ¬ àŠšà§à§±àŠŸà§°àŠ¿"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àŠžàŠ€à§°à§àŠàŠ¬àŠŸàŠ£à§àŠžàŠ®à§àй"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àŠàв àŠ«à§°à§±àŠŸà§°à§àŠ¡àŠ¿àŠ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"àŠà§°à§à§°à§àŠàŠŸàŠ²à§àŠš àŠ\'àŠ²àŠ¬à§àŠ àŠ®\'àŠ¡"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"àŠ®àŠàŠ"</string>
<string name="inputMethod" msgid="1784759500516314751">"àŠàŠšàŠªà§àŠ àŠªàŠŠà§àŠ§àŠ€àŠ¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àŠªàŠŸàŠ àŠ¬àŠ¿àŠ·àŠ¯àŠŒàŠ àŠàŠŸà§°à§àН"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àŠàŠàŠ€àŠ¿ àŠ¯àŠŸàŠàŠ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àŠàŠšàŠªà§àŠà§° àŠªàŠŠà§àŠ§àŠ€àŠ¿ àŠžàŠ²àŠšàŠ¿ àŠà§°àŠ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àŠ·à§àŠ’à§°à§àŠà§° àŠàŠŸàŠ²à§ àŠ àŠŸàŠ àŠ¶à§àŠ· àŠ¹à§ àŠàŠà§"</string>
@@ -1922,7 +1927,7 @@
<string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"àŠ¡àŠŸàŠàŠšàŠàŠŸàŠàŠ®"</string>
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"àŠàŠŸà§°à§àН-àŠŠàŠ¿àŠšà§° àŠšàŠ¿àŠ¶àŠŸ"</string>
<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_events_name" msgid="2280682960128512257">"àŠ
àŠšà§àŠ·à§àŠ àŠŸàŠš"</string>
<string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"àŠšàŠ¿àŠŠà§à§°àŠŸà§°àŠ€"</string>
<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>
@@ -1972,7 +1977,7 @@
<string name="language_selection_title" msgid="52674936078683285">"àŠàŠŸàŠ·àŠŸ àŠ¯à§àŠ àŠà§°àŠ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"àŠ
àŠà§àŠàŠ²à§° àŠ
àŠà§à§°àŠŸàŠ§àŠ¿àŠàŠŸà§°"</string>
<string name="search_language_hint" msgid="7004225294308793583">"àŠàŠŸàŠ·àŠŸà§° àŠšàŠŸàŠ® àŠ²àŠ¿àŠàŠ"</string>
- <string name="language_picker_section_suggested" msgid="6556199184638990447">"àŠªà§à§°àŠžà§àŠ€àŠŸà§±àŠ¿àŠ€"</string>
+ <string name="language_picker_section_suggested" msgid="6556199184638990447">"àŠªà§°àŠŸàŠ®à§°à§àŠ¶àŠ¿àŠ€"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"àŠªà§°àŠŸàŠ®à§°à§àŠ¶àŠ¿àŠ€"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"àŠªà§°àŠŸàŠ®à§°à§àŠ¶àŠ¿àŠ€ àŠàŠŸàŠ·àŠŸàŠžàŠ®à§àй"</string>
<string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"àŠà§àŠªàŠŸà§°àŠ¿àŠ àŠà§°àŠŸ àŠ
àŠà§àŠàŠ²àŠžàŠ®à§àй"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0d0d102..a186815 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil ÅÉbÉkÉyÉ daxil olmaq mümkün deyil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"TÉrcih edilÉn ÅÉbÉkÉni dÉyiÅin. DÉyiÅmÉk üçün kliklÉyin."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"TÉcili zÉng Élçatan deyil"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi vasitÉsilÉ tÉcili zÉnglÉr etmÉk mümkün deyil"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Siqnallar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ZÉng yönlÉndirmÉ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"TÉcili geriyÉ zÉng rejimi"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Sil"</string>
<string name="inputMethod" msgid="1784759500516314751">"DaxiletmÉ metodu"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"MÉtn ÉmÉliyyatları"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"GeriyÉ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"DaxiletmÉ metodunu dÉyiÅdirin"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"YaddaÅ yeri bitir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 653a06b..76554fb 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Povezivanje sa mobilnom mreÅŸom nije uspelo"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probajte da promenite ÅŸeljenu mreÅŸu. Dodirnite da biste promenili."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi nisu dostupni"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ne moÅŸete da upuÄujete hitne pozive preko WiâFi-ja"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmeravanje poziva"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ReÅŸim za hitan povratni poziv"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Izbriši"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metod unosa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Radnje u vezi sa tekstom"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Nazad"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Promenite metod unosa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Memorijski prostor je na izmaku"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2f517a5..c7d4224 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"СеÑка ЌабÑлÑМай ÑÑвÑÐ·Ñ ÐœÐµÐŽÐ°ÑÑÑпМаÑ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÐаÑÑÑМÑÑе, каб вÑбÑаÑÑ ÑМÑÑÑ ÑеÑкÑ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐкÑÑÑаММÑÑ Ð²ÑклÑÐºÑ ÐœÐµÐŽÐ°ÑÑÑпМÑÑ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ÐкÑÑÑаММÑÑ Ð²ÑклÑÐºÑ Ñ ÑеÑÑÑ WiâFi МеЎаÑÑÑпМÑÑ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÐбвеÑÑкÑ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐеÑааЎÑаÑаÑÑÑ Ð²ÑклÑкÑ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Ð ÑжÑÐŒ ÑкÑÑÑаММÑÑ
зваÑПÑМÑÑ
вÑклÑкаÑ"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐÑЎалiÑÑ"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐеÑаЎ ÑвПЎÑ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐзеÑÐœÐœÑ Ð· ÑÑкÑÑаЌ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐеÑаклÑÑÑММе ÑÑжÑÐŒÑ ÑвПЎÑ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐеÑÑа ÐŽÐ»Ñ Ð·Ð°Ñ
Ð°Ð²Ð°ÐœÐœÑ ÐœÐ° зÑÑ
ПЎзе"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1b486fb..d5b59a8 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ðе ЌПже Ўа Ñе ÑÑÑаМПвО вÑÑзка Ñ ÐŒÐŸÐ±ÐžÐ»ÐœÐ°Ñа ÐŒÑежа"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÐзбеÑеÑе ÐŽÑÑга пÑеЎпПÑОÑаМа ÐŒÑежа. ÐПкПÑМеÑе за пÑПЌÑМа."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐÑЌа ЎПÑÑÑп ЎП ÑпеÑМОÑе ПбажЎаМОÑ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ðе ЌПже Ўа Ñе ОзвÑÑÑÐ²Ð°Ñ ÑпеÑМО ÐŸÐ±Ð°Ð¶ÐŽÐ°ÐœÐžÑ Ð¿Ñез Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"СОгМалО"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐÑеМаÑПÑваМе Ма ПбажЎаМОÑ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"РежОЌ Ма ПбÑаÑМП ПбажЎаМе пÑО ÑпеÑМПÑÑ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐзÑÑОваМе"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐеÑПЎ Ма вÑвежЎаМе"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐейÑÑÐ²ÐžÑ Ñ ÑекÑÑа"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐÑевклÑÑваМе Ма ЌеÑПЎа Ма вÑвежЎаМе"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐÑÑÑПÑП в Ñ
ÑаМОлОÑеÑП е Ма ОзÑеÑпваМе"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b9fde04..ef02111 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"àŠ®à§àŠ¬àŠŸàŠàв àŠšà§àŠàŠàŠ¯àŠŒàŠŸàŠ°à§àŠà§ àŠàŠŸàŠšà§àŠà§àŠ àŠàŠ°àŠŸ àŠ¯àŠŸàŠà§àŠà§ àŠšàŠŸ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"àŠªàŠàŠšà§àŠŠà§àа àŠšà§àŠàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ àŠªàŠ°àŠ¿àŠ¬àŠ°à§àŠ€àŠš àŠàŠ°à§ àŠŠà§àŠà§àŠšà¥€ àŠ
àŠšà§àН àŠšà§àŠàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ àŠ¬à§àŠà§ àŠšàŠ¿àŠ€à§ àŠà§àŠ¯àŠŸàŠª àŠàаà§àŠšà¥€"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àŠàаà§àŠ°àŠ¿ àŠàв àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¬à§ àŠšàŠŸ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"àŠàŠ¯àŠŒàŠŸàŠ-àŠ«àŠŸàŠàŠ¯àŠŒà§àа àŠ®àŠŸàŠ§à§àŠ¯àŠ®à§ àŠàаà§àŠ°àŠ¿ àŠàв àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¬à§ àŠšàŠŸ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àŠžàŠ€àŠ°à§àŠàŠ€àŠŸ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àŠàв àŠ«àŠ°àŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠàŠ°àŠŸ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"àŠàаà§àŠ°àŠ¿ àŠàŠ²àŠ¬à§àŠ¯àŠŸàŠ àŠ®à§àŠ¡"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"àŠ®à§àŠà§àŠš"</string>
<string name="inputMethod" msgid="1784759500516314751">"àŠàŠšàŠªà§àŠ àŠªàŠŠà§àŠ§àŠ€àŠ¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àŠªàŠŸàŠ à§àН àŠà§àŠ°àŠ¿àŠ¯àŠŒàŠŸàŠà§àŠ²àŠ¿"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àŠ«àŠ¿àŠ°à§ àŠ¯àŠŸàŠš"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àŠàŠšàŠªà§àŠ àŠªàŠŠà§àŠ§àŠ€àŠ¿ àŠªàŠŸàŠ²à§àŠàŠŸàŠš"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àŠžà§àŠà§àаà§àŠ àŠªà§àаà§àŠ£ àŠ¹àŠ€à§ àŠàвà§àŠà§"</string>
@@ -1718,7 +1723,7 @@
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"àŠàŠàŠ¯àŠŒ àŠàŠ²àŠ¿àŠàŠ® àŠà§ àŠàŠ¯àŠŒà§àŠ àŠžà§àŠà§àŠšà§àŠ¡ àŠ§àŠ°à§ àŠ¥àŠŸàŠàŠ²à§ <xliff:g id="SERVICE">%1$s</xliff:g> àŠàŠŸàŠ²à§ àŠ¹àŠ¯àŠŒà§ àŠ¯àŠŸàŠ¬à§à¥€ àŠàŠàŠ¿ àŠàŠàŠàŠ¿ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠžàŠ¿àŠ¬àŠ¿àŠ²àŠ¿àŠàŠ¿ àŠ«àŠ¿àŠàŠŸàŠ°à¥€ àŠàа àŠ«àŠ²à§, àŠàŠªàŠšàŠŸàŠ° àŠ¡àŠ¿àŠàŠŸàŠàŠž àŠà§àŠàŠŸàŠ¬à§ àŠàŠŸàŠ àŠàŠ°àŠ¬à§ àŠžà§àŠàŠ¿àŠ€à§ àŠªàŠ°àŠ¿àŠ¬àŠ°à§àŠ€àŠš àŠ¹àŠ€à§ àŠªàŠŸàŠ°à§à¥€\n\nàŠžà§àŠàŠ¿àŠàŠž > àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠžàŠ¿àŠ¬àŠ¿àŠ²àŠ¿àŠàŠ¿ àŠ¥à§àŠà§ àŠàŠªàŠšàŠ¿ àŠàŠ àŠ¶àŠ°à§àŠàŠàŠŸàŠ àŠªàŠ°àŠ¿àŠ¬àŠ°à§àŠ€àŠš àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§àŠšà¥€"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"àŠàŠŸàŠ²à§ àŠàаà§àŠš"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"àŠàŠŸàŠ²à§ àŠàŠ°àŠ¬à§àŠš àŠšàŠŸ"</string>
- <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"àŠàŠŸàŠ²à§"</string>
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"àŠàŠŸàŠ²à§ àŠàŠà§"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"àŠ¬àŠšà§àЧ"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> àŠ
à§àŠ¯àŠŸàŠªàŠàŠ¿àŠà§ àŠàŠªàŠšàŠŸàŠ° àŠ¡àŠ¿àŠàŠŸàŠàŠžà§ àŠžàŠ®à§àŠªà§àаà§àŠ£ àŠšàŠ¿àŠ¯àŠŒàŠšà§àŠ€à§àŠ°àŠ£à§àа àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠ€à§ àŠàŠŸàŠš?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"àŠ¯à§ àŠ
à§àŠ¯àŠŸàŠªàŠà§àŠ²àŠ¿ àŠàŠªàŠšàŠŸàŠà§ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠžàŠ¿àŠ¬àŠ¿àŠ²àŠ¿àŠàŠ¿àŠ° àŠªà§àŠ°àŠ¯àŠŒà§àŠàŠš àŠ®à§àŠàŠŸàŠ€à§ àŠžàŠŸàŠ¹àŠŸàŠ¯à§àН àŠàŠ°à§ àŠžà§àŠ àŠ
à§àŠ¯àŠŸàŠªàŠà§àŠ²àŠ¿àŠ° àŠàŠšà§àН àŠžàŠ®à§àŠªà§àаà§àŠ£ àŠšàŠ¿àŠ¯àŠŒàŠšà§àŠ€à§àŠ°àŠ£à§àа àŠ¬àŠ¿àŠ·àŠ¯àŠŒàŠàŠ¿ àŠàŠªàŠ¯à§àŠà§àŠ€, àŠàŠ¿àŠšà§àŠ€à§ àŠ€àŠŸ àŠ¬àŠ²à§ àŠžàŠ®àŠžà§àŠ€ àŠ
à§àŠ¯àŠŸàŠªà§àа àŠàŠšà§àН àŠšàŠ¯àŠŒà¥€"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 2414b7e..9f0a387 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nije moguÄe dosegnuti mobilnu mreÅŸu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pokušajte promijeniti preferiranu mreÅŸu. Dodirnite za promjenu."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi su nedostupni"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nije moguÄe uspostaviti hitne pozive putem WiâFi mreÅŸe"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ProsljeÄivanje poziva"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"NaÄin rada za hitni povratni poziv"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Izbriši"</string>
<string name="inputMethod" msgid="1784759500516314751">"NaÄin unosa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Akcije za tekst"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Nazad"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Promjena naÄina unosa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ponestaje prostora za pohranu"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8e733ec..7aad1a7 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No es pot accedir a la xarxa mòbil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prova de canviar de xarxa preferent. Toca per canviar-la."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Les trucades d\'emergència no estan disponibles"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"No es poden fer trucades d\'emergència per Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desviació de trucades"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode de devolució de trucada d\'emergència"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Suprimeix"</string>
<string name="inputMethod" msgid="1784759500516314751">"Mètode d\'introducció de text"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Accions de text"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Enrere"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Canvia el mètode d\'introducció de text"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index dee6bbb..eba1796 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilní síÅ¥ není dostupná"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Zkuste zmÄnit preferovanou síÅ¥. ZmÄníte ji klepnutím."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"TísÅová volání jsou nedostupná"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"PÅes WiâFi nelze uskuteÄÅovat tísÅová volání"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"UpozornÄní"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"PÅesmÄrování hovorů"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ReÅŸim tísÅového zpÄtného volání"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"Smazat"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metoda zadávání dat"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Operace s textem"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ZpÄt"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"PÅepnout metodu zadávání"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"V úloÅŸišti je málo místa"</string>
@@ -1973,7 +1978,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"PÅidat dozorovaného uÅŸivatele"</string>
<string name="language_selection_title" msgid="52674936078683285">"PÅidat jazyk"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferovaná oblast"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"Zadejte název jazyka"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Zadejte jazyk"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Navrhované"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"NavrÅŸeno"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Navrhované jazyky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bde7dbd..d0dca41 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Der er ingen forbindelse til mobilnetværket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prøv at skifte dit foretrukne netværk. Tryk for skifte."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Det er ikke muligt at foretage nødopkald"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Det er ikke muligt at foretage nødopkald via WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Underretninger"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Viderestilling af opkald"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Nødtilbagekaldstilstand"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Slet"</string>
<string name="inputMethod" msgid="1784759500516314751">"Inputmetode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Teksthandlinger"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Tilbage"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Skift indtastningsmetode"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Der er snart ikke mere lagerplads"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 27d3848..fea2777 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilfunknetz nicht erreichbar"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Versuche, das bevorzugte Netzwerk zu ändern. Tippe, um ein anderes auszuwählen."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Notrufe nicht möglich"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Notrufe über WLAN nicht möglich"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Warnmeldungen"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Anrufweiterleitung"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Notfallrückrufmodus"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Löschen"</string>
<string name="inputMethod" msgid="1784759500516314751">"Eingabemethode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Textaktionen"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Zurück"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Eingabemethode wechseln"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Der Speicherplatz wird knapp"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1f9c09f..dec720f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Δεν είναι δυνατή η σÏνδεση στο δίκτυο κινητής τηλεφωνίας"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Δοκιμάστε να αλλάξετε το προτιμÏμενο δίκτυο. Πατήστε για αλλαγή."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Οι κλήσεις Îκτακτης ανάγκης δεν είναι διαθÎσιμες"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Δεν είναι δυνατή η πραγματοποίηση κλήσεων Îκτακτης ανάγκης μÎσω WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ειδοποιήσεις"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ΠροÏθηση κλήσης"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Λειτουργία επιστροφής κλήσης Îκτακτης ανάγκης"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Διαγραφή"</string>
<string name="inputMethod" msgid="1784759500516314751">"ΜÎθοδος εισÏδου"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ΕνÎργειες κειμÎνου"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Πίσω"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Εναλλαγή μεθÏδου εισαγωγής"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ο αποθηκευτικÏς χÏρος εξαντλείται"</string>
@@ -1900,7 +1905,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</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_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{Για Îνα λεπτÏ (μÎχρι τις {formattedTime})}other{Για # λεπτά (μÎχρι τις {formattedTime})}}"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 907026a..dc36c8c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Can’t make emergency calls over WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Input method"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Text actions"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Back"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Switch input method"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Storage space running out"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4148ad7..c1316ed 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Can’t make emergency calls over WiâFi"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Emergency calls require a mobile network"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1183,8 @@
<string name="deleteText" msgid="4200807474529938112">"Delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Input method"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Text actions"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Handwriting is not supported in this field"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Handwriting is not supported in password fields"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Back"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Switch input method"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Storage space running out"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a3f50c5..9f00023 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Can’t make emergency calls over WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Input method"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Text actions"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Back"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Switch input method"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Storage space running out"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 72d89fb..67ca701 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Can’t make emergency calls over WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Input method"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Text actions"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Back"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Switch input method"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Storage space running out"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index edba901..4abc241 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Can’t reach mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Try changing preferred network. Tap to change."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Emergency calling unavailable"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Can’t make emergency calls over WiâFi"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Emergency calls require a mobile network"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerts"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Call forwarding"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1183,8 @@
<string name="deleteText" msgid="4200807474529938112">"Delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Input method"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Text actions"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Handwriting is not supported in this field"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Handwriting is not supported in password fields"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Back"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Switch input method"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Storage space running out"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c23ad31..03660cb 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No se puede acceder a la red móvil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Presiona para cambiar la red preferida."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Servicio de llamadas de emergencia no disponible"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"No se pueden hacer llamadas de emergencia mediante Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de llamada"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de devolución de llamada de emergencia"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Eliminar"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Acciones de texto"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Atrás"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Cambiar método de entrada"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Queda poco espacio de almacenamiento"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index def340d3..1554b46 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"No se puede establecer conexión con la red móvil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Toca para cambiar la red preferida."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Servicio de llamadas de emergencia no disponible"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"No se pueden hacer llamadas de emergencia por WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de llamadas"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de devolución de llamada de emergencia"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Eliminar"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de introducción de texto"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Acciones de texto"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Atrás"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Cambiar método de introducción de texto"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Queda poco espacio"</string>
@@ -1901,7 +1906,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}many{Durante # minutos (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string>
@@ -1972,7 +1977,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Añadir usuario supervisado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Añadir un idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"Nombre de idioma"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Escribe el idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerencias"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 90a98a5..9b9760c 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobiilsidevõrguga ei saa ühendust"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Proovige eelistatud võrku vahetada. Puudutage muutmiseks."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hädaabikõned pole saadaval"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiFi kaudu ei saa hädaabikõnesid teha"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Hädaabikõnede jaoks on vajalik mobiilsidevõrk"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Teatised"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Kõnede suunamine"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Hädaolukorra tagasihelistusreÅŸiim"</string>
@@ -1183,6 +1183,8 @@
<string name="deleteText" msgid="4200807474529938112">"Kustuta"</string>
<string name="inputMethod" msgid="1784759500516314751">"Sisestusmeetod"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tekstitoimingud"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Käsitsi kirjutamine ei ole sellel väljal toetatud"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Käsitsi kirjutamine ei ole parooliväljadel toetatud"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Tagasi"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Sisestusmeetodi vahetamine"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Talletusruum saab täis"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 45d9e25..7f9919d 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ezin da konektatu sare mugikorrera"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Aldatu sare hobetsia. Sakatu aldatzeko."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Ezin da egin larrialdi-deirik"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ezin duzu egin larrialdi-deirik Wi-Fi bidez"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertak"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Dei-desbideratzea"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Larrialdi-zerbitzuen deiak jasotzeko modua"</string>
@@ -278,7 +279,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"Ezarpenak"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Lagundu"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ahots-laguntza"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"Blokeoa"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"Blokeatu"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Jakinarazpen berria"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teklatu fisikoa"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Ezabatu"</string>
<string name="inputMethod" msgid="1784759500516314751">"Idazketa-metodoa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Testu-ekintzak"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Atzera"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Aldatu idazketa-metodoa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Memoria betetzen ari da"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index c1a1b82..af97c90 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"؎ؚک٠تÙÙÙ ÙÙ
را٠دردسترس ÙÛØ³Øª"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"تغÛÛØ± ØŽØšÚ©Ù ØªØ±Ø¬ÛØÛ Ø±Ø§ اÙ
ØªØØ§Ù Ú©ÙÛØ¯. ØšØ±Ø§Û ØªØºÛÛØ±Ø ضرؚ٠ؚزÙÛØ¯."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"تÙ
اس Ø§Ø¶Ø·Ø±Ø§Ø±Û Ø§Ù
کاÙÙŸØ°ÛØ± ÙÛØ³Øª"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"تÙ
اس Ø§Ø¶Ø·Ø±Ø§Ø±Û Ø§Ø²Ø·Ø±ÛÙ WiâFi اÙ
کاÙÙŸØ°ÛØ± ÙÛØ³Øª"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÙØŽØ¯Ø§Ø±Ùا"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ؚازارسا٠تÙ
اس"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ØØ§Ùت ٟاسخ تÙ
اس اضطرارÛ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ØØ°Ù"</string>
<string name="inputMethod" msgid="1784759500516314751">"Ø±ÙØŽ ÙØ±ÙدÛ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Ú©ÙØŽÙØ§Û Ù
تÙÛ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ؚرگ؎ت"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"تغÛÛØ± Ø±ÙØŽ ÙØ±ÙدÛ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÙØ¶Ø§Û Ø°Ø®ÛØ±ÙØ³Ø§Ø²Û Ø¯Ø±ØØ§Ù ٟر ؎د٠است"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 88ede78..823a26a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobiiliverkkoon ei saada yhteyttä"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Kokeile vaihtaa ensisijaista verkkoa. Vaihda se napauttamalla."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hätäpuhelut eivät ole käytettävissä"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Hätäpuhelujen soittaminen Wi-Fi-yhteyden kautta ei onnistu."</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ilmoitukset"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Soitonsiirto"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Hätäpuhelujen takaisinsoittotila"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Poista"</string>
<string name="inputMethod" msgid="1784759500516314751">"Syöttötapa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tekstitoiminnot"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Takaisin"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Vaihda syöttötapaa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Tallennustila loppumassa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 12176c8..87af6b0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossible de joindre le réseau cellulaire"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Essayez de changer de réseau préféré. Touchez l\'écran pour changer."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Le service d\'appel d\'urgence n\'est pas accessible"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Impossible d\'effectuer des appels d\'urgence par Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transfert d\'appel"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode de rappel d\'urgence"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Supprimer"</string>
<string name="inputMethod" msgid="1784759500516314751">"Mode de saisie"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Actions sur le texte"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Retour"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Changer de méthode d\'entrée"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Espace de stockage bientôt saturé"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 91b2e34..9037bb7 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossible d\'accéder au réseau mobile"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Essayez de changer le réseau préféré. Appuyez pour le modifier."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Appels d\'urgence non disponibles"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Impossible de passer des appels d\'urgence via le Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transfert d\'appel"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode de rappel d\'urgence"</string>
@@ -261,7 +262,7 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"Rapport de bug"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Fermer la session"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Capture d\'écran"</string>
- <string name="bugreport_title" msgid="8549990811777373050">"Rapport de bug"</string>
+ <string name="bugreport_title" msgid="8549990811777373050">"Signaler un bug"</string>
<string name="bugreport_message" msgid="5212529146119624326">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Rapport interactif"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, de saisir plus d\'informations sur le problème et d\'effectuer des captures d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Supprimer"</string>
<string name="inputMethod" msgid="1784759500516314751">"Mode de saisie"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Actions sur le texte"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Retour"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Changer le mode de saisie"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Espace de stockage bientôt saturé"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 4f1b88e..ff819f1 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Non se puido conectar coa rede de telefonía móbil"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Proba a cambiar a rede preferida. Toca para cambiar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"As chamadas de emerxencia non están dispoñibles"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Non se poden realizar chamadas de emerxencia por wifi"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emerxencia precisan unha rede de telefonía móbil"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de chamadas"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de devolución de chamadas de emerxencia"</string>
@@ -1183,6 +1183,8 @@
<string name="deleteText" msgid="4200807474529938112">"Eliminar"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de introdución de texto"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Accións de texto"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Este campo non admite a escritura manual"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Os campos dos contrasinais non admiten a escritura manual"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Atrás"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Cambia o método de introdución"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Estase esgotando o espazo de almacenamento"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6bd19ea..49a29d2 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"મà«àª¬àªŸàªàª² ચà«àªàªµàª°à«àª ઞà«àª§à« પહà«àªàªà« શàªàªŸàª€à«àª ચથà«"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"પઞàªàªŠàªà«àªšà«àª ચà«àªàªµàª°à«àª બઊલવટચૠપà«àª°àª¯àªŸàªž àªàª°à«. બઊલવટ મટàªà« àªà«
પ àªàª°à«."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àªàªà«àªàªà«àªšà« àªà«àª²àª¿àªàª ઞà«àªµàªŸ àª
ચà«àªªàª²àª¬à«àª§"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"વટàª-ફટઠપરથૠàªàªà«àªàªà«àªšàªŸ àªà«àª² àªàª°à« શàªàªŸàª€àªŸ ચથà«"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àª
લરà«àª"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àªà«àª² ફà«àª°à«àªµàª°à«àª¡àª¿àªàª"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"àªàªà«àªàªà« àªà«àª²àª¬à«
ઠમà«àª¡"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ડિલà«àª àªàª°à«"</string>
<string name="inputMethod" msgid="1784759500516314751">"àªàªšàªªà«àª પઊà«àª§àª€àª¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àªà«àªà«àªžà«àª àªà«àª°àª¿àª¯àªŸàª"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"પટàªàª³"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àªàªšàªªà«àª પઊà«àª§àª€àª¿ ઞà«àªµàª¿àª àªàª°à«"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ઞà«àªà«àª°à«àª ઞà«àª¥àªŸàªš ઞમટપà«àª€ થયà«àª"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 53c3c63..b3a0dce 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à€®à¥à€¬à€Ÿà€à€² à€šà¥à€à€µà€°à¥à€ à€žà¥ à€à€šà¥à€à¥à€ à€šà€¹à¥à€ à€à€¿à€¯à€Ÿ à€à€Ÿ à€žà€à€Ÿ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à€ªà€žà€à€Šà¥à€Šà€Ÿ à€šà¥à€à€µà€°à¥à€ à€¬à€Šà€²à€à€° à€Šà¥à€à¥à€. à€¬à€Šà€²à€šà¥ à€à¥ à€²à€¿à€ à€à¥à€ª à€à€°à¥à€."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à€à€ªà€Ÿà€€à€à€Ÿà€²à¥à€š à€à¥à€² à€à€°à€šà¥ à€à¥ à€žà¥à€µà€¿à€§à€Ÿ à€à€ªà€²à€¬à¥à€§ à€šà€¹à¥à€ à€¹à¥"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"à€µà€Ÿà€-à€«à€Œà€Ÿà€ à€à¥ à€à€Œà€°à€¿à€ à€à€ªà€Ÿà€€à€à€Ÿà€²à¥à€š à€à¥à€² à€šà€¹à¥à€ à€à€¿à€¯à€Ÿ à€à€Ÿ à€žà€à€€à€Ÿ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à€žà¥à€à€šà€Ÿà€à€"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à€à¥à€² à€à¥ à€Šà¥à€žà€°à¥ à€šà€à€¬à€° à€ªà€° à€à¥à€à€šà€Ÿ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à€à€ªà€Ÿà€€à€à€Ÿà€²à¥à€š à€à¥à€²à€¬à¥à€ à€®à¥à€¡"</string>
@@ -256,7 +257,7 @@
<string name="global_action_power_off" msgid="4404936470711393203">"à€¬à€à€Š à€à€°à¥à€"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"à€ªà€Ÿà€µà€°"</string>
<string name="global_action_restart" msgid="4678451019561687074">"à€°à¥à€žà¥à€à€Ÿà€°à¥à€ à€à€°à¥à€"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"à€à€ªà€Ÿà€€à€à€Ÿà€²à¥à€š"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"à€à€ªà€Ÿà€€à€à€Ÿà€²à¥à€š à€žà¥à€µà€¿à€§à€Ÿà€à€ à€Šà¥à€à¥à€"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"à€à€¡à€Œà€¬à€¡à€Œà¥ à€à¥ à€°à€¿à€ªà¥à€°à¥à€"</string>
<string name="global_action_logout" msgid="6093581310002476511">"à€žà€€à¥à€° à€à€€à¥à€® à€à€°à¥à€"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à€®à€¿à€à€Ÿà€à€"</string>
<string name="inputMethod" msgid="1784759500516314751">"à€à€šà€ªà¥à€ à€µà€¿à€§à€¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à€²à¥à€ à€à¥à€°à€¿à€¯à€Ÿà€à€"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"à€µà€Ÿà€ªà€ž à€à€Ÿà€à€"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à€à€šà€ªà¥à€ à€à€Ÿ à€€à€°à¥à€à€Ÿ à€¬à€Šà€²à¥à€"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à€®à¥à€®à¥à€°à¥ à€®à¥à€ à€à€à€¹ à€šà€¹à¥à€ à€¬à€à¥ à€¹à¥"</string>
@@ -1923,7 +1928,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"à€¹à€«à€Œà¥à€€à¥ à€à¥ à€°à€Ÿà€€"</string>
<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>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"à€žà¥à€šà¥ à€à€Ÿ à€žà€®à€¯"</string>
<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>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 69d88f0..2f93a53 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilna mreÅŸa nije dostupna"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pokušajte promijeniti preferiranu mreÅŸu. Dodirnite da biste je promijenili."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hitni pozivi nisu dostupni"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nije moguÄe upuÄivati hitne pozive putem WiâFi-ja"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozorenja"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmjeravanje poziva"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"NaÄin hitnog povratnog poziva"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Izbriši"</string>
<string name="inputMethod" msgid="1784759500516314751">"NaÄin unosa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Radnje s tekstom"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Natrag"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Promjena naÄina unosa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ponestaje prostora za pohranu"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8a3d551..286d55e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"A mobilhálózat nem érhetÅ el"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Próbálja meg módosítani a preferált hálózatot. Koppintson a módosításhoz."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Segélyhívás nem lehetséges"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nem lehet segélyhívást kezdeményezni Wi-Fi-n keresztül"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Értesítések"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Hívásátirányítás"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"SürgÅsségi visszahívás mód"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Törlés"</string>
<string name="inputMethod" msgid="1784759500516314751">"Beviteli mód"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Műveletek szöveggel"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Vissza"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Beviteli módszer váltása"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Kevés a szabad terület"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 84d18c7..5ad4415 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÕÕ°Õ¡Õ»ÕžÕ²ÕŸÕ¥Ö ÕŽÕ«Õ¡Õ¶Õ¡Õ¬ Õ¢Õ»Õ»Õ¡ÕµÕ«Õ¶ ÖÕ¡Õ¶ÖÕ«Õ¶"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÕÕžÖÕ±Õ¥Ö Õ¡ÕµÕ¬ ÖÕ¡Õ¶ÖÕ« ÕŽÕ«Õ¡Õ¶Õ¡Õ¬: ÕÕºÕ¥ÖÕ Õ¶Õ¡ÕÕšÕ¶Õ¿ÖÕ¡Õ® ÖÕ¡Õ¶ÖÕš ÖÕžÕÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÕÕ¿Õ¡Õº Õ¯Õ¡Õ¶Õ¹Õ¥ÖÕš հա՜անելի Õ¹Õ¥Õ¶"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ÕÕ¿Õ¡Õº Õ¯Õ¡Õ¶Õ¹Õ¥ÖÕš հա՜անելի Õ¹Õ¥Õ¶ WiâFi-Õ« ÕŽÕ«Õ»ÕžÖÕžÕŸ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÔŸÕ¡Õ¶ÕžÖÖÕžÖÕŽÕ¶Õ¥Ö"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Ô¶Õ¡Õ¶Õ£Õ« ÕŸÕ¥ÖÕ¡Õ°Õ¡ÕœÖÕ¥Õ¡ÕŸÕžÖÕžÖÕŽ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ÕÕ¿Õ¡Õº Õ°Õ¥Õ¿ÕŠÕ¡Õ¶Õ£Õ« ՌեժիՎ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÕÕ¶Õ»Õ¥Õ¬"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÕÕžÖÕ¿ÖÕ¡Õ£ÖÕŽÕ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õš"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÕÕ¥Ö՜տի Õ£ÕžÖÕ®ÕžÕ²ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÕÕ¥Õ¿"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÕÕžÕÕ¥Õ¬ Õ¶Õ¥ÖÕ¡Õ®ÕŽÕ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õš"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÕÕ«Õ·ÕžÕ²ÕžÖÕ©ÕµÕžÖÕ¶Õš ՜պաՌ՟՞ÖÕŽ Õ§"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index aadf58d..3230b02 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Tidak dapat menjangkau jaringan seluler"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Coba ubah jaringan pilihan. Ketuk untuk mengubah."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Panggilan darurat tidak tersedia"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Tidak dapat melakukan panggilan darurat melalui Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Notifikasi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Penerusan panggilan"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode telepon balik darurat"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Hapus"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metode masukan"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tindakan teks"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Kembali"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Beralih metode input"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ruang penyimpanan hampir habis"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index c56e35f..21f3bfe 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ekki næst samband við farsímakerfi"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prófaðu að velja annað símkerfi. Ýttu til að breyta."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Neyðarsímtöl eru ekki í boði"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ekki er hægt að hringja neyðarsímtöl með Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Tilkynningar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Símtalsflutningur"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Stilling fyrir svarhringingu neyðarsímtala"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Eyða"</string>
<string name="inputMethod" msgid="1784759500516314751">"Innsláttaraðferð"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Textaaðgerðir"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Til baka"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Skipta um innfærsluaðferð"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Geymslurýmið er senn á þrotum"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1c12a97..25bde8fe 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Impossibile raggiungere la rete mobile"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prova a cambiare la rete preferita. Tocca per cambiare."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chiamate di emergenza non disponibili"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Impossibile fare chiamate di emergenza tramite WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Avvisi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Deviazione chiamate"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modalità di richiamata di emergenza"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Elimina"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metodo inserimento"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Azioni testo"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Indietro"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Cambia metodo di immissione"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Spazio di archiviazione in esaurimento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 744c2ed..734f26a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"×× × ××ª× ××ת××ך ×ךשת ×ס×××ך×ת"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"×׀שך ×× ×¡×ת ××©× ×ת ×ת ×ךשת ××××¢×׀ת. ×ש ×××§×ש ××× ××©× ×ת ××ת×."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ש×××ת ××ך×× ×× ×××× ×ת"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"×× × ××ª× ××׊ע ש×××ת ××ך×× ××š× Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"×תך××ת"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"××¢×ךת ש×××ת"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"××Š× \'×תקשך×ת ×××š× ×××ך××\'"</string>
@@ -261,7 +262,7 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"××××× ×¢× ×××"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ס××× ××€×¢××"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"׊×××× ×ס×"</string>
- <string name="bugreport_title" msgid="8549990811777373050">"××× ×¢× ×××"</string>
+ <string name="bugreport_title" msgid="8549990811777373050">"××××× ×¢× ×××"</string>
<string name="bugreport_message" msgid="5212529146119624326">"××€×¢××× ××× ×ª×ס××£ ××××¢ ×¢× ××Š× ×××ש×ך ×× ×××× ×©×× ××× ×ש××× ×××ª× ××××עת ××××××. ××× ×ª×××©× ××× ×§×Š×š ×ך××¢ ׀ת××ת ×××××× ×¢× ×××× ××¢× ×ש×××ת ×××××¢× ××€××¢×. ×ש ×××ת×× ×ס××× ×ת."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"××× ××× ×ך××§××××"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"×××× ××שת×ש ××׀שך×ת ××× ×ך×× ××קך××. ××× ××׀שךת ×× ××¢×§×× ××ך ×תק×××ת ××××, ××××× ×€×š××× × ×ס׀×× ×¢× ×××¢×× ××׊×× ×ת ××ס×. ××× ×¢×©××× ××ש××× ××× ×§××¢×× ×©× ×׊××× ×€××ת ×ש×××ש ×ש×׊×ךת ×××××× ×¢×××× × ×ש×ת ××× ×š×."</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"××××§×"</string>
<string name="inputMethod" msgid="1784759500516314751">"ש××ת ×§××"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"×€×¢×××ת ×קס×"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"××ך×"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"××××€× ×©× ×©××ת ××§××"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"××§×× ×××ס×× ×¢××× ×××××ך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 576e1df9..5cff295 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ã¢ãã€ã« ãããã¯ãŒã¯ã«ã¢ã¯ã»ã¹ã§ããŸãã"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ã¿ããããŠãåªå
ãããã¯ãŒã¯ã倿ŽããŠãã ããã"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ç·æ¥éå ±ã¯å©çšã§ããŸãã"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi ã§ã¯ç·æ¥éå ±ãã§ããŸãã"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"éç¥"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"é»è©±ã®è»¢é"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ç·æ¥éå ±åŸ
æ©ã¢ãŒã"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"åé€"</string>
<string name="inputMethod" msgid="1784759500516314751">"å
¥åæ¹æ³"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ããã¹ãæäœ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"æ»ã"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"å
¥åæ¹æ³ã®åãæ¿ã"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"空ã容éããã"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 43f13a3..dc8e594 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"áááááá£á á¥á¡ááááá áááááášáá ááá ááá á®áá á®áááá"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"áªáááá á£ááá áá¢áá¡á á¥á¡áááá¡ ášááªááá. ášááá®áá ášáá¡ááªáááááá."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ááááá£áááááá ááá á ááá£á¬áááááááá"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ááááá£áááááá ááá ááá WiâFi-á¡ ááášáááááá ááá áááá®áá áªááááááá"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ááá€á áá®ááááááá"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ááá áá¡ ááááááá¡áááá áááá"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ááááá£áááááá áááááá ááááá¡ á ááááá"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"á¬áášáá"</string>
<string name="inputMethod" msgid="1784759500516314751">"ášáá§ááááá¡ áááááá"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"á¥áááááááá á¢áá¥á¡á¢áá"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"á£ááá"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ášáá§ááááá¡ ááááááá¡ ááááá ááá"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ááááá¡á£á€ááá áááááá áá¬á£á ááá"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index e029b70..c91d14f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПбОлÑÐŽÑк желÑге ÒПÑÑÐ»Ñ ÐŒÒ¯ÐŒÐºÑМ еЌеÑ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ТаңЎаÑÐ»Ñ Ð¶ÐµÐ»ÑÐœÑ Ó©Ð·Ð³ÐµÑÑÑп көÑÑÒ£Ñз. ӚзгеÑÑÑ Ò¯ÑÑМ ÑÒ¯ÑÑÑÒ£Ñз."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐеЎел ÒÑзЌеÑке ÒПңÑÑÐ°Ñ ÑÐ°Ð»Ñ ÐŒÒ¯ÐŒÐºÑМ еЌеÑ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fi аÑÒÑÐ»Ñ Ð¶ÐµÐŽÐµÐ» ÒÑзЌеÑке ÒПңÑÑÐ°Ñ ÑÐ°Ð»Ñ ÐŒÒ¯ÐŒÐºÑМ еЌеÑ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÐабÑлЎаÑ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÒПңÑÑаÑÐŽÑ Ð±Ð°ÑÒа МөЌÑÑге баÒÑÑÑаÑ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"КұÒÑл кеÑÑ ÒПңÑÑÐ°Ñ ÑÐ°Ð»Ñ ÑежОЌÑ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐПÑ"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐМгÑÐ·Ñ ÓÐŽÑÑÑ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐÓÑÑМ ÓÑекеÑÑеÑÑ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐÑÑÒа"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐМгÑÐ·Ñ ÓÐŽÑÑÑМ аÑÑÑÑÑÑÑ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐаЎÑа ПÑÑМ азайÑп баÑаЎÑ"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 1dee12e..92c3c5a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"áá·áâá¢á¶á
âáááá¶ááâááááá¶áâááŒáááááâá
ááááá¶ááá"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"áá¶áááááâááááŒáâáá
ááááá¶áâáááâá
ááááááŸá ááŒáá
á»á
âááŸáááážáááá¶ááâááááŒáá"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"áá·áâá¢á¶á
âááááŸâáá¶áâá á
âááááá¶ááâáá¶ááá"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"áá·áâá¢á¶á
ááááŸáá¶áâá á
âááááá¶ááâáá¶á WiâFi áá¶ááá"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"áá¶áááŒááááá¹á"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"áá¶ááááááŒáâáá¶áá á
âááŒáááááâáááá"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"áá»ááá¶áâá á
áááá¡ááâáá·áâááááá¶áá"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"áá»á"</string>
<string name="inputMethod" msgid="1784759500516314751">"áá·áážáááá
áŒá"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ááááááá¶áâá¢ááááá"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ááááááá"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ááááŒááá·áážáá¶áááááâáááá
áŒá"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"á¢ááâááá áâáááá»á"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1574a84..d93d9b8 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ಮà³à²¬à³à²²à³ ಚà³à²à³à²µà²°à³à²à³ ಀಲà³à²ªà²²à³ ಞಟಧà³à²¯à²µà²¿à²²à³à²²"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à²à²Šà³à²¯à²€à³à²à³à²³à²¿à²žà²¿à²Š ಚà³à²à³à²µà²°à³à²à³à²à²³à²šà³à²šà³ ಬಊಲಟಯಿಞಲೠಪà³à²°à²¯à²€à³à²šà²¿à²žà²¿. ಬಊಲಟಯಿಞಲೠà²à³à²¯à²Ÿà²ªà³ ಮಟಡಿ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ಀà³à²°à³à²€à³ à²à²°à³ ಮಟಡà³à²µà²¿à²à³ ಲà²à³à²¯à²µà²¿à²²à³à²²"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ವà³-ಫೠಮà³à²²à² ಀà³à²°à³à²€à³ à²à²°à³à²à²³à²šà³à²šà³ ಮಟಡಲೠಞಟಧà³à²¯à²µà²¿à²²à³à²²"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à²à²à³à²à²°à²¿à²à³à²à²³à³"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à²à²°à³ ಫಟರà³à²µà²°à³à²¡à³ ಮಟಡà³à²µà²¿à²à³"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ಀà³à²°à³à²€à³ à²à²Ÿà²²à³à²¬à³à²¯à²Ÿà²à³ ಮà³à²¡à³"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à²
ಳಿಞಿ"</string>
<string name="inputMethod" msgid="1784759500516314751">"à²à²šà³à²ªà³à²à³ ವಿಧಟಚ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ಪಠà³à²¯à²Š à²à³à²°à²®à²à²³à³"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ಹಿà²à²Šà²à³à²à³"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à²à²šà³à²ªà³à²à³ ವಿಧಟಚವಚà³à²šà³ ಬಊಲಿಞಿ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ಞà²à²à³à²°à²¹à²£à³ ಞà³à²¥à²³à²µà³ ಀà³à²à²¬à²¿à²Šà³"</string>
@@ -1900,7 +1905,7 @@
<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_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{à²à²à²Šà³ ಚಿಮಿಷಊವರà³à²à³ ({formattedTime} ವರà³à²à³)}one{# ಚಿಮಿಷà²à²³à²µà²°à³à²à³ ({formattedTime} ವರà³à²à³)}other{# ಚಿಮಿಷà²à²³à²µà²°à³à²à³ ({formattedTime} ವರà³à²à³)}}"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 75d4a2d..fd15f81 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"몚ë°ìŒ ë€ížìí¬ì ì°ê²°í ì ììµëë€."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Ʞ볞 ë€ížìí¬ë¥Œ ë³ê²œíŽ ë³Žìžì. ííì¬ ë³ê²œí ì ììµëë€."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"êžŽêž ì í륌 ì¬ì©í ì ììµëë€."</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFië¡ë êžŽêž ì í륌 걞 ì ììµëë€."</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ì늌"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ì°©ì ì í"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"êžŽêž ìœë°± 몚ë"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ìì "</string>
<string name="inputMethod" msgid="1784759500516314751">"ì
ë ¥ ë°©ë²"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"í
ì€íž ìì
"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ë€ë¡"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ì
ë ¥ ë°©ë² ì í"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ì ì¥ ê³µê°ìŽ ë¶ì¡±íš"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 118a542..13c94d1 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПбОлЎОк ÑаÑЌакка ÑÑÑаÑпай жаÑаÑ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ТаМЎалгаМ ÑаÑЌакÑÑ Ó©Ð·Ð³Ó©ÑÑүп көÑүңүз. ӚзгөÑÑÒ¯Ò¯ Ò¯ÑүМ ÑапÑаңÑз."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"КаÑÑлÑÑ ÑалÑÑ Ð¶ÐµÑкОлОкÑОз"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fi аÑкÑлÑÑ ÑаÑÑлÑÑ ÑалÑÑÐ»Ð°Ñ ÐžÑÑеÑОлгеМ жПк"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"КаÑÑлÑÑ Ð±ÐžÐ»ÐŽÐžÑүүлөÑ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ЧалÑÑÐœÑ Ð±Ð°Ñка МПЌеÑге багÑÑÑПП"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"КаÑÑлÑÑ ÐºÐ°Ð¹Ñа ÑалÑÑ ÑежОЌО"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÓšÑÒ¯ÑÒ¯Ò¯"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐОÑгОзүү ÑкЌаÑÑ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ТекÑÑ Ð±ÐŸÑМÑа ОÑÑеÑ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐÑÑка"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐОÑгОзүү ÑкЌаÑÑМ өзгөÑÑÒ¯Ò¯"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"СакÑагÑÑÑа ПÑÑМ калбай баÑаÑаÑ"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7057324..4b78b08 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"àºà»à»àºªàº²àº¡àº²àºàºàºŽàºàºà»à»à»àºàº·àºàºà»àº²àºàº¡àº·àºàº·à»àºà»"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à»àº«à»àº¥àºàºàºà»àºœàºà»àºàº·àºàºà»àº²àºàºàºµà»àºà»àºàºàºàº²àº. à»àºàº°à»àºàº·à»àºàºà»àºœàº."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àºà»à»àºªàº²àº¡àº²àºà»àºà»àºàº²àºà»àºàºªàºžàºà»àºªàºµàºà»àºà»"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"àºà»à»àºªàº²àº¡àº²àºà»àºàºªàºžàºà»àºªàºµàºàºà»àº²àº WiâFi à»àºà»"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àºàº²àºà»àºàº·àºàº"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àºàº²àºà»àºàºàºªàº²àº"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à»à»àºà»àºàºàº±àºàºªàºžàºà»àºªàºµàº"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ລຶàº"</string>
<string name="inputMethod" msgid="1784759500516314751">"ຮູàºà»àºàºàºàº²àºàºà»àºàºàºà»à»àº¡àº¹àº"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àºàº²àºà»àº®àº±àºàº§àºœàºàºàºàºàºà»à»àºàº§àº²àº¡"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àºàº±àºàºàº·àº"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ສະຫຌັàºàº§àºŽàºàºµàºàº²àºàºà»àºàºàºà»à»àº¡àº¹àº"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àºàº·à»àºàºàºµà»àºàº±àºà»àºàº±àºàºà»à»àº¡àº¹àºàºàº³àº¥àº±àºàºàº°à»àºàº±àº¡"</string>
@@ -1900,7 +1905,7 @@
<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_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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e3405d6..46d69c7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nepavyko pasiekti mobiliojo ryšio tinklo"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Pabandykite pakeisti pageidaujamÄ
tinklÄ
. Palieskite, kad pakeistumÄte."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"SkambuÄių pagalbos numeriu paslauga nepasiekiama"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Negalima skambinti pagalbos numeriu naudojant „WiâFi“"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ä®spÄjimai"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"SkambuÄio peradresavimas"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Atskambinimo pagalbos numeriu reÅŸimas"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"Ištrinti"</string>
<string name="inputMethod" msgid="1784759500516314751">"Įvesties būdas"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Teksto veiksmai"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Atgal"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Perjungti įvesties metodÄ
"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"MaÅŸÄja laisvos saugyklos vietos"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d297856..7ddeb4c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nevar sasniegt mobilo tīklu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"MÄÄ£iniet nomainÄ«t vÄlamo tÄ«klu. Pieskarieties, lai to mainÄ«tu."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Nav pieejami ÄrkÄrtas izsaukumi"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Izmantojot Wi-Fi, nevar veikt ÄrkÄrtas izsaukumus"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"BrÄ«dinÄjumi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Zvanu pÄradresÄcija"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ÄrkÄrtas atzvana reÅŸÄ«ms"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"DzÄst"</string>
<string name="inputMethod" msgid="1784759500516314751">"Ievades metode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Teksta darbības"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"AtpakaČ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"PÄrslÄgt ievades metodi"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Paliek maz brīvas vietas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a15aa6e5..4bef670 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПбОлМаÑа ÐŒÑежа е МеЎПÑÑапМа"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"СЌеМеÑе Ñа пÑеÑпПÑОÑаМаÑа ÐŒÑежа. ÐПпÑеÑе за пÑПЌеМа."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐÑМОÑе пПвОÑО Ñе МеЎПÑÑапМО"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ðе ЌПже Ўа ПÑÑваÑÑÐ²Ð°Ð°Ñ ÐžÑМО пПвОÑО пÑÐµÐºÑ Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÐÑеЎÑпÑеЎÑваÑа"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐÑПÑлеЎÑваÑе пПвОк"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"РежОЌ Ма ОÑеМ пПвÑаÑеМ пПвОк"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐзбÑОÑО"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐеÑПЎ Ма вМеÑ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐеÑÑÑва ÑП ÑекÑÑ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐÑеÑÑлеÑе гП ЌеÑÐŸÐŽÐŸÑ Ð·Ð° вМеÑÑваÑе"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐапаÑОÑеÑÐŸÑ Ðµ ÑеÑОÑО пПлМ"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 8043293..70aeadd 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"àŽ®àµàެàµàµœ àŽšàµàޱàµàޱàµàŽµàµŒàŽàµàŽàŽ¿àŽ²àµàŽàµàŽàµ àŽàŽ£àŽàµàޱàµàŽ±àµ àŽàµàޝàµàŽ¯àŽŸàŽšàŽŸàŽµàµàŽšàµàŽšàŽ¿àŽ²àµà޲"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽ€àµàŽ€ àŽšàµàޱàµàޱàµàŽµàµŒàŽàµàŽàµ àŽ®àŽŸàŽ±àµàޱàµàŽšàµàŽšàŽ€àµ àŽªàŽ°àµàŽàµàŽ·àŽ¿àŽàµàŽàµàŽ. àŽ®àŽŸàŽ±àµàŽ±àŽŸàµ» àŽàŽŸàŽªàµàŽªàµ àŽàµàޝàµàޝàµàŽ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àŽàŽ®àµŒàŽàµ»àŽžàŽ¿ àŽàµàŽ³àŽ¿àŽàŽàµ àŽ²àŽàµàŽ¯àŽ®àŽ²àµà޲"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"àŽµàµàŽ«àµ àŽµàŽŽàŽ¿ àŽàŽ®àµŒàŽàµ»àŽžàŽ¿ àŽàµà޳àµàŽàµŸ àŽàµàޝàµàŽ¯àŽŸàŽšàŽŸàŽàŽ¿àŽ²àµà޲"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àŽ
àŽ²àµàµŒàŽàµàŽàµàŽàµŸ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àŽàµàµŸ àŽ«àµàµŒà޵àµàŽ¡àŽ¿àŽàŽàµ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"àŽ
àŽàŽ¿àŽ¯àŽšàµàŽ€àŽ° àŽàµàµŸàŽ¬àŽŸàŽàµàŽàµ àŽ®àµàŽ¡àµ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"àŽà޲àµàŽ²àŽŸàŽ€àŽŸàŽàµàŽàµàŽ"</string>
<string name="inputMethod" msgid="1784759500516314751">"àŽàµàŽªàµàŽªàµàŽàµàޝàµàŽ¯àµœ àŽ°àµàŽ€àŽ¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àŽàµàŽàµàŽžàµàޱàµàŽ±àµ àŽªàµàŽ°àŽµàµŒàŽ€àµàŽ€àŽšàŽàµàŽàµŸ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àŽ®àŽàŽàµàŽàµàŽ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àŽàµ»àŽªàµàŽàµàŽàµ àŽ°àµàŽ€àŽ¿ àŽ®àŽŸàŽ±àµàŽ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àŽžàŽàŽàŽ°àŽ£àŽ¯àŽ¿àŽàŽ àŽàŽŽàŽ¿àŽàµàŽàµ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 615369c..adb1f87 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПбайл ÑүлжÑÑМЎ Ñ
ПлбПгЎПÑ
бПлПЌжгүй байМа"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"СПМгПÑПМ ÑүлжÑÑг Ó©Ó©ÑÑлөÑ
Ó©Ó©Ñ ÐŸÑПлЎПМП ÑÑ. ÓšÓ©ÑÑлөÑ
ОйМ ÑÑлЎ ÑПвÑОМП ÑÑ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ЯаÑалÑай ÐŽÑÑЎлага Ñ
ОйÑ
бПлПЌжгүй"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi-Ñ ÑаÑалÑай ÐŽÑÑЎлага Ñ
ОйÑ
бПлПЌжгүй байМа"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"СаМÑÑлга"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐÑÑЎлага ÑОлжүүлÑÑ
"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ЯаÑалÑай ÐŽÑÑЎлага Ñ
ОйÑ
гПÑОЌ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"УÑÑгаÑ
"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐÑÑÑлаÑ
аÑга"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ТекÑÑ Ò¯Ð¹Ð»ÐŽÑл"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐÑÑаÑ
"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐÑÑÑлаÑ
аÑгÑг ÑÑлгÑÑ
"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"СаМгОйМ Ñ
ÑЌжÑÑ ÐŽÑÑагЎаж байМа"</string>
@@ -1971,7 +1976,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Ð¥ÑМалÑÑай Ñ
ÑÑÑглÑÐ³Ñ ÐœÑÐŒÑÑ
"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ð¥Ñл МÑÐŒÑÑ
"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ÐÒ¯Ñ ÐœÑÑгОйМ ÑПÑ
ОÑгПП"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"УлÑÑМ Ñ
ÑлОйг бОÑÐœÑ Ò¯Ò¯"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Ð¥ÑлМОй МÑÑОйг бОÑÐœÑ Ò¯Ò¯"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"СаМал бПлгПÑПМ"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"СаМал бПлгПÑПМ"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"СаМал бПлгПÑПМ Ñ
Ñл"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d96bb41..393f95e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à€®à¥à€¬à€Ÿà€à€² à€šà¥à€à€µà€°à¥à€ à€à€ªà€²à€¬à¥à€§ à€šà€Ÿà€¹à¥"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à€ªà¥à€°à€Ÿà€§à€Ÿà€šà¥à€¯ à€Šà€¿à€²à¥à€²à¥ à€šà¥à€à€µà€°à¥à€ à€¬à€Šà€²à€£à¥à€¯à€Ÿà€à€Ÿ à€ªà¥à€°à€¯à€€à¥à€š à€à€°à€Ÿ. à€¬à€Šà€²à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à¥
à€ª à€à€°à€Ÿ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à€à€£à¥à€¬à€Ÿà€£à¥ à€à¥à€²à€¿à€à€ à€
à€šà¥à€ªà€²à€¬à¥à€§"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"à€µà€Ÿà€¯-à€«à€Ÿà€¯ à€µà€°à¥à€š à€à€£à¥à€¬à€Ÿà€£à¥ à€à¥à€² à€à€°à¥ à€¶à€à€€ à€šà€Ÿà€¹à¥"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à€
à€²à€°à¥à€"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à€à¥à€² à€«à¥à€°à€µà€°à¥à€¡à€¿à€à€"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à€à€®à€°à¥à€à€šà¥à€žà¥ à€à¥à€²à€¬à¥
à€ à€®à¥à€¡"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à€¹à€à€µà€Ÿ"</string>
<string name="inputMethod" msgid="1784759500516314751">"à€à€šà€ªà¥à€ à€ªà€Šà¥à€§à€€"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à€®à€à€à¥à€° à€à¥à€°à€¿à€¯à€Ÿ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"à€®à€Ÿà€à¥ à€à€Ÿ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à€à€šà€ªà¥à€ à€ªà€Šà¥à€§à€€ à€žà¥à€µà€¿à€ à€à€°à€Ÿ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à€žà€à€à€¯à€š à€žà¥à€¥à€Ÿà€š à€žà€à€ªà€€ à€à€¹à¥"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index d794ae0..9274c51 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Tidak dapat mencapai rangkaian mudah alih"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Cuba tukar rangkaian pilihan. Ketik untuk menukar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Panggilan kecemasan tidak tersedia"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Tidak boleh membuat panggilan kecemasan melalui Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Makluman"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Pemajuan panggilan"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mod paggil balik kecemasan"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Padam"</string>
<string name="inputMethod" msgid="1784759500516314751">"Kaedah input"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tindakan teks"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Kembali"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Tukar kaedah masukan"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ruang storan semakin berkurangan"</string>
@@ -1900,7 +1905,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu penggunaan data dikurangkan, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Untuk mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Sebagai contoh, imej tidak dipaparkan sehingga anda mengetik pada imej itu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Selama satu minit (hingga{formattedTime})}other{Selama # minit (hingga {formattedTime})}}"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 825d3a6..9e3ec9e 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ááá¯ááá¯ááºážááœááºááẠááá¯ááºážáááá«"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"áŠážá
á¬ážáá±ážááœááºáááºááá¯á· ááŒá±á¬ááºážááŒáá·áºáá«á ááŒá±á¬ááºážááẠááá¯á·áá«á"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"á¡áá±ážáá±á«áºáá±á«áºááá¯ááŸá¯ ááááá¯ááºáá«"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi ááŒáá·áº á¡áá±ážáá±á«áºáá±á«áºááá¯ááŸá¯áá»á¬áž ááŒá¯áá¯ááºááááá«"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ááááá±ážáá»ááºáá»á¬áž"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"á¡áááºáá±á«áºááá¯ááŸá¯á¡á¬áž áááºááá·áºááá¯á·ááŒááºáž"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"á¡áá±ážáá±á«áº ááŒááºáááºáá±á«áºááá¯ááá¯ááºáá±á¬áá¯ááº"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"áá»ááºáááº"</string>
<string name="inputMethod" msgid="1784759500516314751">"ááá·áºááœááºážáááºáááºážáááºáž"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"á
á¬ááᯠáá¯ááºáá±á¬ááºáá»ááº"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"áá±á¬ááºááá¯á·"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"áááºááœááºááŒá±á¬ááºážáááº"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ááááºážáááºáá±á¬ áá±áᬠáááºážáá±áá«áááº"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3c07ba7..551b4d5 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Får ikke kontakt med mobilnettverket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Prøv å endre foretrukket nettverk. Trykk for å endre."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Nødanrop er utilgjengelig"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Kan ikke ringe nødnumre via WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Varsler"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Viderekobling"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modusen nødsamtale-tilbakeringing"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Slett"</string>
<string name="inputMethod" msgid="1784759500516314751">"Inndatametode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Teksthandlinger"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Tilbake"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Bytt inndatametode"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Lite ledig lagringsplass"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 8d0ac72..24426eb 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à€®à¥à€¬à€Ÿà€à€² à€šà¥à€à€µà€°à¥à€à€®à€Ÿà€¥à€¿ à€ªà€¹à¥à€à€ à€°à€Ÿà€à¥à€š à€žà€à€¿à€à€š"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à€°à¥à€à€Ÿà€à€à€à¥ à€šà¥à€à€µà€°à¥à€ à€ªà€°à€¿à€µà€°à¥à€€à€š à€à€°à¥ à€¹à¥à€°à¥à€šà¥à€¹à¥à€žà¥à¥€ à€ªà€°à€¿à€µà€°à¥à€€à€š à€à€°à¥à€š à€à¥à€¯à€Ÿà€ª à€à€°à¥à€šà¥à€¹à¥à€žà¥à¥€"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à€à€ªà€€à¥à€à€Ÿà€²à¥à€š à€à€² à€žà¥à€µà€Ÿ à€
à€šà¥à€ªà€²à€¬à¥à€§ à€"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi à€®à€Ÿà€°à¥à€«à€€ à€à€ªà€€à¥à€à€Ÿà€²à¥à€š à€à€² à€à€°à¥à€š à€žà€à€¿à€à€Šà¥à€š"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à€
à€²à€°à¥à€à€¹à€°à¥"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à€à€² à€«à€°à¥à€µà€Ÿà€°à¥à€¡ à€à€°à¥à€šà¥ à€žà¥à€µà€Ÿ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à€à€ªà€€à¥à€à€Ÿà€²à¥à€š à€à€²à€¬à¥à€¯à€Ÿà€ à€®à¥à€¡"</string>
@@ -349,9 +350,9 @@
<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_title_canPerformGestures" msgid="9106545062106728987">"à€à€žà€Ÿà€°à€Ÿà€¹à€°à¥ à€žà€®à¥à€¬à€šà¥à€§à¥ à€à€Ÿà€°à¥à€¯ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
- <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"à€à¥à€¯à€Ÿà€ª, à€žà¥à€µà€Ÿà€à€ª à€à€°à¥à€š, à€¥à€¿à€à¥à€š à€° à€
à€šà¥à€¯ à€à€žà€Ÿà€°à€Ÿà€¹à€°à¥ à€žà€®à¥à€¬à€šà¥à€§à¥ à€à€Ÿà€°à¥à€¯ à€à€°à¥à€š à€žà€à¥à€"</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"à€«à€¿à€à€à€°à€ªà¥à€°à€¿à€šà¥à€à€à€Ÿ à€à€žà€Ÿà€°à€Ÿà€¹à€°à¥"</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>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"à€¯à€žà€²à¥ à€¯à€šà¥à€€à¥à€°à€à¥ à€«à€¿à€à€à€°à€ªà¥à€°à€¿à€šà¥à€à€žà€®à¥à€¬à€šà¥à€§à¥ à€žà¥à€šà¥à€žà€°à€®à€Ÿ à€à€°à€¿à€à€à€Ÿ à€à€žà€Ÿà€°à€Ÿà€¹à€°à¥à€²à€Ÿà€ à€à€¿à€à¥à€š à€žà€à¥à€à¥€"</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"à€žà¥à€à¥à€°à€¿à€šà€žà€ à€²à€¿à€šà¥à€¹à¥à€žà¥"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"à€¡à€¿à€žà¥à€ªà¥à€²à¥à€à¥ à€žà¥à€à¥à€°à€¿à€šà€žà€ à€²à€¿à€š à€žà€à€¿à€šà¥à€à¥€"</string>
@@ -373,9 +374,9 @@
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"à€«à¥à€š à€à€²à€¹à€°à¥à€à¥ à€à€µà€Ÿà€« à€Šà€¿à€šà¥à€¹à¥à€žà¥"</string>
<string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"à€à€ªà€²à€Ÿà€ à€à€à€®à€š à€«à¥à€š à€à€²à€à¥ à€à€µà€Ÿà€« à€Šà€¿à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€"</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"à€à¥à€à¥à€žà¥à€ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ (SMS) à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"à€à€ªà€²à€Ÿà€ SMS à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€° à€ªà¥à€°à€à¥à€°à€¿à€¯à€Ÿ à€à€°à¥à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€¯à€žà€à¥ à€®à€€à€²à€¬ à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€ªà€à€°à€£à€®à€Ÿ à€ªà€ à€Ÿà€à€à€à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€€à€ªà€Ÿà€à€à€²à€Ÿà€ à€šà€Šà¥à€à€Ÿà€à€šà¥ à€®à¥à€šà€¿à€à€° à€à€°à¥à€š à€µà€Ÿ à€®à¥à€à€Ÿà€à€š à€žà€à¥à€Šà€à¥€"</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"à€à€ªà€²à€Ÿà€ SMS à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€° à€ªà¥à€°à€à¥à€°à€¿à€¯à€Ÿ à€à€°à¥à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€¯à€žà€à¥ à€®à€€à€²à€¬ à€à€ªà€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€ªà€à€°à€£à€®à€Ÿ à€ªà€ à€Ÿà€à€à€à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€€à€ªà€Ÿà€à€à€²à€Ÿà€ à€šà€Šà¥à€à€Ÿà€à€šà¥ à€®à¥à€šà€¿à€à€° à€à€°à¥à€š à€µà€Ÿ à€®à¥à€à€Ÿà€à€š à€žà€à¥à€Šà€à¥€"</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"à€à¥à€à¥à€žà¥à€ à€®à¥à€¯à€Ÿà€žà¥à€ (MMS) à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"à€à€ªà€²à€Ÿà€ MMS à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€° à€ªà¥à€°à€à¥à€¯à€Ÿ à€à€°à¥à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€¯à€žà€à¥ à€®à€€à€²à€¬ à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€ªà€à€°à€£à€®à€Ÿ à€ªà€ à€Ÿà€à€à€à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€€à€ªà€Ÿà€à€à€²à€Ÿà€ à€šà€Šà¥à€à€Ÿà€à€šà¥ à€®à¥à€šà€¿à€à€° à€à€°à¥à€š à€µà€Ÿ à€®à¥à€à€Ÿà€à€š à€žà€à¥à€Šà€à¥€"</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"à€à€ªà€²à€Ÿà€ MMS à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€° à€ªà¥à€°à€à¥à€¯à€Ÿ à€à€°à¥à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€¯à€žà€à¥ à€®à€€à€²à€¬ à€à€ªà€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€ªà€à€°à€£à€®à€Ÿ à€ªà€ à€Ÿà€à€à€à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€€à€ªà€Ÿà€à€à€²à€Ÿà€ à€šà€Šà¥à€à€Ÿà€à€šà¥ à€®à¥à€šà€¿à€à€° à€à€°à¥à€š à€µà€Ÿ à€®à¥à€à€Ÿà€à€š à€žà€à¥à€Šà€à¥€"</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"à€®à¥à€¬à€Ÿà€à€² à€ªà¥à€°à€žà€Ÿà€°à€£à€žà€®à¥à€¬à€šà¥à€§à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€«à€°à¥à€µà€Ÿà€°à¥à€¡ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"à€®à¥à€¬à€Ÿà€à€² à€ªà¥à€°à€žà€Ÿà€°à€£à€žà€®à¥à€¬à€šà¥à€§à¥ à€®à¥à€¯à€Ÿà€žà¥à€à€¹à€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€¹à¥à€šà€Ÿà€žà€Ÿà€¥à¥ à€€à€¿à€šà¥à€¹à€°à¥à€²à€Ÿà€ à€«à€°à¥à€µà€Ÿà€°à¥à€¡ à€à€°à¥à€šà€à€Ÿ à€²à€Ÿà€à€¿ à€¯à€žà€²à¥ à€à€ªà€²à€Ÿà€ à€®à¥à€¬à€Ÿà€à€² à€ªà¥à€°à€žà€Ÿà€°à€£ à€®à¥à€¡à¥à€¯à¥à€²à€®à€Ÿ à€à¥à€¡à€¿à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€€à€ªà€Ÿà€à€à€²à€Ÿà€ à€à€€à€¿à€ªà€¯ à€žà¥à€¥à€Ÿà€šà€®à€Ÿ à€à€ªà€€à¥à€à€Ÿà€²à¥à€š à€
à€µà€žà¥à€¥à€Ÿà€à€Ÿ à€¬à€Ÿà€°à¥à€®à€Ÿ à€à€Ÿà€šà€à€Ÿà€°à¥ à€Šà€¿à€šà€à€Ÿ à€²à€Ÿà€à€¿ à€®à¥à€¬à€Ÿà€à€² à€ªà¥à€°à€žà€Ÿà€°à€£à€žà€®à¥à€¬à€šà¥à€§à¥ à€
à€²à€°à¥à€à€¹à€°à¥ à€ªà€ à€Ÿà€à€šà¥à€à¥€ à€¹à€Ÿà€šà€¿à€à€Ÿà€°à€ à€à€ªà€¹à€°à¥à€²à¥ à€à€ªà€€à¥à€à€Ÿà€²à¥à€š à€®à¥à€¬à€Ÿà€à€² à€ªà¥à€°à€žà€Ÿà€°à€£ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€¹à¥à€à€Šà€Ÿ à€€à€ªà€Ÿà€à€à€à¥ à€¯à€šà¥à€€à¥à€°à€²à€Ÿà€ à€à€Ÿà€°à¥à€¯ à€žà€®à¥à€ªà€Ÿà€Šà€š à€à€°à¥à€šà¥ à€µà€Ÿ à€žà€à¥à€à€Ÿà€²à€¿à€€ à€¹à¥à€šà¥ à€à¥à€°à€®à€®à€Ÿ à€¹à€žà¥à€€à€à¥à€·à¥à€ª à€à€°à¥à€š à€žà€à¥à€à€šà¥à¥€"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"à€à€Ÿà€°à¥ à€°à€¹à¥à€à€Ÿ à€à€²à€¹à€°à¥ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€š à€à€°à¥à€š"</string>
@@ -399,7 +400,7 @@
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"à€ªà¥à€°à¥à€«à€Ÿà€à€² à€° à€¯à€šà¥à€€à¥à€° à€®à€Ÿà€²à€¿à€à€¹à€°à¥à€à¥ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€š à€à€°à€Ÿà€à€šà¥à€¹à¥à€žà¥"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"à€à€ªà€¹à€°à¥à€²à€Ÿà€ à€ªà¥à€°à¥à€«à€Ÿà€à€² à€° à€¯à€šà¥à€€à¥à€° à€®à€Ÿà€²à€¿à€à€¹à€°à¥ à€žà¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€¹à¥à€žà¥à¥€"</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"à€à€²à€¿à€°à€¹à¥à€à€Ÿ à€à€ªà€¹à€°à¥à€²à€Ÿà€ à€ªà¥à€šà€à€à¥à€°à€® à€à€°à€Ÿà€à€šà¥à€¹à¥à€žà¥"</string>
- <string name="permdesc_reorderTasks" msgid="8796089937352344183">"à€à€Ÿà€®à€¹à€°à¥à€²à€Ÿà€ à€
à€à¥à€°à€à€Ÿà€ à€° à€ªà¥à€·à¥à€ à€à¥à€®à€¿à€®à€Ÿ à€žà€Ÿà€°à¥à€š à€à€ªà€²à€Ÿà€ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€¯à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€šà€ªà¥à€ à€¬à€¿à€šà€Ÿ à€šà¥ à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
+ <string name="permdesc_reorderTasks" msgid="8796089937352344183">"à€à€Ÿà€®à€¹à€°à¥à€²à€Ÿà€ à€
à€à¥à€°à€à€Ÿà€ à€° à€ªà¥à€·à¥à€ à€à¥à€®à€¿à€®à€Ÿ à€žà€Ÿà€°à¥à€š à€à€ªà€²à€Ÿà€ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€ à€à€ªà€²à¥ à€¯à¥ à€€à€ªà€Ÿà€à€à€à¥ à€à€šà€ªà¥à€ à€¬à€¿à€šà€Ÿ à€šà¥ à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"à€à€Ÿà€° à€®à¥à€¡ à€žà€à¥à€·à€® à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="permdesc_enableCarMode" msgid="56419168820473508">"à€à€Ÿà€° à€®à¥à€¡à€²à€Ÿà€ à€žà€à¥à€·à€® à€ªà€Ÿà€°à¥à€š à€à€ªà€²à€Ÿà€ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€à¥€"</string>
<string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"à€à€ªà€¹à€°à¥ à€¬à€šà¥à€Š à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
@@ -513,9 +514,9 @@
<string name="permlab_backgroundCamera" msgid="7549917926079731681">"à€¬à¥à€¯à€Ÿà€à€à¥à€°à€Ÿà€à€šà¥à€¡à€®à€Ÿ à€«à¥à€à¥ à€à€¿à€à¥à€šà¥à€¹à¥à€žà¥ à€€à€¥à€Ÿ à€à€¿à€¡à€¿à€¯à¥ à€°à¥à€à€°à¥à€¡ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="permdesc_backgroundCamera" msgid="1615291686191138250">"à€¯à¥ à€à€ªà€²à¥ à€à¥à€šà€žà¥à€à¥ à€¬à¥à€²à€Ÿ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿà€à¥ à€ªà¥à€°à€¯à¥à€ à€à€°à¥ à€«à¥à€à¥ à€à€¿à€à¥à€š à€° à€à€¿à€¡à€¿à€¯à¥ à€°à¥à€à€°à¥à€¡ à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"à€à€ª à€µà€Ÿ à€žà¥à€µà€Ÿà€²à€Ÿà€ à€«à¥à€à¥ à€° à€à€¿à€¡à€¿à€¯à¥ à€à€¿à€à¥à€š à€ªà¥à€°à€£à€Ÿà€²à¥à€à€Ÿ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿà€¹à€°à¥à€®à€Ÿà€¥à€¿ à€ªà€¹à¥à€à€ à€°à€Ÿà€à¥à€š à€Šà€¿à€šà¥à€¹à¥à€žà¥"</string>
- <string name="permdesc_systemCamera" msgid="5938360914419175986">"à€ªà¥à€°à€£à€Ÿà€²à¥à€à¥ à€¯à€ž à€µà€¿à€¶à¥à€·à€Ÿà€§à€¿à€à€Ÿà€° à€ªà¥à€°à€Ÿà€ªà¥à€€ à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€à¥à€šà€žà¥à€à¥ à€¬à¥à€²à€Ÿ à€ªà¥à€°à€£à€Ÿà€²à¥à€à¥ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥ à€«à¥à€à¥ à€à€¿à€à¥à€š à€° à€à€¿à€¡à€¿à€¯à¥ à€°à¥à€à€°à¥à€¡ à€à€°à¥à€š à€žà€à¥à€à¥€ à€à€ªà€žà€à€ à€ªà€šà€¿ android.permission.CAMERA à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€¹à¥à€šà¥ à€ªà€°à¥à€"</string>
+ <string name="permdesc_systemCamera" msgid="5938360914419175986">"à€ªà¥à€°à€£à€Ÿà€²à¥à€à¥ à€¯à€ž à€µà€¿à€¶à¥à€·à€Ÿà€§à€¿à€à€Ÿà€° à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€ªà€²à¥ à€à¥à€šà€žà¥à€à¥ à€¬à¥à€²à€Ÿ à€ªà¥à€°à€£à€Ÿà€²à¥à€à¥ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥ à€«à¥à€à¥ à€à€¿à€à¥à€š à€° à€à€¿à€¡à€¿à€¯à¥ à€°à¥à€à€°à¥à€¡ à€à€°à¥à€š à€žà€à¥à€à¥€ à€à€ªà€žà€à€ à€ªà€šà€¿ android.permission.CAMERA à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€¹à¥à€šà¥ à€ªà€°à¥à€"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"à€à¥à€šà¥ à€à€ª à€µà€Ÿ à€žà¥à€µà€Ÿà€²à€Ÿà€ à€à¥à€²à€¿à€à€Šà¥ à€µà€Ÿ à€¬à€šà¥à€Š à€à€°à€¿à€à€Šà¥ à€à€°à¥à€à€Ÿ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€¯à€šà¥à€€à¥à€°à€¹à€°à¥à€à€Ÿ à€¬à€Ÿà€°à¥à€®à€Ÿ à€à€²à€¬à¥à€¯à€Ÿà€ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€¹à¥à€žà¥à¥€"</string>
- <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"à€à¥à€šà¥ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€¯à€šà¥à€€à¥à€° à€à¥à€²à€¿à€à€Šà€Ÿ (à€à¥à€š à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€à¥à€²à¥à€à¥ à€à€šà¥à€šà¥ à€¬à€Ÿà€°à¥à€®à€Ÿ) à€µà€Ÿ à€¬à€šà¥à€Š à€à€°à€¿à€à€Šà€Ÿ à€¯à¥ à€à€ªà€²à¥ à€à€²à€¬à¥à€¯à€Ÿà€ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
+ <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"à€à¥à€šà¥ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€¯à€šà¥à€€à¥à€° à€à¥à€²à€¿à€à€Šà€Ÿ (à€à¥à€š à€à€ªà€²à¥ à€à¥à€²à¥à€à¥ à€à€šà¥à€šà¥ à€¬à€Ÿà€°à¥à€®à€Ÿ) à€µà€Ÿ à€¬à€šà¥à€Š à€à€°à€¿à€à€Šà€Ÿ à€¯à¥ à€à€ªà€²à¥ à€à€²à€¬à¥à€¯à€Ÿà€ à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
<string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"à€à¥à€šà¥ à€à€ª à€µà€Ÿ à€žà¥à€µà€Ÿà€²à€Ÿà€ à€¹à¥à€¡à€²à¥à€ž à€žà€¿à€žà¥à€à€®à€à¥ à€ªà¥à€°à€¯à¥à€à€à€°à¥à€€à€Ÿà€à€Ÿ à€°à¥à€ªà€®à€Ÿ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€à€à¥à€žà¥à€ž à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€¹à¥à€žà¥à¥€"</string>
<string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"à€¯à¥ à€à€ªà€²à¥ à€¹à¥à€¡à€²à¥à€ž à€žà€¿à€žà¥à€à€®à€à¥ à€ªà¥à€°à€¯à¥à€à€à€°à¥à€€à€Ÿà€à€Ÿ à€°à¥à€ªà€®à€Ÿ à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€à€à¥à€žà¥à€ž à€à€°à¥à€š à€žà€à¥à€à¥€"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"à€à€®à¥à€ªà€š à€šà€¿à€¯à€šà¥à€€à¥à€°à€£ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à€®à¥à€à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="inputMethod" msgid="1784759500516314751">"à€šà€¿à€µà¥à€¶ à€µà€¿à€§à€¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à€ªà€Ÿà€ à€à€Ÿà€°à¥à€¯à€¹à€°à¥"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"à€ªà€à€Ÿà€¡à€¿"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à€à€šà€ªà¥à€ à€µà€¿à€§à€¿ à€¬à€Šà€²à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à€à€£à¥à€¡à€Ÿà€°à€£ à€ à€Ÿà€à€ à€žà€à€¿à€à€Šà¥ à€"</string>
@@ -2095,7 +2100,7 @@
<string name="popup_window_default_title" msgid="6907717596694826919">"à€ªà€ªà€
à€ª à€µà€¿à€šà¥à€¡à¥"</string>
<string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"à€¯à€Ÿ à€€ à€à€ªà€à¥ à€žà€à€žà¥à€à€°à€£ à€žà¥à€€à€°à€¹à¥à€°à€Ÿà€ž à€à€°à€¿à€¯à¥ à€µà€Ÿ à€¯à¥ à€¯à€ž à€žà€°à¥à€à€à€à€žà€à€ à€®à€¿à€²à¥à€Šà¥ à€à¥à€š"</string>
- <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€¬à¥à€¯à€Ÿà€à€
à€ª à€€à€¥à€Ÿ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€šà€Ÿà€²à€Ÿà€ à€žà€®à€°à¥à€¥à€š à€šà€à€°à¥à€šà¥ à€¹à¥à€à€Šà€Ÿ à€žà€°à¥à€à€à€ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à€°à¥à€š à€žà€à€¿à€à€š"</string>
+ <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"à€à€ªà€²à¥ à€¬à¥à€¯à€Ÿà€à€
à€ª à€€à€¥à€Ÿ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€šà€Ÿà€²à€Ÿà€ à€žà€®à€°à¥à€¥à€š à€šà€à€°à¥à€šà¥ à€¹à¥à€à€Šà€Ÿ à€žà€°à¥à€à€à€ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à€°à¥à€š à€žà€à€¿à€à€š"</string>
<string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"à€à€ªà€®à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à€¿à€šà¥ à€¹à€žà¥à€€à€Ÿà€à¥à€·à€° à€šà€®à€¿à€²à¥à€šà¥ à€¹à¥à€à€Šà€Ÿ à€žà€°à¥à€à€à€ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à€°à¥à€š à€žà€à€¿à€à€š"</string>
<string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"à€žà€°à¥à€à€à€ à€ªà¥à€šà€°à¥à€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à€°à¥à€š à€žà€à€¿à€à€š"</string>
<string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"à€žà€°à¥à€à€à€ à€
à€žà€à¥à€·à€® à€ªà€Ÿà€°à€¿à€à€à¥ à€"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bc2fc69..fbf93be 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Kan mobiel netwerk niet bereiken"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Probeer een ander voorkeursnetwerk. Tik om te wijzigen."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Noodoproepen niet beschikbaar"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Er kunnen geen noodoproepen worden gemaakt via wifi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Meldingen"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Gesprek doorschakelen"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modus voor noodoproepen"</string>
@@ -255,7 +256,7 @@
<string name="global_action_lock" msgid="6949357274257655383">"Schermvergrendeling"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"Uitzetten"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Aan/uit"</string>
- <string name="global_action_restart" msgid="4678451019561687074">"Opnieuw opstarten"</string>
+ <string name="global_action_restart" msgid="4678451019561687074">"Herstarten"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Noodgeval"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Bugrapport"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Sessie beëindigen"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Verwijderen"</string>
<string name="inputMethod" msgid="1784759500516314751">"Invoermethode"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tekstacties"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Terug"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Invoermethode wijzigen"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Opslagruimte is bijna vol"</string>
@@ -1922,7 +1927,7 @@
<string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Downtime"</string>
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Doordeweekse avond"</string>
<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_events_name" msgid="2280682960128512257">"Afspraak"</string>
<string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Slapen"</string>
<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>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 1b68a74..2b12d82 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ମàବଟà¬à¬²à ଚàà¬àà±à¬°àଠମିଳàଚଟହିà¬"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ଚିଠପଞଚàଊର ଚàà¬àà±à¬°àà¬à¬à ଯିବଟପଟà¬à¬ à¬àଷàà¬à¬Ÿ à¬à¬°à¬šà଀àी ବଊଳଟà¬à¬¬à¬Ÿ ପଟà¬à¬ à¬à¬Ÿà¬ªà à¬à¬°à¬šà଀àी"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à¬à¬°àରàà¬à¬Ÿà¬³àଚ à¬à¬²à à¬à¬ªà¬²à¬¬àଧ ଚଟହିà¬"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"à±à¬Ÿà¬-ଫଟଠଞଟହଟଯààରà à¬à¬°àରàà¬à¬Ÿà¬³àଚ à¬à¬²à à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬ªà¬Ÿà¬°à¬¿à¬¬ ଚଟହିà¬"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à¬à¬²à¬°àà¬"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à¬à¬²à ଫରà±à¬Ÿà¬°àଡିà¬"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à¬à¬°àରàà¬à¬Ÿà¬³àଚ à¬à¬²à¬¬ààଟà¬à ମàଡà"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ଡିଲିଠà¬à¬°à¬šà଀à"</string>
<string name="inputMethod" msgid="1784759500516314751">"à¬à¬šà¬ªàà¬à ପଊàଧ଀ି"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à¬àà¬àଞà¬à à¬à¬Ÿà¬°àଯàà"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ପà¬à¬à ଫàରଚà଀à"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à¬à¬šà¬ªàଠପଊàଧ଀ି ଞàà±à¬¿à¬ à¬à¬°à¬šà଀à"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ଷàà¬àରàà¬à ଞàପàଞà ଶàଷ ହàବଟରà ଲଟà¬à¬¿à¬à¬¿"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 439190b..8e22644 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"àš®à©àš¬àšŸàšàš² àššà©à©±àšàšµàš°àš àš€à©±àš àšªàš¹à©à©°àš àššàš¹à©àš àšà©àš€à© àšàšŸ àšžàšàšŠà©"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"àš€àš°àšà©àš¹à© àššà©à©±àšàšµàš°àš àššà©à©° àš¬àšŠàš² àšà© àšŠà©àšà©à¥€ àš¬àšŠàš²àš£ àš²àš àšà©àšª àšàš°à©à¥€"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"àšžà©°àšàšàšàšŸàš²à©àšš àšàšŸàš²àš¿à©°àš àšàšªàš²àš¬àš§ àššàš¹à©àš"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"àšµàšŸàš-àš«àšŸàš àš°àšŸàš¹à©àš àšžà©°àšàšàšàšŸàš²à©àšš àšàšŸàš²àšŸàš àššàš¹à©àš àšàš° àšžàšàšŠà©"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àš
àš²àš°àš"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àšàšŸàš² àš«àšŸàš°àšµàš°àš¡àš¿à©°àš"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"àšžà©°àšàšàšàšŸàš²à©àšš àšàšŸàš²àš¬à©àš àš®à©àš¡"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"àš®àš¿àšàšŸàš"</string>
<string name="inputMethod" msgid="1784759500516314751">"àšàššàšªà©à©±àš àšµàš¿àš§à©"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àšà©àšàšžàš àšàš¿àš°àš¿àšàšµàšŸàš"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àšªàš¿à©±àšà©"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àšàššàšªà©à©±àš àšµàš¿àš§à© àššà©à©° àšžàšµàš¿à©±àš àšàš°à©"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àšžàšà©àš°à©àš àšŠà© àšàšà©àš¹àšŸ àšàš€àš® àš¹à© àš°àš¹à© àš¹à©"</string>
@@ -1900,7 +1905,7 @@
<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_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{àšà©±àš àš®àš¿à©°àš àš²àš ({formattedTime} àš€à©±àš)}one{# àš®àš¿à©°àš àš²àš ({formattedTime} àš€à©±àš)}other{# àš®àš¿à©°àšàšŸàš àš²àš ({formattedTime} àš€à©±àš)}}"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8f742eb..bb7ccaa 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -86,7 +86,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Brak zasiÄgu sieci komórkowej"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Spróbuj zmieniÄ preferowanÄ
sieÄ. Kliknij, by zmieniÄ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"PoÅÄ
czenia alarmowe sÄ
niedostÄpne"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nie moÅŒna nawiÄ
zywaÄ poÅÄ
czeÅ alarmowych przez WiâFi"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"PoÅÄ
czenia alarmowe wymagajÄ
sieci komórkowej"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerty"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Przekierowanie poÅÄ
czeÅ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Tryb alarmowego poÅÄ
czenia zwrotnego"</string>
@@ -1185,6 +1185,8 @@
<string name="deleteText" msgid="4200807474529938112">"UsuÅ"</string>
<string name="inputMethod" msgid="1784759500516314751">"Sposób wprowadzania tekstu"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"DziaÅania na tekÅcie"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"To pole nie obsÅuguje pisma odrÄcznego"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Pola haseÅ nie obsÅugujÄ
pisma odrÄcznego"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Wstecz"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"PrzeÅÄ
cz metodÄ wprowadzania"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"KoÅczy siÄ miejsce"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 786e582..1da3965 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Não é possível fazer chamadas de emergência por WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Encaminhamento de chamada"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de retorno de chamada de emergência"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Excluir"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Ações de texto"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Voltar"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Mudar o método de entrada"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Pouco espaço de armazenamento"</string>
@@ -1972,7 +1977,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Digite o nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4418acd..70862a8 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -85,7 +85,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não é possível estabelecer ligação à rede móvel."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Experimente alterar a rede preferida. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Não é possível efetuar chamadas de emergência através de WiâFi."</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"As chamadas de emergência requerem uma rede móvel"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Reencaminhamento de chamadas"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de chamada de retorno de emergência"</string>
@@ -1184,6 +1184,8 @@
<string name="deleteText" msgid="4200807474529938112">"Eliminar"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Acções de texto"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"A escrita manual não é suportada neste campo"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"A escrita manual não é suportada nos campos de palavras-passe"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Voltar"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Alternar o método de introdução"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Está quase sem espaço de armazenamento"</string>
@@ -1901,7 +1903,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais, determinadas funcionalidades e algumas ligações de rede."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais, determinadas funcionalidades e algumas ligações de rede."</string>
- <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas apps enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
+ <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas apps enviem ou recebam dados em segundo plano. Qualquer app que esteja a usar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante um minuto (até à[s] {formattedTime})}many{Durante # minutos (até à[s] {formattedTime})}other{Durante # minutos (até à[s] {formattedTime})}}"</string>
@@ -1972,7 +1974,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar utilizador supervisionado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Introduza o idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugeridas"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 786e582..1da3965 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Chamadas de emergência indisponíveis"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Não é possível fazer chamadas de emergência por WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Encaminhamento de chamada"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de retorno de chamada de emergência"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Excluir"</string>
<string name="inputMethod" msgid="1784759500516314751">"Método de entrada"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Ações de texto"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Voltar"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Mudar o método de entrada"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Pouco espaço de armazenamento"</string>
@@ -1972,7 +1977,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"Digite o nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index bc2eae1..2ca2082 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nu se poate stabili conexiunea la reÈeaua mobilÄ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÎncearcÄ sÄ schimbi reÈeaua preferatÄ. Atinge pentru a schimba."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Apelurile de urgenÈÄ nu sunt disponibile"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nu poÈi face apeluri de urgenÈÄ prin Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerte"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"RedirecÈionarea apelurilor"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mod de apelare inversÄ de urgenÈÄ"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"Èterge"</string>
<string name="inputMethod" msgid="1784759500516314751">"MetodÄ de intrare"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"AcÈiuni pentru text"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Înapoi"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"SchimbÄ metoda de introducere"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"SpaÈiul de stocare aproape ocupat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a476bca..5875450 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПбОлÑÐœÐ°Ñ ÑеÑÑ ÐœÐµÐŽÐŸÑÑÑпМа"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÐажЌОÑе, ÑÑÐŸÐ±Ñ Ð²ÑбÑаÑÑ ÐŽÑÑгÑÑ ÑеÑÑ."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐкÑÑÑеММÑе вÑÐ·ÐŸÐ²Ñ ÐœÐµÐŽÐŸÑÑÑпМÑ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ÐкÑÑÑеММÑе вÑÐ·ÐŸÐ²Ñ Ð¿ÐŸ WiâFi МеЎПÑÑÑпМÑ."</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ÐпПвеÑеМОÑ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐеÑеаЎÑеÑаÑÐžÑ Ð²ÑзПвПв"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"РежОЌ ÑкÑÑÑеММÑÑ
ПбÑаÑМÑÑ
вÑзПвПв"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"УЎалОÑÑ"</string>
<string name="inputMethod" msgid="1784759500516314751">"СпПÑПб ввПЎа"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐпеÑаÑОО Ñ ÑекÑÑПЌ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"СЌеМОÑÑ ÑпПÑПб ввПЎа"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐеЎПÑÑаÑПÑМП паЌÑÑО"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 8bbf199..58ef919 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à¶¢à¶à¶à¶ž à¶¢à·à¶œà¶º à·à·à¶ à·
à¶à· à·à·à¶º à¶±à·à·à·à¶à·à¶º"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à¶à·à¶žà¶à· à¶¢à·à¶œà¶º à·à·à¶±à·à· à¶à·à¶»à·à¶žà¶§ à¶à¶à·à·à·à· à¶à¶»à¶±à·à¶±. à·à·à¶±à·à· à¶à·à¶»à·à¶žà¶§ à¶à¶§à·à¶§à· à¶à¶»à¶±à·à¶±."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à·à¶¯à·à·à· à¶à¶žà¶à·à¶žà· ගබ෠à¶à¶ à¶±à·à·à·à¶à·à¶º"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fi à·à¶»à·à· à·à¶¯à·à·à· à¶à¶žà¶à·à¶žà· ගබ෠à¶à¶ à¶±à·à·à·à¶à·à¶º"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à¶à¶à·à·à¶žà·"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à¶à¶žà¶à·à¶ž à¶Žà·à¶»à¶à·à¶ºà·à¶žà· à¶à·à¶»à·à¶ž"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à·à¶¯à·à·à· à¶
à·à·à·à¶®à· à¶Žà·à· à¶à¶žà¶à·à¶žà· à¶Žà·à¶»à¶à·à¶»à¶º"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à¶žà¶à¶±à·à¶±"</string>
<string name="inputMethod" msgid="1784759500516314751">"à¶à¶¯à·à¶± à¶à·à¶»à¶žà¶º"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à¶Žà·à·
à¶à·à¶»à·à¶ºà·à·à¶±à·"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"à¶à¶Žà·à·"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à¶à¶¯à·à¶± à¶à·à¶»à¶žà¶º à¶žà·à¶»à· à¶à·à¶»à·à¶ž"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à¶à¶ යනය à¶à¶© à¶Žà·à¶»à¶žà·à¶«à¶º à¶
à¶©à· à·à· à¶à¶"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 928371d..915c5eb 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nepodarilo sa pripojiť k mobilnej sieti"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Skúste zmeniÅ¥ predvolenú sieÅ¥. Zmeníte ju klepnutím."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"TiesÅové volania nie sú k dispozícii"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nedajú sa uskutoÄniÅ¥ tiesÅové volania cez Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Upozornenia"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Presmerovanie hovorov"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ReÅŸim tiesÅového spätného volania"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"OdstrániÅ¥"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metóda vstupu"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Operácie s textom"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"SpäÅ¥"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"PrepnúÅ¥ metódu vstupu"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Nedostatok ukladacieho priestoru"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e4abb44..4c13c00 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobilnega omreÅŸja ni mogoÄe doseÄi"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Poskusite spremeniti prednostno omreÅŸje. Dotaknite se, Äe ga ÅŸelite spremeniti."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Klicanje v sili ni na voljo"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Klicev v sili ni mogoÄe opravljati prek omreÅŸja Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Opozorila"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Preusmerjanje klicev"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"NaÄin za povratni klic v sili"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"Izbriši"</string>
<string name="inputMethod" msgid="1784759500516314751">"NaÄin vnosa"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Besedilna dejanja"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Nazaj"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Preklop naÄina vnosa"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Prostor za shranjevanje bo pošel"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 29d6fe5..c344c7d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Rrjeti celular është i paarritshëm"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Provo të ndryshosh rrjetin e preferuar. Trokit për ta ndryshuar."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Telefonatat e urgjencës nuk ofrohen"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nuk mund të kryhen telefonata urgjence me WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Sinjalizimet"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Transferimi i telefonatave"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modaliteti i \"Kthimit të telefonatës së urgjencës\""</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Fshi"</string>
<string name="inputMethod" msgid="1784759500516314751">"Metoda e hyrjes"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Veprimet e tekstit"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Pas"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Ndërro metodën e hyrjes"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Hapësira ruajtëse po mbaron"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index db9c849..0c5557f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -85,7 +85,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ÐПвезОваÑе Ñа ЌПбОлМПЌ ÐŒÑежПЌ МОÑе ÑÑпелП"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ÐÑПбаÑÑе Ўа пÑПЌеМОÑе жеÑÐµÐœÑ ÐŒÑежÑ. ÐПЎОÑМОÑе Ўа бОÑÑе пÑПЌеМОлО."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ХОÑМО пПзОвО МОÑÑ ÐŽÐŸÑÑÑпМО"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ðе ЌПжеÑе Ўа ÑпÑÑÑÑеÑе Ñ
ОÑМе пПзОве пÑекП WiâFi-Ñа"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"УпПзПÑеÑа"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐÑеÑÑЌеÑаваÑе пПзОва"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"РежОЌ за Ñ
ОÑаМ пПвÑаÑМО пПзОв"</string>
@@ -1184,6 +1185,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐзбÑОÑО"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐеÑПЎ ÑМПÑа"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"РаЎÑе Ñ Ð²ÐµÐ·Ðž Ñа ÑекÑÑПЌ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐÑПЌеМОÑе ЌеÑПЎ ÑМПÑа"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐеЌПÑОÑÑкО пÑПÑÑÐŸÑ Ñе Ма ОзЌакÑ"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 657eb2c..4abc6f6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Det går inte att nå mobilnätverket"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Testa att byta föredraget nätverk. Tryck om du vill ändra."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Det går inte att ringa nödsamtal"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Det går inte att ringa nödsamtal via WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Aviseringar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Vidarekoppla samtal"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Läget Återuppringning vid nödsamtal"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Ta bort"</string>
<string name="inputMethod" msgid="1784759500516314751">"Indatametod"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Textåtgärder"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Tillbaka"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Byt inmatningsmetod"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Lagringsutrymmet börjar ta slut"</string>
@@ -1271,7 +1276,7 @@
<string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Mobilen uppdateras …"</string>
<string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"Surfplattan uppdateras …"</string>
<string name="android_upgrading_title" product="device" msgid="6774767702998149762">"Enheten uppdateras …"</string>
- <string name="android_start_title" product="default" msgid="4036708252778757652">"Mobilen startar …"</string>
+ <string name="android_start_title" product="default" msgid="4036708252778757652">"Telefonen startar …"</string>
<string name="android_start_title" product="automotive" msgid="7917984412828168079">"Android startar …"</string>
<string name="android_start_title" product="tablet" msgid="4429767260263190344">"Surfplattan startar …"</string>
<string name="android_start_title" product="device" msgid="6967413819673299309">"Enheten startar …"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 83be3fc..95a9b73 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Imeshindwa kufikia mtandao wa simu"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Jaribu kutumia mtandao unaopendelea. Gusa ili ubadilishe."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Huduma ya kupiga simu za dharura haipatikani"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Huwezi kupiga simu ya dharura kupitia WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Arifa"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Kupeleka simu kwenye namba nyingine"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Hali ya kupiga simu za dharura"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Futa"</string>
<string name="inputMethod" msgid="1784759500516314751">"Mbinu ya uingizaji"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Vitendo vya maandishi"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Rudi nyuma"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Badilisha mbinu ya kuingiza data"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Nafasi ya kuhifadhi inakaribia kujaa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 362a18d..85640a6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à®®à¯à®ªà¯à®²à¯ சà¯à®à¯à®µà¯à®°à¯à®à¯ à®à®¿à®à¯à®à¯à®à®µà®¿à®²à¯à®²à¯"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"விரà¯à®ªà¯à®ª சà¯à®à¯à®µà¯à®°à¯à®à¯à®à¯ மடறà¯à®±à®µà¯à®®à¯. மடறà¯à®±, ஀à®à¯à®à®µà¯à®®à¯."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à®
வà®à®° à®
எà¯à®ªà¯à®ªà¯à®à¯ à®à¯à®¯à¯à®¯ à®®à¯à®à®¿à®¯à®Ÿà®€à¯"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"வà¯à®à®ªà¯ à®®à¯à®²à®®à¯ à®
வà®à®° à®
எà¯à®ªà¯à®ªà¯à®à®³à¯à®à¯ à®à¯à®¯à¯à®¯ à®®à¯à®à®¿à®¯à®Ÿà®€à¯"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"விஎிபà¯à®ªà¯à®à¯à®à®²à¯à®à®³à¯"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à®
எà¯à®ªà¯à®ªà¯ ஀ிரà¯à®ªà¯à®ªà®¿à®µà®¿à®à¯à®€à®²à¯"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à®
வà®à®°à®à®Ÿà®²à®€à¯ ஀ிரà¯à®®à¯à®ª à®
எà¯à®à¯à®à¯à®®à¯ பயனà¯à®®à¯à®±à¯"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"சà¯à®à¯à®à¯"</string>
<string name="inputMethod" msgid="1784759500516314751">"à®à®³à¯à®³à¯à®à¯à®à¯ à®®à¯à®±à¯"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à®à®°à¯ சà®à®µà®à®¿à®à¯à®à¯à®à®³à¯"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"பினà¯à®à¯à®²à¯à®²à¯à®®à¯"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à®à®³à¯à®³à¯à®à¯à®à¯ à®®à¯à®±à¯à®¯à¯ மடறà¯à®±à¯à®®à¯"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à®à¯à®®à®¿à®ªà¯à®ªà®¿à®à®®à¯ à®à¯à®±à¯à®à®¿à®±à®€à¯"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 738b410..c0c7806e0 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à°®à±à°¬à±à°²à± à°šà±à°à±à°µà°°à±à°à± à°
à°à°Šà±à°¬à°Ÿà°à±à°²à± à°²à±à°Šà±"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"à°ªà±à°°à°Ÿà°§à°Ÿà°šà±à°¯ à°šà±à°à±à°µà°°à±à°à±à°šà± మటరà±à°à±à°à±à°µà°¡à°Ÿà°šà°¿à°à°¿ à°ªà±à°°à°¯à°€à±à°šà°¿à°à°à°à°¡à°¿. మటరà±à°à°¡à°Ÿà°šà°¿à°à°¿ à°šà±à°à±à°à°à°¡à°¿."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à°
à°€à±à°¯à°µà°žà°° à°à°Ÿà°²à°¿à°à°à± à°
à°à°Šà±à°¬à°Ÿà°à±à°²à± à°²à±à°Šà±"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiఀౠà°
à°€à±à°¯à°µà°žà°° à°à°Ÿà°²à±à°žà± à°à±à°¯à°²à±à°°à±"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"à°
లరà±à°à±à°²à±"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"à°à°Ÿà°²à± à°«à°Ÿà°°à±à°µà°Ÿà°°à±à°¡à°¿à°à°à±"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à°
à°€à±à°¯à°µà°žà°° à°à°Ÿà°²à±à°¬à±à°¯à°Ÿà°à± à°®à±à°¡à±"</string>
@@ -278,7 +279,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"à°žà±à°à±à°à°¿à°à°à±à°²à±"</string>
<string name="global_action_assist" msgid="2517047220311505805">"ఞహటయà°"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"వటయిఞౠà°
à°žà°¿à°žà±à°à±à°à°à±"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"లటà°à± à°à±à°¯à°¿"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"లటà°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"à°à±à°€à±à°€ à°šà±à°à°¿à°«à°¿à°à±à°·à°šà±"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"à°à±à°€à°¿à° à°à±à°¬à±à°°à±à°¡à±"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"à°€à±à°²à°à°¿à°à°à°à°¡à°¿"</string>
<string name="inputMethod" msgid="1784759500516314751">"à°à°šà±à°ªà±à°à± పఊà±à°§à°€à°¿"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"à°µà°à°šà°Ÿà°šà°¿à°à°¿ à°žà°à°¬à°à°§à°¿à°à°à°¿à°š à°à°°à±à°¯à°²à±"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"à°µà±à°šà±à°à°à±"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"à°à°šà±à°ªà±à°à± విధటచటచà±à°šà°¿ మటరà±à°à°à°¡à°¿"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"à°žà±à°à±à°°à±à°à± à°à°Ÿà°³à± à°
యిపà±à°€à±à°à°Šà°¿"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 7856369..c3a3c6d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"à¹àžàž·à¹àžàž¡àžà¹àžà¹àžàž£àž·àžàžà¹àž²àž¢àž¡àž·àžàžàž·àžà¹àž¡à¹à¹àžà¹"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"àž¥àžàžà¹àžàž¥àžµà¹àž¢àžà¹àžàž£àž·àžàžà¹àž²àž¢àžàžµà¹àžà¹àžàžàžàž²àž£ à¹àžàž°à¹àžàž·à¹àžà¹àžàž¥àžµà¹àž¢àž"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"à¹àžàž£àž«àž²àž«àž¡àž²àž¢à¹àž¥àžàžàžžàžà¹àžàžŽàžà¹àž¡à¹à¹àžà¹"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"à¹àžàž£àž«àž²àž«àž¡àž²àž¢à¹àž¥àžàžàžžàžà¹àžàžŽàžàžà¹àž²àž WiâFi à¹àž¡à¹à¹àžà¹"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"àžàž²àž£à¹àžà¹àžà¹àžàž·àžàž"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"àžàž²àž£à¹àžàžàžªàž²àž¢"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"à¹àž«àž¡àžàžàžŽàžàžà¹àžàžàž¥àž±àžàžàžžàžà¹àžàžŽàž"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"àž¥àž"</string>
<string name="inputMethod" msgid="1784759500516314751">"àž§àžŽàžàžµàžà¹àžàžàžà¹àžàž¡àž¹àž¥"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"àžàž²àž£àžàž³àžàž²àžàžàžàžàžà¹àžàžàž§àž²àž¡"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"àžàž¥àž±àž"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"àžªàž¥àž±àžàž§àžŽàžàžµàžàž²àž£àžà¹àžàžàžà¹àžàž¡àž¹àž¥"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"àžàž·à¹àžàžàžµà¹àžàž±àžà¹àžà¹àžà¹àž«àž¥àž·àžàžà¹àžàž¢"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f95c6b2..717b9e0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Hindi makakonekta sa mobile network"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Subukang baguhin ang gustong network. I-tap para baguhin."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Hindi available ang pang-emergency na pagtawag"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Hindi makapagsagawa ng mga emergency na tawag sa pamamagitan ng WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Mga Alerto"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Pagpasa ng tawag"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Emergency callback mode"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"I-delete"</string>
<string name="inputMethod" msgid="1784759500516314751">"Pamamaraan ng pag-input"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Pagkilos ng teksto"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Bumalik"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Magpalit ng pamamaraan ng pag-input"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Nauubusan na ang puwang ng storage"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9638983..03a6577 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil aÄa eriÅilemiyor"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tercih edilen aÄı deÄiÅtirmeyi deneyin. DeÄiÅtirmek için dokunun."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Acil durum çaÄrısı kullanılamaz"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Kablosuz aÄ üzerinden acil durum çaÄrıları yapılamaz"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Uyarılar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÇaÄrı yönlendirme"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Acil geri arama modu"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Sil"</string>
<string name="inputMethod" msgid="1784759500516314751">"GiriÅ yöntemi"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Metin eylemleri"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Geri"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"GiriÅ yöntemini deÄiÅtir"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Depolama alanı bitiyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 640e7fc..a8c86d4 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -86,7 +86,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ðе вЎаÑÑÑÑÑ Ð¿ÑÐŽ’ÑЎМаÑОÑÑ ÐŽÐŸ ЌПбÑлÑÐœÐŸÑ ÐŒÐµÑежÑ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"СпÑПбÑйÑе зЌÑМОÑО вОбÑÐ°ÐœÑ ÐŒÐµÑежÑ. ТПÑкМÑÑÑÑÑ, ÑПб Ñе зÑПбОÑО."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ÐкÑÑÑÐµÐœÑ Ð²ÐžÐºÐ»ÐžÐºÐž МеЎПÑÑÑпМÑ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ðе ЌПжМа зЎÑйÑМÑваÑО екÑÑÑÐµÐœÑ Ð²ÐžÐºÐ»ÐžÐºÐž ÑеÑез Wi-Fi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"СпПвÑÑеММÑ"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"ÐеÑеаЎÑеÑаÑÑÑ Ð²ÐžÐºÐ»ÐžÐºÑ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"РежОЌ екÑÑÑеМПгП звПÑПÑМПгП вОклОкÑ"</string>
@@ -1185,6 +1186,10 @@
<string name="deleteText" msgid="4200807474529938112">"ÐОЎалОÑО"</string>
<string name="inputMethod" msgid="1784759500516314751">"ÐеÑПЎ ввеЎеММÑ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"ÐÑÑ Ð· ÑекÑÑПЌ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÐазаЎ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"ÐÐŒÑМОÑО ЌеÑПЎ ввеЎеММÑ"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ÐакÑМÑÑÑÑÑÑÑ Ð¿Ð°ÐŒ’ÑÑÑ"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index f8f7dde..05184fc 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ù
ÙØšØ§ØŠÙ ÙÛÙ¹ ÙØ±Ú© تک Ø±Ø³Ø§ØŠÛ ÙÛÛÚº Û٠سکتÛ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ØªØ±Ø¬ÛØÛ ÙÛÙ¹ ÙØ±Ú© تؚدÛ٠کر Ú©Û Ø¯ÛÚ©ÚŸÛÚºÛ ØªØšØ¯Û٠کرÙÛ Ú©Û ÙÛÛ ØªÚŸÙŸØªÚŸÙŸØ§ØŠÛÚºÛ"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"اÛÙ
Ø±Ø¬ÙØ³Û کاÙÙÚ¯ Ø¯Ø³ØªÛØ§Øš ÙÛÛÚº ÛÛ"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi Ú©Û Ø°Ø±ÛØ¹Û اÛÙ
Ø±Ø¬ÙØ³Û Ú©Ø§ÙØ² ÙÛÛÚº کر سکتÛ"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ø§ÙØ±Ù¹Ø³"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Ú©Ø§Ù ÙØ§Ø±ÙرÚÙÚ¯"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"اÛÙ
Ø±Ø¬ÙØ³Û کا٠ؚÛÚ© ÙØ¶Ø¹"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"ØØ°Ù کرÛÚº"</string>
<string name="inputMethod" msgid="1784759500516314751">"Ø§ÙØ¯Ø±Ø§Ø¬ کا طرÛÙÛ"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Ù
ØªÙ Ú©Û Ú©Ø§Ø±Ø±ÙØ§ØŠÛاں"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"ÙŸÛÚÚŸÛ"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Ø§ÙØ¯Ø±Ø§Ø¬ کا طرÛÙÛ Ø³ÙØŠÚ کرÛÚº"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Ø§Ø³Ù¹ÙØ±Ûج Ú©Û Ø¬Ú¯Û Ø®ØªÙ
Û٠رÛÛ ÛÛ"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 5c73637..dc31f00 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Mobil tarmoqqa ulanib bo‘lmadi"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Tarmoq turini almashtiring. Almashtirish uchun bosing."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Favqulodda chaqiruv ishlamayapti"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"WiâFi orqali favqulodda chaqiruvlar amalga oshirilmadi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Ogohlantirishlar"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Chaqiruvlarni uzatish"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Favqulodda qaytarib chaqirish rejimi"</string>
@@ -278,7 +279,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"Sozlamalar"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Yordam"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ovozli yordam"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"Bloklash"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"Qulflash"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Yangi bildirishnoma"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tashqi klaviatura"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"O‘chirish"</string>
<string name="inputMethod" msgid="1784759500516314751">"Kiritish uslubi"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Matn yozish"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Orqaga"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Matn kiritish usulini almashtirish"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Xotirada joy yetarli emas"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 2b39b8a..d82487e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Không thá» kết ná»i vá»i mạng di Äá»ng"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Hãy thá» thay Äá»i mạng ưu tiên. Nhấn Äá» thay Äá»i."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Không có dá»ch vụ gá»i khẩn cấp"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Không thá» thá»±c hiá»n cuá»c gá»i khẩn cấp qua WiâFi"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Thông báo"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Chuyá»n tiếp cuá»c gá»i"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Chế Äá» gá»i lại khẩn cấp"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"Xóa"</string>
<string name="inputMethod" msgid="1784759500516314751">"Phương thức nháºp"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Tác vụ vÄn bản"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Quay lại"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Chuyá»n phương thức nháºp"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Sắp hết dung lượng lưu trữ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 036e91f..d1f7d32 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"æ æ³è¿æ¥å°ç§»åšçœç»"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"请å°è¯æŽæ¹éŠéçœç»ãç¹æå³å¯æŽæ¹ã"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"æ æ³äœ¿çšçާæ¥åŒææå¡"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"æ æ³éè¿ WLAN æšæçŽ§æ¥åŒæçµè¯"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"æé"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"æ¥çµèœ¬æ¥"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"玧æ¥åæšæš¡åŒ"</string>
@@ -260,7 +261,7 @@
<string name="global_action_bug_report" msgid="5127867163044170003">"é误æ¥å"</string>
<string name="global_action_logout" msgid="6093581310002476511">"ç»æäŒè¯"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"å±å¹æªåŸ"</string>
- <string name="bugreport_title" msgid="8549990811777373050">"Bug æ¥å"</string>
+ <string name="bugreport_title" msgid="8549990811777373050">"é误æ¥å"</string>
<string name="bugreport_message" msgid="5212529146119624326">"è¿äŒæ¶éæå
³åœå讟å€ç¶æçä¿¡æ¯ïŒå¹¶ä»¥çµåé®ä»¶ç圢åŒè¿è¡åéãä»åŒå§çæé误æ¥åå°åå€å¥œåééèŠäžç¹æ¶éŽïŒè¯·èå¿çåŸ
ã"</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"äºåšåŒæ¥å"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"åšå€§å€æ°æ
åµäžïŒå»ºè®®æšäœ¿çšæ€é项ïŒä»¥äŸ¿è¿œèžªæ¥åççæè¿åºŠïŒèŸå
¥äžçžåºé®é¢çžå
³çæŽå€è¯Šç»ä¿¡æ¯ïŒä»¥åæªåå±å¹æªåŸãç³»ç»å¯èœäŒçç¥æäžäºäžåžžçšçåºæ®µïŒä»è猩ççææ¥åçæ¶éŽã"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"å é€"</string>
<string name="inputMethod" msgid="1784759500516314751">"èŸå
¥æ³"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"æåæäœ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"è¿å"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"忢èŸå
¥æ³"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"ååšç©ºéŽäžè¶³"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 460067f..c914fd1 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ç¡æ³é£ç·è³æµå網絡"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"è«åè©Šè®æŽå奜ç網絡ãèŒæå³å¯è®æŽã"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ç¡æ³æ¥æç·æ¥é»è©±"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ç¡æ³ç¶ WiâFi æ¥æç·æ¥é»è©±"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"éç¥"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"äŸé»èœé§"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ç·æ¥åæ¥æš¡åŒ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"åªé€"</string>
<string name="inputMethod" msgid="1784759500516314751">"茞å
¥æ³"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"æåæäœ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"è¿å"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"åæèŒžå
¥æ¹æ³"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"å²å空éå³å°çšç¡"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1a6b1d5..8ac4531 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -84,7 +84,8 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"ç¡æ³é£äžè¡å網路"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"è«åè©Šè®æŽå奜ç網路ãèŒè§žå³å¯è®æŽã"</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ç¡æ³æ¥æç·æ¥é»è©±"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ç¡æ³éé WiâFi æ¥æç·æ¥é»è©±"</string>
+ <!-- no translation found for EmergencyCallWarningSummary (9102799172089265268) -->
+ <skip />
<string name="notification_channel_network_alert" msgid="4788053066033851841">"å¿«èš"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"äŸé»èœæ¥"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ç·æ¥åæ¥æš¡åŒ"</string>
@@ -1183,6 +1184,10 @@
<string name="deleteText" msgid="4200807474529938112">"åªé€"</string>
<string name="inputMethod" msgid="1784759500516314751">"茞å
¥æ³"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"æååäœ"</string>
+ <!-- no translation found for error_handwriting_unsupported (7809438534946014050) -->
+ <skip />
+ <!-- no translation found for error_handwriting_unsupported_password (5095401146106891087) -->
+ <skip />
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"è¿å"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"åæèŒžå
¥æ³"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"å²å空éå³å°çšç¡"</string>
@@ -1900,7 +1905,7 @@
<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_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>
@@ -1971,7 +1976,7 @@
<string name="supervised_user_creation_label" msgid="6884904353827427515">"æ°å¢åç£ç®¡ç䜿çšè
"</string>
<string name="language_selection_title" msgid="52674936078683285">"æ°å¢èªèš"</string>
<string name="country_selection_title" msgid="5221495687299014379">"å°åå奜èšå®"</string>
- <string name="search_language_hint" msgid="7004225294308793583">"è«èŒžå
¥èªèšåçš±"</string>
+ <string name="search_language_hint" msgid="7004225294308793583">"è«èŒžå
¥èªèš"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"建è°èªèš"</string>
<string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建è°å°å"</string>
<string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"建è°èªèš"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index cf4858e..eb75d2a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -84,7 +84,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Ayikwazi ukufinyelela kunethiwekhi yeselula"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Zama ukushintsha inethiwekhi encanyelwayo. Thepha ukuze ushintshe."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Ukushaya okuphuthumayo akutholakali"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ayikwazi ukwenza amakholi aphuthumayo nge-Wi-Fi"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Amakholi aphuthumayo adinga inethiwekhi yeselula"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Izexwayiso"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Ukudlulisa ikholi"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"Imodi yokushayela yesimo esiphuthumayo"</string>
@@ -1183,6 +1183,8 @@
<string name="deleteText" msgid="4200807474529938112">"Susa"</string>
<string name="inputMethod" msgid="1784759500516314751">"Indlela yokufakwayo"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Izenzo zombhalo"</string>
+ <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Ukubhala ngesandla akusekelwa kule nkambu"</string>
+ <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Ukubhala ngesandla akusekelwa kuzinkambu zephasiwedi"</string>
<string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Emuva"</string>
<string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Shintsha indlela yokufaka"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Isikhala sokulondoloza siyaphela"</string>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 417c6df..e671919 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -593,6 +593,10 @@
<color name="accessibility_magnification_thumbnail_container_background_color">#99000000</color>
<color name="accessibility_magnification_thumbnail_container_stroke_color">#FFFFFF</color>
+ <!-- Activity Embedding divider -->
+ <color name="activity_embedding_divider_color">#8e918f</color>
+ <color name="activity_embedding_divider_color_pressed">#e3e3e3</color>
+
<!-- Lily Language Picker language item view colors -->
<color name="language_picker_item_text_color">#202124</color>
<color name="language_picker_item_text_color_secondary">#5F6368</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index efba709..1d6b151 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6419,10 +6419,8 @@
<!-- Default value for Settings.ASSIST_TOUCH_GESTURE_ENABLED -->
<bool name="config_assistTouchGestureEnabledDefault">true</bool>
- <!-- Default value for Settings.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED -->
- <bool name="config_searchPressHoldNavHandleEnabledDefault">true</bool>
- <!-- Default value for Settings.ASSIST_LONG_PRESS_HOME_ENABLED for search overlay -->
- <bool name="config_searchLongPressHomeEnabledDefault">true</bool>
+ <!-- Default value for Settings.SEARCH_ALL_ENTRYPOINTS_ENABLED -->
+ <bool name="config_searchAllEntrypointsEnabledDefault">true</bool>
<!-- The maximum byte size of the information contained in the bundle of
HotwordDetectedResult. -->
@@ -6986,4 +6984,7 @@
<!-- Whether WM DisplayContent supports high performance transitions
(lower-end devices may want to disable) -->
<bool name="config_deviceSupportsHighPerfTransitions">true</bool>
+
+ <!-- Wear devices: An intent action that is used for remote intent. -->
+ <string name="config_wearRemoteIntentAction" translatable="false" />
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 291a593..4aa741d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -1028,6 +1028,16 @@
<dimen name="popup_enter_animation_from_y_delta">20dp</dimen>
<dimen name="popup_exit_animation_to_y_delta">-10dp</dimen>
+ <!-- Dimensions for the activity embedding divider. -->
+ <dimen name="activity_embedding_divider_handle_width">4dp</dimen>
+ <dimen name="activity_embedding_divider_handle_height">48dp</dimen>
+ <dimen name="activity_embedding_divider_handle_radius">2dp</dimen>
+ <dimen name="activity_embedding_divider_handle_width_pressed">12dp</dimen>
+ <dimen name="activity_embedding_divider_handle_height_pressed">53dp</dimen>
+ <dimen name="activity_embedding_divider_handle_radius_pressed">6dp</dimen>
+ <dimen name="activity_embedding_divider_touch_target_width">24dp</dimen>
+ <dimen name="activity_embedding_divider_touch_target_height">64dp</dimen>
+
<!-- Default handwriting bounds offsets for editors. -->
<dimen name="handwriting_bounds_offset_left">10dp</dimen>
<dimen name="handwriting_bounds_offset_top">40dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f915f03..a3dba48 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -231,8 +231,10 @@
<string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
<string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
- <!-- Displayed to tell the user that emergency calls might not be available. -->
- <string name="EmergencyCallWarningSummary">Can\u2019t make emergency calls over Wi\u2011Fi</string>
+ <!-- Displayed to tell the user that emergency calls might not be available; this is shown to
+ the user when only WiFi calling is available and the carrier does not support emergency
+ calls over WiFi calling. -->
+ <string name="EmergencyCallWarningSummary">Emergency calls require a mobile network</string>
<!-- Telephony notification channel name for a channel containing network alert notifications. -->
<string name="notification_channel_network_alert">Alerts</string>
@@ -3247,6 +3249,12 @@
<!-- Title for EditText context menu [CHAR LIMIT=20] -->
<string name="editTextMenuTitle">Text actions</string>
+ <!-- Error shown when a user uses a stylus to try handwriting on a text field which doesn't support stylus handwriting. [CHAR LIMIT=TOAST] -->
+ <string name="error_handwriting_unsupported">Handwriting is not supported in this field</string>
+
+ <!-- Error shown when a user uses a stylus to try handwriting on a password text field which doesn't support stylus handwriting. [CHAR LIMIT=TOAST] -->
+ <string name="error_handwriting_unsupported_password">Handwriting is not supported in password fields</string>
+
<!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="input_method_nav_back_button_desc">Back</string>
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 668a88c..4322b55 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3122,6 +3122,8 @@
<!-- TextView -->
<java-symbol type="bool" name="config_textShareSupported" />
<java-symbol type="string" name="failed_to_copy_to_clipboard" />
+ <java-symbol type="string" name="error_handwriting_unsupported" />
+ <java-symbol type="string" name="error_handwriting_unsupported_password" />
<java-symbol type="id" name="notification_material_reply_container" />
<java-symbol type="id" name="notification_material_reply_text_1" />
@@ -5017,8 +5019,7 @@
<java-symbol type="bool" name="config_assistLongPressHomeEnabledDefault" />
<java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
- <java-symbol type="bool" name="config_searchPressHoldNavHandleEnabledDefault" />
- <java-symbol type="bool" name="config_searchLongPressHomeEnabledDefault" />
+ <java-symbol type="bool" name="config_searchAllEntrypointsEnabledDefault" />
<java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
@@ -5336,6 +5337,11 @@
<java-symbol type="raw" name="default_ringtone_vibration_effect" />
+ <!-- For activity embedding divider -->
+ <java-symbol type="drawable" name="activity_embedding_divider_handle" />
+ <java-symbol type="dimen" name="activity_embedding_divider_touch_target_width" />
+ <java-symbol type="dimen" name="activity_embedding_divider_touch_target_height" />
+
<!-- Whether we order unlocking and waking -->
<java-symbol type="bool" name="config_orderUnlockAndWake" />
@@ -5379,4 +5385,6 @@
<!-- Whether WM DisplayContent supports high performance transitions -->
<java-symbol type="bool" name="config_deviceSupportsHighPerfTransitions" />
+
+ <java-symbol type="string" name="config_wearRemoteIntentAction" />
</resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7d740ef..c8625b9 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -42,8 +42,8 @@
<!-- Argentina: 5 digits, known short codes listed -->
<shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077|78887" />
- <!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
- <shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" />
+ <!-- Armenia: 3-5 digits, emergency numbers 10[123] -->
+ <shortcode country="am" pattern="\\d{3,5}" premium="11[2456]1|3024" free="10[123]|71522|71512|71502" />
<!-- Austria: 10 digits, premium prefix 09xx, plus EU -->
<shortcode country="at" pattern="11\\d{4}" premium="09.*" free="116\\d{3}" />
@@ -111,7 +111,7 @@
<shortcode country="do" pattern="\\d{1,6}" free="912892" />
<!-- Ecuador: 1-6 digits (standard system default, not country specific) -->
- <shortcode country="ec" pattern="\\d{1,6}" free="466453" />
+ <shortcode country="ec" pattern="\\d{1,6}" free="466453|18512" />
<!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
@@ -137,11 +137,11 @@
visual voicemail code for EE: 887 -->
<shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
- <!-- Georgia: 4 digits, known premium codes listed -->
- <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
+ <!-- Georgia: 1-5 digits, known premium codes listed -->
+ <shortcode country="ge" pattern="\\d{1,5}" premium="801[234]|888[239]" free="95201|95202|95203" />
<!-- Ghana: 4 digits, known premium codes listed -->
- <shortcode country="gh" pattern="\\d{4}" free="5041" />
+ <shortcode country="gh" pattern="\\d{4}" free="5041|3777" />
<!-- Greece: 5 digits (54xxx, 19yxx, x=0-9, y=0-5): http://www.cmtelecom.com/premium-sms/greece -->
<shortcode country="gr" pattern="\\d{5}" premium="54\\d{3}|19[0-5]\\d{2}" free="116\\d{3}|12115" />
@@ -210,6 +210,9 @@
<!-- Macedonia: 1-6 digits (not confirmed), known premium codes listed -->
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
+ <!-- Mongolia : 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="mn" pattern="\\d{1,6}" free="44444|45678|445566" />
+
<!-- Malawi: 1-5 digits (standard system default, not country specific) -->
<shortcode country="mw" pattern="\\d{1,5}" free="4276" />
@@ -247,7 +250,7 @@
<shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" />
<!-- Pakistan -->
- <shortcode country="pk" pattern="\\d{1,5}" free="2057|9092" />
+ <shortcode country="pk" pattern="\\d{1,6}" free="2057|9092|909203" />
<!-- Palestine: 5 digits, known premium codes listed -->
<shortcode country="ps" pattern="\\d{1,5}" free="37477|6681" />
@@ -291,7 +294,7 @@
<shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
<!-- Senegal(SN): 1-5 digits (standard system default, not country specific) -->
- <shortcode country="sn" pattern="\\d{1,5}" free="21215" />
+ <shortcode country="sn" pattern="\\d{1,5}" free="21215|21098" />
<!-- El Salvador(SV): 1-5 digits (standard system default, not country specific) -->
<shortcode country="sv" pattern="\\d{4,6}" free="466453" />
@@ -321,14 +324,17 @@
visual voicemail code for T-Mobile: 122 -->
<shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831" />
+ <!--Uruguay : 1-5 digits (standard system default, not country specific) -->
+ <shortcode country="uy" pattern="\\d{1,5}" free="55002" />
+
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
+ <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055|8079" />
<!-- Mayotte (French Territory): 1-5 digits (not confirmed) -->
<shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
<!-- South Africa -->
- <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056" />
+ <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" />
<!-- Zimbabwe -->
<shortcode country="zw" pattern="\\d{1,5}" free="33679" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
index 9907397..2ce7a7d 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
@@ -88,6 +88,7 @@
private InsetsState mInsetsState;
private ClientWindowFrames mFrames;
private MergedConfiguration mMergedConfiguration;
+ private ActivityWindowInfo mActivityWindowInfo;
@Before
public void setup() {
@@ -99,6 +100,7 @@
mInsetsState = new InsetsState();
mFrames = new ClientWindowFrames();
mMergedConfiguration = new MergedConfiguration(mGlobalConfig, mConfiguration);
+ mActivityWindowInfo = new ActivityWindowInfo();
doReturn(mActivity).when(mHandler).getActivity(mActivityToken);
doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed();
@@ -107,7 +109,7 @@
@Test
public void testActivityConfigurationChangeItem_getContextToUpdate() {
final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem
- .obtain(mActivityToken, mConfiguration, new ActivityWindowInfo());
+ .obtain(mActivityToken, mConfiguration, mActivityWindowInfo);
final Context context = item.getContextToUpdate(mHandler);
assertEquals(mActivity, context);
@@ -118,7 +120,7 @@
final ActivityRelaunchItem item = ActivityRelaunchItem
.obtain(mActivityToken, null /* pendingResults */, null /* pendingNewIntents */,
0 /* configChange */, mMergedConfiguration, false /* preserveWindow */,
- new ActivityWindowInfo());
+ mActivityWindowInfo);
final Context context = item.getContextToUpdate(mHandler);
assertEquals(mActivity, context);
@@ -177,7 +179,7 @@
@Test
public void testMoveToDisplayItem_getContextToUpdate() {
final MoveToDisplayItem item = MoveToDisplayItem
- .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, new ActivityWindowInfo());
+ .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, mActivityWindowInfo);
final Context context = item.getContextToUpdate(mHandler);
assertEquals(mActivity, context);
@@ -218,13 +220,13 @@
final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames,
true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */,
true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
- true /* dragResizing */);
+ true /* dragResizing */, mActivityToken, mActivityWindowInfo);
item.execute(mHandler, mPendingActions);
verify(mWindow).resized(mFrames,
true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */,
true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
- true /* dragResizing */);
+ true /* dragResizing */, mActivityWindowInfo);
}
@Test
@@ -232,7 +234,7 @@
final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames,
true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */,
true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
- true /* dragResizing */);
+ true /* dragResizing */, mActivityToken, mActivityWindowInfo);
final Context context = item.getContextToUpdate(mHandler);
assertEquals(ActivityThread.currentApplication(), context);
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 93c2e0e..40e79ad 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
import android.platform.test.ravenwood.RavenwoodRule;
@@ -445,6 +446,42 @@
assertThat(bundle.size()).isEqualTo(0);
}
+ @Test
+ @DisabledOnRavenwood(blockedBy = Parcel.class)
+ public void parcelledBundleWithBinder_shouldReturnHasBindersTrue() throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("test", new CustomParcelable(13, "Tiramisu"));
+ bundle.putBinder("test_binder",
+ new IBinderWorkSourceNestedService.Stub() {
+
+ public int[] nestedCallWithWorkSourceToSet(int uidToBlame) {
+ return new int[0];
+ }
+
+ public int[] nestedCall() {
+ return new int[0];
+ }
+ });
+ Bundle bundle2 = new Bundle(getParcelledBundle(bundle));
+ assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_PRESENT);
+
+ bundle2.putParcelable("test2", new CustomParcelable(13, "Tiramisu"));
+ assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_UNKNOWN);
+ }
+
+ @Test
+ @DisabledOnRavenwood(blockedBy = Parcel.class)
+ public void parcelledBundleWithoutBinder_shouldReturnHasBindersFalse() throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("test", new CustomParcelable(13, "Tiramisu"));
+ Bundle bundle2 = new Bundle(getParcelledBundle(bundle));
+ //Should fail to load with framework classloader.
+ assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_NOT_PRESENT);
+
+ bundle2.putParcelable("test2", new CustomParcelable(13, "Tiramisu"));
+ assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_UNKNOWN);
+ }
+
private Bundle getMalformedBundle() {
Parcel p = Parcel.obtain();
p.writeInt(BaseBundle.BUNDLE_MAGIC);
@@ -520,6 +557,7 @@
public CustomParcelable createFromParcel(Parcel in) {
return new CustomParcelable(in);
}
+
@Override
public CustomParcelable[] newArray(int size) {
return new CustomParcelable[size];
diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java
index 26f6d69..442394e3 100644
--- a/core/tests/coretests/src/android/os/ParcelTest.java
+++ b/core/tests/coretests/src/android/os/ParcelTest.java
@@ -347,4 +347,30 @@
p.recycle();
Binder.setIsDirectlyHandlingTransactionOverride(false);
}
+
+ @Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
+ public void testHasBinders_AfterWritingBinderToParcel() {
+ Binder binder = new Binder();
+ Parcel pA = Parcel.obtain();
+ int iA = pA.dataPosition();
+ pA.writeInt(13);
+ assertFalse(pA.hasBinders());
+ pA.writeStrongBinder(binder);
+ assertTrue(pA.hasBinders());
+ }
+
+
+ @Test
+ @IgnoreUnderRavenwood(blockedBy = Parcel.class)
+ public void testHasBindersInRange_AfterWritingBinderToParcel() {
+ Binder binder = new Binder();
+ Parcel pA = Parcel.obtain();
+ pA.writeInt(13);
+
+ int binderStartPos = pA.dataPosition();
+ pA.writeStrongBinder(binder);
+ int binderEndPos = pA.dataPosition();
+ assertTrue(pA.hasBinders(binderStartPos, binderEndPos - binderStartPos));
+ }
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 316e191..97f894f 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -21,12 +21,11 @@
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
-import static android.view.InsetsController.AnimationType;
+import static android.view.InsetsSource.FLAG_ANIMATE_RESIZING;
import static android.view.InsetsSource.ID_IME;
import static android.view.InsetsSourceConsumer.ShowResult.IME_SHOW_DELAYED;
import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
-import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.defaultVisible;
@@ -671,36 +670,81 @@
}
@Test
- public void testResizeAnimation_insetsTypes() {
- for (int i = 0; i < SIZE; i++) {
- final @InsetsType int type = 1 << i;
- final @AnimationType int expectedAnimationType = (type & systemBars()) != 0
- ? ANIMATION_TYPE_RESIZE
- : ANIMATION_TYPE_NONE;
- doTestResizeAnimation_insetsTypes(type, expectedAnimationType);
- }
- }
-
- private void doTestResizeAnimation_insetsTypes(@InsetsType int type,
- @AnimationType int expectedAnimationType) {
- final int id = type;
+ public void testResizeAnimation_withFlagAnimateResizing() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final int id = ID_NAVIGATION_BAR;
+ final @InsetsType int type = navigationBars();
final InsetsState state1 = new InsetsState();
- state1.getOrCreateSource(id, type).setVisible(true).setFrame(0, 0, 500, 50);
+ state1.getOrCreateSource(id, type)
+ .setVisible(true)
+ .setFrame(0, 0, 500, 50)
+ .setFlags(FLAG_ANIMATE_RESIZING, FLAG_ANIMATE_RESIZING);
final InsetsState state2 = new InsetsState(state1, true /* copySources */);
state2.peekSource(id).setFrame(0, 0, 500, 60);
- final String message = "Animation type of " + WindowInsets.Type.toString(type) + ":";
+
+ // New insets source won't cause the resize animation.
+ mController.onStateChanged(state1);
+ assertEquals("There must not be resize animation.", ANIMATION_TYPE_NONE,
+ mController.getAnimationType(type));
+
+ // Changing frame of the source with FLAG_ANIMATE_RESIZING will cause the resize
+ // animation.
+ mController.onStateChanged(state2);
+ assertEquals("There must be resize animation.", ANIMATION_TYPE_RESIZE,
+ mController.getAnimationType(type));
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testResizeAnimation_withoutFlagAnimateResizing() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final int id = ID_STATUS_BAR;
+ final @InsetsType int type = statusBars();
+ final InsetsState state1 = new InsetsState();
+ state1.getOrCreateSource(id, type)
+ .setVisible(true)
+ .setFrame(0, 0, 500, 50)
+ .setFlags(0, FLAG_ANIMATE_RESIZING);
+ final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+ state2.peekSource(id).setFrame(0, 0, 500, 60);
+ final String message = "There must not be resize animation.";
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
- // Changing frame might cause the resize animation. This depends on the insets type.
+ // Changing frame of the source without FLAG_ANIMATE_RESIZING must not cause the resize
+ // animation.
mController.onStateChanged(state2);
- assertEquals(message, expectedAnimationType, mController.getAnimationType(type));
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
- // Cancel the existing animations for the next iteration.
- mController.cancelExistingAnimations();
+ @Test
+ public void testResizeAnimation_sourceFrame() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final int id = ID_STATUS_BAR;
+ final @InsetsType int type = statusBars();
+ final InsetsState state1 = new InsetsState();
+ state1.setDisplayFrame(new Rect(0, 0, 500, 1000));
+ state1.getOrCreateSource(id, type).setFrame(0, 0, 500, 50);
+ final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+ state2.setDisplayFrame(state1.getDisplayFrame());
+ state2.peekSource(id).setFrame(0, 0, 500, 0);
+ final String message = "There must not be resize animation.";
+
+ // New insets source won't cause the resize animation.
+ mController.onStateChanged(state1);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing frame won't cause the resize animation if the new frame is empty.
+ mController.onStateChanged(state2);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing frame won't cause the resize animation if the existing frame is empty.
+ mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 90a8c5c..226629e 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -16,7 +16,14 @@
package android.view;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
+import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_DEFAULT_NORMAL_READ_ONLY;
+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.toolkitFrameRateBySizeReadOnly;
+import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static junit.framework.Assert.assertEquals;
@@ -124,6 +131,7 @@
}
@Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void noVelocityUsesCategorySmall() throws Throwable {
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
@@ -141,12 +149,14 @@
// Now that it is small, any invalidation should have a normal category
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(Surface.FRAME_RATE_CATEGORY_NORMAL,
- mViewRoot.getPreferredFrameRateCategory());
+ int expected = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
});
}
@Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void noVelocityUsesCategoryNarrowWidth() throws Throwable {
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
@@ -164,12 +174,14 @@
// Now that it is small, any invalidation should have a normal category
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(Surface.FRAME_RATE_CATEGORY_NORMAL,
- mViewRoot.getPreferredFrameRateCategory());
+ int expected = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
});
}
@Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void noVelocityUsesCategoryNarrowHeight() throws Throwable {
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
@@ -187,12 +199,14 @@
// Now that it is small, any invalidation should have a normal category
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(Surface.FRAME_RATE_CATEGORY_NORMAL,
- mViewRoot.getPreferredFrameRateCategory());
+ int expected = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
});
}
@Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void noVelocityUsesCategoryLargeWidth() throws Throwable {
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
@@ -210,12 +224,14 @@
// Now that it is small, any invalidation should have a high category
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(Surface.FRAME_RATE_CATEGORY_HIGH,
- mViewRoot.getPreferredFrameRateCategory());
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
});
}
@Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void noVelocityUsesCategoryLargeHeight() throws Throwable {
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
@@ -233,7 +249,20 @@
// Now that it is small, any invalidation should have a high category
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(Surface.FRAME_RATE_CATEGORY_HIGH,
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
+ });
+ }
+
+ @Test
+ @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
+ FLAG_TOOLKIT_FRAME_RATE_DEFAULT_NORMAL_READ_ONLY})
+ public void defaultNormal() throws Throwable {
+ waitForFrameRateCategoryToSettle();
+ mActivityRule.runOnUiThread(() -> {
+ mMovingView.invalidate();
+ assertEquals(FRAME_RATE_CATEGORY_NORMAL,
mViewRoot.getPreferredFrameRateCategory());
});
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 652011b..fa364e0 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -41,6 +41,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -81,6 +82,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -462,6 +464,7 @@
*/
@UiThreadTest
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_getDefaultValues() {
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
@@ -478,6 +481,7 @@
* Also, mIsFrameRateBoosting should be true when the visibility becomes visible
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_visibility_bySize() {
@@ -511,6 +515,7 @@
* <7%: FRAME_RATE_CATEGORY_LOW
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_smallSize_bySize() {
@@ -539,6 +544,7 @@
* >=7% : FRAME_RATE_CATEGORY_NORMAL
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_normalSize_bySize() {
@@ -571,6 +577,7 @@
* Also, mIsFrameRateBoosting should be true when the visibility becomes visible
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateCategory_visibility_defaultHigh() {
View view = new View(sContext);
@@ -587,8 +594,9 @@
sInstrumentation.runOnMainSync(() -> {
view.setVisibility(View.VISIBLE);
view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_HIGH);
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory());
});
sInstrumentation.waitForIdleSync();
@@ -603,6 +611,7 @@
* <7%: FRAME_RATE_CATEGORY_NORMAL
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateCategory_smallSize_defaultHigh() {
View view = new View(sContext);
@@ -630,6 +639,7 @@
* >=7% : FRAME_RATE_CATEGORY_HIGH
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateCategory_normalSize_defaultHigh() {
View view = new View(sContext);
@@ -650,7 +660,9 @@
ViewRootImpl viewRootImpl = view.getViewRootImpl();
sInstrumentation.runOnMainSync(() -> {
view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory());
});
}
@@ -659,6 +671,7 @@
* It should take the max value among all of the voted categories per frame.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
View view = new View(sContext);
@@ -704,6 +717,7 @@
* prioritize 60Hz..
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRate_aggregate() {
View view = new View(sContext);
@@ -762,6 +776,7 @@
* submit your preferred choice to the ViewRootImpl.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRate_category() {
View view = new View(sContext);
@@ -801,6 +816,7 @@
* Also, we shouldn't call setFrameRate.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY, FLAG_VIEW_VELOCITY_API})
public void votePreferredFrameRate_voteFrameRateCategory_velocityToHigh() {
View view = new View(sContext);
@@ -832,6 +848,7 @@
* We should boost the frame rate if the value of mInsetsAnimationRunning is true.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_insetsAnimation() {
View view = new View(sContext);
@@ -868,6 +885,7 @@
* Test FrameRateBoostOnTouchEnabled API
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_frameRateBoostOnTouch() {
View view = new View(sContext);
@@ -900,6 +918,7 @@
* mPreferredFrameRate should be set to 0.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateTimeOut() throws InterruptedException {
final long delay = 200L;
@@ -937,6 +956,7 @@
* A View should either vote a frame rate or a frame rate category instead of both.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_voteFrameRateOnly() {
View view = new View(sContext);
@@ -979,6 +999,7 @@
* - otherwise, use the previous category value.
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_infrequentLayer_defaultHigh() throws InterruptedException {
final long delay = 200L;
@@ -1000,11 +1021,13 @@
ViewRootImpl viewRootImpl = view.getViewRootImpl();
- // In transistion from frequent update to infrequent update
+ // In transition from frequent update to infrequent update
Thread.sleep(delay);
sInstrumentation.runOnMainSync(() -> {
view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory());
});
// reset the frame rate category counts
@@ -1016,7 +1039,7 @@
sInstrumentation.waitForIdleSync();
}
- // In transistion from frequent update to infrequent update
+ // In transition from frequent update to infrequent update
Thread.sleep(delay);
sInstrumentation.runOnMainSync(() -> {
view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
@@ -1024,6 +1047,13 @@
assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
FRAME_RATE_CATEGORY_NO_PREFERENCE);
});
+ Thread.sleep(delay);
+ sInstrumentation.runOnMainSync(() -> {
+ view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ });
// Infrequent update
Thread.sleep(delay);
@@ -1039,6 +1069,7 @@
*/
@UiThreadTest
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_isFrameRatePowerSavingsBalanced() {
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
@@ -1056,6 +1087,7 @@
* 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category
*/
@Test
+ @Ignore("Can be enabled only after b/330596920 is ready")
@RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException {
final long delay = 30L;
@@ -1081,8 +1113,9 @@
assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
FRAME_RATE_CATEGORY_NO_PREFERENCE);
view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_HIGH);
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory());
});
// reset the frame rate category counts
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index a5c9624..faad472 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -52,9 +52,11 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -72,6 +74,7 @@
*/
@Presubmit
@SmallTest
+@UiThreadTest
@RunWith(AndroidJUnit4.class)
public class HandwritingInitiatorTest {
private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
@@ -133,7 +136,7 @@
when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
when(mTestView1.getLineAtCoordinate(anyFloat())).thenReturn(0);
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -170,7 +173,7 @@
when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
when(mTestView1.getLineAtCoordinate(anyFloat())).thenReturn(2);
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -200,7 +203,7 @@
@Test
public void onTouchEvent_startHandwritingOnce_when_stylusMoveMultiTimes_withinHWArea() {
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -244,9 +247,7 @@
when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
when(mTestView1.getLineAtCoordinate(anyFloat())).thenReturn(0);
- if (!mInitiateWithoutConnection) {
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
- }
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = sHwArea1.left - HW_BOUNDS_OFFSETS_LEFT_PX / 2;
final int y1 = sHwArea1.top - HW_BOUNDS_OFFSETS_TOP_PX / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -282,13 +283,7 @@
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
- if (mInitiateWithoutConnection) {
- // Focus is changed after stylus movement.
- mHandwritingInitiator.updateFocusedView(mTestView1, /*fromTouchEvent*/ true);
- } else {
- // InputConnection is created after stylus movement.
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
- }
+ onEditorFocusedOrConnectionCreated(mTestView1);
verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView1);
}
@@ -310,24 +305,11 @@
final int y2 = y1;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
-
- if (!mInitiateWithoutConnection) {
- // First create InputConnection for mTestView2 and verify that handwriting is not
- // started.
- mHandwritingInitiator.onInputConnectionCreated(mTestView2);
- }
-
+ onEditorFocusedOrConnectionCreated(mTestView2);
// Note: mTestView2 receives focus when initiationWithoutInputConnection() is enabled.
// verify that handwriting is not started.
verify(mHandwritingInitiator, never()).startHandwriting(mTestView2);
- if (mInitiateWithoutConnection) {
- // Focus is changed after stylus movement.
- mHandwritingInitiator.updateFocusedView(mTestView1, /*fromTouchEvent*/ true);
- } else {
- // Next create InputConnection for mTextView1. Handwriting is started for this view
- // since the stylus down point is closest to this view.
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
- }
+ onEditorFocusedOrConnectionCreated(mTestView1);
// Handwriting is started for this view since the stylus down point is closest to this
// view.
verify(mHandwritingInitiator).startHandwriting(mTestView1);
@@ -349,7 +331,7 @@
delegateView.setIsHandwritingDelegate(true);
mTestView1.setHandwritingDelegatorCallback(
- () -> mHandwritingInitiator.onInputConnectionCreated(delegateView));
+ () -> onEditorFocusedOrConnectionCreated(delegateView));
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
@@ -369,17 +351,15 @@
public void onTouchEvent_tryAcceptDelegation_delegatorCallbackFocusesDelegate() {
View delegateView = new EditText(mContext);
delegateView.setIsHandwritingDelegate(true);
+ if (mInitiateWithoutConnection) {
+ mHandwritingInitiator.onEditorFocused(delegateView);
+ }
mHandwritingInitiator.onInputConnectionCreated(delegateView);
reset(mHandwritingInitiator);
- if (mInitiateWithoutConnection) {
- mTestView1.setHandwritingDelegatorCallback(
- () -> mHandwritingInitiator.updateFocusedView(
- delegateView, /*fromTouchEvent*/ false));
- } else {
- mTestView1.setHandwritingDelegatorCallback(
- () -> mHandwritingInitiator.onDelegateViewFocused(delegateView));
- }
+
+ mTestView1.setHandwritingDelegatorCallback(
+ () -> mHandwritingInitiator.onDelegateViewFocused(delegateView));
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
@@ -391,7 +371,7 @@
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
- verify(mHandwritingInitiator, times(1)).tryAcceptStylusHandwritingDelegation(delegateView);
+ verify(mHandwritingInitiator, times(1)).tryAcceptStylusHandwritingDelegation(any());
}
@Test
@@ -429,14 +409,6 @@
assertThat(onTouchEventResult4).isTrue();
}
- private void callOnInputConnectionOrUpdateViewFocus(View view) {
- if (mInitiateWithoutConnection) {
- mHandwritingInitiator.updateFocusedView(view, /*fromTouchEvent*/ true);
- } else {
- mHandwritingInitiator.onInputConnectionCreated(view);
- }
- }
-
@Test
public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() {
final Rect rect = new Rect(600, 600, 900, 900);
@@ -444,7 +416,7 @@
false /* isStylusHandwritingAvailable */);
mHandwritingInitiator.updateHandwritingAreasForView(testView);
- callOnInputConnectionOrUpdateViewFocus(testView);
+ onEditorFocusedOrConnectionCreated(testView);
final int x1 = (rect.left + rect.right) / 2;
final int y1 = (rect.top + rect.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -463,7 +435,7 @@
@Test
public void onTouchEvent_notStartHandwriting_when_stylusTap_withinHWArea() {
- callOnInputConnectionOrUpdateViewFocus(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = 200;
final int y1 = 200;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -479,7 +451,7 @@
@Test
public void onTouchEvent_notStartHandwriting_when_stylusMove_outOfHWArea() {
- callOnInputConnectionOrUpdateViewFocus(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = 10;
final int y1 = 10;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -495,7 +467,7 @@
@Test
public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTimeOut() {
- callOnInputConnectionOrUpdateViewFocus(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = 10;
final int y1 = 10;
final long time1 = 10L;
@@ -551,9 +523,7 @@
@Test
public void onTouchEvent_focusView_inputConnectionAlreadyBuilt_stylusMoveOnce_withinHWArea() {
- if (!mInitiateWithoutConnection) {
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
- }
+ onEditorFocusedOrConnectionCreated(mTestView1);
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -606,14 +576,14 @@
verify(mTestView2, times(1)).requestFocus();
- callOnInputConnectionOrUpdateViewFocus(mTestView2);
+ onEditorFocusedOrConnectionCreated(mTestView2);
verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView2);
}
@Test
public void onTouchEvent_handwritingAreaOverlapped_focusedViewHasPriority() {
// Simulate the case where mTestView1 is focused.
- callOnInputConnectionOrUpdateViewFocus(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
// The ACTION_DOWN location is within the handwriting bounds of both mTestView1 and
// mTestView2. Although it's closer to mTestView2's handwriting bounds, handwriting is
// initiated for mTestView1 because it's focused.
@@ -651,7 +621,7 @@
@Test
public void onResolvePointerIcon_afterHandwriting_hidePointerIconForConnectedView() {
// simulate the case where sTestView1 is focused.
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
injectStylusEvent(mHandwritingInitiator, sHwArea1.centerX(), sHwArea1.centerY(),
/* exceedsHWSlop */ true);
// Verify that handwriting started for sTestView1.
@@ -677,15 +647,14 @@
public void onResolvePointerIcon_afterHandwriting_hidePointerIconForDelegatorView() {
// Set mTextView2 to be the delegate of mTestView1.
mTestView2.setIsHandwritingDelegate(true);
+ mTestView1.setHandwritingDelegatorCallback(
+ () -> {
+ if (mInitiateWithoutConnection) {
+ mHandwritingInitiator.updateFocusedView(mTestView2);
+ }
+ mHandwritingInitiator.onInputConnectionCreated(mTestView2);
+ });
- if (mInitiateWithoutConnection) {
- mTestView1.setHandwritingDelegatorCallback(
- () -> mHandwritingInitiator.updateFocusedView(
- mTestView2, /*fromTouchEvent*/ false));
- } else {
- mTestView1.setHandwritingDelegatorCallback(
- () -> mHandwritingInitiator.onInputConnectionCreated(mTestView2));
- }
injectStylusEvent(mHandwritingInitiator, sHwArea1.centerX(), sHwArea1.centerY(),
/* exceedsHWSlop */ true);
// Prerequisite check, verify that handwriting started for delegateView.
@@ -700,7 +669,7 @@
@Test
public void onResolvePointerIcon_showHoverIconAfterTap() {
// Simulate the case where sTestView1 is focused.
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
injectStylusEvent(mHandwritingInitiator, sHwArea1.centerX(), sHwArea1.centerY(),
/* exceedsHWSlop */ true);
// Verify that handwriting started for sTestView1.
@@ -722,7 +691,7 @@
@Test
public void onResolvePointerIcon_showHoverIconAfterFocusChange() {
// Simulate the case where sTestView1 is focused.
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
+ onEditorFocusedOrConnectionCreated(mTestView1);
injectStylusEvent(mHandwritingInitiator, sHwArea1.centerX(), sHwArea1.centerY(),
/* exceedsHWSlop */ true);
// Verify that handwriting started for sTestView1.
@@ -733,14 +702,8 @@
// After handwriting is initiated for the connected view, hide the hover icon.
assertThat(icon1).isNull();
- // Simulate that focus is switched to mTestView2 first and then switched back.
- if (mInitiateWithoutConnection) {
- mHandwritingInitiator.updateFocusedView(mTestView2, /*fromTouchEvent*/ true);
- mHandwritingInitiator.updateFocusedView(mTestView1, /*fromTouchEvent*/ true);
- } else {
- mHandwritingInitiator.onInputConnectionCreated(mTestView2);
- mHandwritingInitiator.onInputConnectionCreated(mTestView1);
- }
+ onEditorFocusedOrConnectionCreated(mTestView2);
+ onEditorFocusedOrConnectionCreated(mTestView1);
PointerIcon icon2 = mHandwritingInitiator.onResolvePointerIcon(mContext, hoverEvent1);
// After the change of focus, hover icon shows again.
@@ -752,11 +715,11 @@
if (mInitiateWithoutConnection) {
mTestView1.setAutoHandwritingEnabled(false);
mTestView1.setHandwritingDelegatorCallback(null);
- mHandwritingInitiator.updateFocusedView(mTestView1, /*fromTouchEvent*/ true);
+ onEditorFocusedOrConnectionCreated(mTestView1);
} else {
View mockView = createView(sHwArea1, false /* autoHandwritingEnabled */,
true /* isStylusHandwritingAvailable */);
- mHandwritingInitiator.onInputConnectionCreated(mockView);
+ onEditorFocusedOrConnectionCreated(mockView);
}
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
@@ -972,4 +935,12 @@
1 /* yPrecision */, 0 /* deviceId */, 0 /* edgeFlags */,
InputDevice.SOURCE_STYLUS, 0 /* flags */);
}
+
+ private void onEditorFocusedOrConnectionCreated(View testView) {
+ if (Flags.initiationWithoutInputConnection()) {
+ mHandwritingInitiator.onEditorFocused(testView);
+ } else {
+ mHandwritingInitiator.onInputConnectionCreated(testView);
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 60a436e..745390d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -25,7 +25,6 @@
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.google.common.truth.Truth.assertThat;
@@ -54,7 +53,6 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Handler;
-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;
@@ -176,21 +174,6 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
- public void selectTestService_oldPermissionDialog_deny_dialogIsHidden() {
- launchActivity();
- openShortcutsList();
-
- mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(Until.newWindow(), UI_TIMEOUT_MS);
- onView(withText(DENY_LABEL)).perform(scrollTo(), click());
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
- onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
- doesNotExist());
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_allow_rowChecked() {
launchActivity();
openShortcutsList();
@@ -202,7 +185,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_deny_rowNotChecked() {
launchActivity();
openShortcutsList();
@@ -214,7 +196,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_uninstall_callsUninstaller_rowRemoved() {
launchActivity();
openShortcutsList();
@@ -228,7 +209,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_notShownWhenNotRequired() throws Exception {
when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
.thenReturn(false);
@@ -243,7 +223,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_notPermittedByAdmin_blockedEvenIfNoWarningRequired()
throws Exception {
when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
@@ -380,11 +359,9 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (Flags.cleanupAccessibilityWarningDialog()) {
- // Setting the Theme is necessary here for the dialog to use the proper style
- // resources as designated in its layout XML.
- setTheme(R.style.Theme_DeviceDefault_DayNight);
- }
+ // Setting the Theme is necessary here for the dialog to use the proper style
+ // resources as designated in its layout XML.
+ setTheme(R.style.Theme_DeviceDefault_DayNight);
}
@Override
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
index 24aab61..362eeea 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
@@ -25,7 +25,6 @@
import android.app.AlertDialog;
import android.content.Context;
import android.os.RemoteException;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.AndroidTestingRunner;
@@ -57,8 +56,6 @@
*/
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-@RequiresFlagsEnabled(
- android.view.accessibility.Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public class AccessibilityServiceWarningTest {
private static final String A11Y_SERVICE_PACKAGE_LABEL = "TestA11yService";
private static final String A11Y_SERVICE_SUMMARY = "TestA11yService summary";
diff --git a/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
new file mode 100644
index 0000000..68545cf
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.internal.net;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityBlobStoreTest {
+ private static final String DATABASE_FILENAME = "ConnectivityBlobStore.db";
+ private static final String TEST_NAME = "TEST_NAME";
+ private static final byte[] TEST_BLOB = new byte[] {(byte) 10, (byte) 90, (byte) 45, (byte) 12};
+
+ private Context mContext;
+ private File mFile;
+
+ private ConnectivityBlobStore createConnectivityBlobStore() {
+ return new ConnectivityBlobStore(mFile);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mFile = mContext.getDatabasePath(DATABASE_FILENAME);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mContext.deleteDatabase(DATABASE_FILENAME);
+ }
+
+ @Test
+ public void testFileCreateDelete() {
+ assertFalse(mFile.exists());
+ createConnectivityBlobStore();
+ assertTrue(mFile.exists());
+
+ assertTrue(mContext.deleteDatabase(DATABASE_FILENAME));
+ assertFalse(mFile.exists());
+ }
+
+ @Test
+ public void testPutAndGet() throws Exception {
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.put(TEST_NAME, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(TEST_NAME));
+
+ // Test replacement
+ final byte[] newBlob = new byte[] {(byte) 15, (byte) 20};
+ assertTrue(connectivityBlobStore.put(TEST_NAME, newBlob));
+ assertArrayEquals(newBlob, connectivityBlobStore.get(TEST_NAME));
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+ assertFalse(connectivityBlobStore.remove(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.put(TEST_NAME, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(TEST_NAME));
+
+ assertTrue(connectivityBlobStore.remove(TEST_NAME));
+ assertNull(connectivityBlobStore.get(TEST_NAME));
+
+ // Removing again returns false
+ assertFalse(connectivityBlobStore.remove(TEST_NAME));
+ }
+
+ @Test
+ public void testMultipleNames() throws Exception {
+ final String name1 = TEST_NAME + "1";
+ final String name2 = TEST_NAME + "2";
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+ assertNull(connectivityBlobStore.get(name1));
+ assertNull(connectivityBlobStore.get(name2));
+ assertFalse(connectivityBlobStore.remove(name1));
+ assertFalse(connectivityBlobStore.remove(name2));
+
+ assertTrue(connectivityBlobStore.put(name1, TEST_BLOB));
+ assertTrue(connectivityBlobStore.put(name2, TEST_BLOB));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name1));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name2));
+
+ // Replace the blob for name1 only.
+ final byte[] newBlob = new byte[] {(byte) 16, (byte) 21};
+ assertTrue(connectivityBlobStore.put(name1, newBlob));
+ assertArrayEquals(newBlob, connectivityBlobStore.get(name1));
+
+ assertTrue(connectivityBlobStore.remove(name1));
+ assertNull(connectivityBlobStore.get(name1));
+ assertArrayEquals(TEST_BLOB, connectivityBlobStore.get(name2));
+
+ assertFalse(connectivityBlobStore.remove(name1));
+ assertTrue(connectivityBlobStore.remove(name2));
+ assertNull(connectivityBlobStore.get(name2));
+ assertFalse(connectivityBlobStore.remove(name2));
+ }
+
+ @Test
+ public void testList() throws Exception {
+ final String[] unsortedNames = new String[] {
+ TEST_NAME + "1",
+ TEST_NAME + "2",
+ TEST_NAME + "0",
+ "NON_MATCHING_PREFIX",
+ "MATCHING_SUFFIX_" + TEST_NAME
+ };
+ // Expected to match and discard the prefix and be in increasing sorted order.
+ final String[] expected = new String[] {
+ "0",
+ "1",
+ "2"
+ };
+ final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+ for (int i = 0; i < unsortedNames.length; i++) {
+ assertTrue(connectivityBlobStore.put(unsortedNames[i], TEST_BLOB));
+ }
+ final String[] actual = connectivityBlobStore.list(TEST_NAME /* prefix */);
+ assertArrayEquals(expected, actual);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/net/OWNERS b/core/tests/coretests/src/com/android/internal/net/OWNERS
new file mode 100644
index 0000000..f51ba47
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/net/OWNERS
@@ -0,0 +1 @@
+include /core/java/com/android/internal/net/OWNERS
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index fbe1b8e..6bdd291 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -49,6 +49,7 @@
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.RECOVERY"/>
+ <permission name="android.permission.SCHEDULE_EXACT_ALARM"/>
<permission name="android.permission.STATUS_BAR"/>
<permission name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 9c1c7006..ea3235b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -588,6 +588,8 @@
<permission name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" />
<!-- Permission required for CTS test - PackageManagerShellCommandInstallTest -->
<permission name="android.permission.EMERGENCY_INSTALL_PACKAGES" />
+ <!-- Permission required for Cts test - CtsSettingsTestCases -->
+ <permission name="android.permission.PREPARE_FACTORY_RESET" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Vendor_054c_Product_05c4.idc b/data/keyboards/Vendor_054c_Product_05c4.idc
index 9576e8d..2da6227 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.idc
+++ b/data/keyboards/Vendor_054c_Product_05c4.idc
@@ -45,14 +45,15 @@
# This uneven timing causes the apparent speed of a finger (calculated using
# time deltas between received reports) to vary dramatically even if it's
# actually moving smoothly across the touchpad, triggering the touchpad stack's
-# drumroll detection logic, which causes the finger's single smooth movement to
-# be treated as many small movements of consecutive touches, which are then
-# inhibited by the click wiggle filter.
+# drumroll detection logic. For moving fingers, the drumroll detection logic
+# splits the finger's single movement into many small movements of consecutive
+# touches, which are then inhibited by the click wiggle filter. For tapping
+# fingers, it prevents tapping to click because it thinks the finger's moving
+# too fast.
#
-# Since this touchpad does not seem vulnerable to click wiggle, we can safely
-# disable drumroll detection due to speed changes (by setting the speed change
-# threshold very high, since there's no boolean control property).
-gestureProp.Drumroll_Max_Speed_Change_Factor = 1000000000
+# Since this touchpad doesn't seem to have to drumroll issues, we can safely
+# disable drumroll detection.
+gestureProp.Drumroll_Suppression_Enable = 0
# Because of the way this touchpad is positioned, touches around the edges are
# no more likely to be palms than ones in the middle, so remove the edge zones
diff --git a/data/keyboards/Vendor_054c_Product_09cc.idc b/data/keyboards/Vendor_054c_Product_09cc.idc
index 9576e8d..2a1a4fc 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.idc
+++ b/data/keyboards/Vendor_054c_Product_09cc.idc
@@ -45,14 +45,15 @@
# This uneven timing causes the apparent speed of a finger (calculated using
# time deltas between received reports) to vary dramatically even if it's
# actually moving smoothly across the touchpad, triggering the touchpad stack's
-# drumroll detection logic, which causes the finger's single smooth movement to
-# be treated as many small movements of consecutive touches, which are then
-# inhibited by the click wiggle filter.
+# drumroll detection logic. For moving fingers, the drumroll detection logic
+# splits the finger's single movement into many small movements of consecutive
+# touches, which are then inhibited by the click wiggle filter. For tapping
+# fingers, it prevents tapping to click because it thinks the finger's moving
+# too fast.
#
-# Since this touchpad does not seem vulnerable to click wiggle, we can safely
-# disable drumroll detection due to speed changes (by setting the speed change
-# threshold very high, since there's no boolean control property).
-gestureProp.Drumroll_Max_Speed_Change_Factor = 1000000000
+# Since this touchpad doesn't seem to have drumroll issues, we can safely
+# disable drumroll detection.
+gestureProp.Drumroll_Suppression_Enable = 0
# Because of the way this touchpad is positioned, touches around the edges are
# no more likely to be palms than ones in the middle, so remove the edge zones
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index 6c81a60..1e41b4d 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -2,6 +2,7 @@
flag {
name: "exact_compute_bounds"
+ is_exported: true
namespace: "core_graphics"
description: "Add a function without unused exact param for computeBounds."
bug: "304478551"
@@ -9,6 +10,7 @@
flag {
name: "yuv_image_compress_to_ultra_hdr"
+ is_exported: true
namespace: "core_graphics"
description: "Feature flag for YUV image compress to Ultra HDR."
bug: "308978825"
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index f105072..2cac2e1 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -17,7 +17,6 @@
package android.security;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
import android.os.StrictMode;
/**
@@ -30,10 +29,6 @@
*/
public class KeyStore {
- // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int NO_ERROR = 1;
-
// Used for UID field to indicate the calling UID.
public static final int UID_SELF = -1;
@@ -48,8 +43,8 @@
* Add an authentication record to the keystore authorization table.
*
* @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
- * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
- * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
+ * @return 0 on success, otherwise an error value corresponding to a
+ * {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
public int addAuthToken(byte[] authToken) {
StrictMode.noteDiskWrite();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 101a10e..3f39eeb 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -359,14 +359,12 @@
} catch (KeyStoreException keyStoreException) {
GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
mKey, keyStoreException);
- if (e != null) {
- if (e instanceof InvalidKeyException) {
- throw (InvalidKeyException) e;
- } else if (e instanceof InvalidAlgorithmParameterException) {
- throw (InvalidAlgorithmParameterException) e;
- } else {
- throw new ProviderException("Unexpected exception type", e);
- }
+ if (e instanceof InvalidKeyException) {
+ throw (InvalidKeyException) e;
+ } else if (e instanceof InvalidAlgorithmParameterException) {
+ throw (InvalidAlgorithmParameterException) e;
+ } else {
+ throw new ProviderException("Unexpected exception type", e);
}
}
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 372e4cb..9b82206 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -20,7 +20,6 @@
import android.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.ErrorCode;
import android.security.GateKeeper;
-import android.security.KeyStore;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
@@ -131,15 +130,10 @@
/**
* Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
- * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
- * should succeed.
+ * in response to a failed {code IKeystoreSecurityLevel#createOperation()}.
*/
public static GeneralSecurityException getExceptionForCipherInit(
AndroidKeyStoreKey key, KeyStoreException e) {
- if (e.getErrorCode() == KeyStore.NO_ERROR) {
- return null;
- }
-
// Cipher-specific cases
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_INVALID_NONCE:
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 9756278..16c77d0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -53,7 +53,7 @@
* The min version of the WM Extensions that must be supported in the current platform version.
*/
@VisibleForTesting
- static final int EXTENSIONS_VERSION_CURRENT_PLATFORM = 5;
+ static final int EXTENSIONS_VERSION_CURRENT_PLATFORM = 6;
private final Object mLock = new Object();
private volatile DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
index 100185b..cae232e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -17,6 +17,12 @@
package androidx.window.extensions.embedding;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
+import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static androidx.window.extensions.embedding.DividerAttributes.RATIO_UNSET;
import static androidx.window.extensions.embedding.DividerAttributes.WIDTH_UNSET;
@@ -28,34 +34,253 @@
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RotateDrawable;
+import android.hardware.display.DisplayManager;
+import android.os.IBinder;
import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.window.InputTransferToken;
+import android.window.TaskFragmentOperation;
+import android.window.TaskFragmentParentInfo;
+import android.window.WindowContainerTransaction;
+import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;
+import java.util.Objects;
+
/**
* Manages the rendering and interaction of the divider.
*/
class DividerPresenter {
+ private static final String WINDOW_NAME = "AE Divider";
+
// TODO(b/327067596) Update based on UX guidance.
- @VisibleForTesting static final float DEFAULT_MIN_RATIO = 0.35f;
- @VisibleForTesting static final float DEFAULT_MAX_RATIO = 0.65f;
- @VisibleForTesting static final int DEFAULT_DIVIDER_WIDTH_DP = 24;
+ private static final Color DEFAULT_DIVIDER_COLOR = Color.valueOf(Color.BLACK);
+ @VisibleForTesting
+ static final float DEFAULT_MIN_RATIO = 0.35f;
+ @VisibleForTesting
+ static final float DEFAULT_MAX_RATIO = 0.65f;
+ @VisibleForTesting
+ static final int DEFAULT_DIVIDER_WIDTH_DP = 24;
- static int getDividerWidthPx(@NonNull DividerAttributes dividerAttributes) {
+ /**
+ * The {@link Properties} of the divider. This field is {@code null} when no divider should be
+ * drawn, e.g. when the split doesn't have {@link DividerAttributes} or when the decor surface
+ * is not available.
+ */
+ @Nullable
+ @VisibleForTesting
+ Properties mProperties;
+
+ /**
+ * The {@link Renderer} of the divider. This field is {@code null} when no divider should be
+ * drawn, i.e. when {@link #mProperties} is {@code null}. The {@link Renderer} is recreated or
+ * updated when {@link #mProperties} is changed.
+ */
+ @Nullable
+ @VisibleForTesting
+ Renderer mRenderer;
+
+ /**
+ * The owner TaskFragment token of the decor surface. The decor surface is placed right above
+ * the owner TaskFragment surface and is removed if the owner TaskFragment is destroyed.
+ */
+ @Nullable
+ @VisibleForTesting
+ IBinder mDecorSurfaceOwner;
+
+ /** Updates the divider when external conditions are changed. */
+ void updateDivider(
+ @NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentParentInfo parentInfo,
+ @Nullable SplitContainer topSplitContainer) {
+ if (!Flags.activityEmbeddingInteractiveDividerFlag()) {
+ return;
+ }
+
+ // Clean up the decor surface if top SplitContainer is null.
+ if (topSplitContainer == null) {
+ removeDecorSurfaceAndDivider(wct);
+ return;
+ }
+
+ // Clean up the decor surface if DividerAttributes is null.
+ final DividerAttributes dividerAttributes =
+ topSplitContainer.getCurrentSplitAttributes().getDividerAttributes();
+ if (dividerAttributes == null) {
+ removeDecorSurfaceAndDivider(wct);
+ return;
+ }
+
+ if (topSplitContainer.getCurrentSplitAttributes().getSplitType()
+ instanceof SplitAttributes.SplitType.ExpandContainersSplitType) {
+ // No divider is needed for ExpandContainersSplitType.
+ removeDivider();
+ return;
+ }
+
+ // Skip updating when the TFs have not been updated to match the SplitAttributes.
+ if (topSplitContainer.getPrimaryContainer().getLastRequestedBounds().isEmpty()
+ || topSplitContainer.getSecondaryContainer().getLastRequestedBounds().isEmpty()) {
+ return;
+ }
+
+ final SurfaceControl decorSurface = parentInfo.getDecorSurface();
+ if (decorSurface == null) {
+ // Clean up when the decor surface is currently unavailable.
+ removeDivider();
+ // Request to create the decor surface
+ createOrMoveDecorSurface(wct, topSplitContainer.getPrimaryContainer());
+ return;
+ }
+
+ // make the top primary container the owner of the decor surface.
+ if (!Objects.equals(mDecorSurfaceOwner,
+ topSplitContainer.getPrimaryContainer().getTaskFragmentToken())) {
+ createOrMoveDecorSurface(wct, topSplitContainer.getPrimaryContainer());
+ }
+
+ updateProperties(
+ new Properties(
+ parentInfo.getConfiguration(),
+ dividerAttributes,
+ decorSurface,
+ getInitialDividerPosition(topSplitContainer),
+ isVerticalSplit(topSplitContainer),
+ parentInfo.getDisplayId()));
+ }
+
+ private void updateProperties(@NonNull Properties properties) {
+ if (Properties.equalsForDivider(mProperties, properties)) {
+ return;
+ }
+ final Properties previousProperties = mProperties;
+ mProperties = properties;
+
+ if (mRenderer == null) {
+ // Create a new renderer when a renderer doesn't exist yet.
+ mRenderer = new Renderer();
+ } else if (!Properties.areSameSurfaces(
+ previousProperties.mDecorSurface, mProperties.mDecorSurface)
+ || previousProperties.mDisplayId != mProperties.mDisplayId) {
+ // Release and recreate the renderer if the decor surface or the display has changed.
+ mRenderer.release();
+ mRenderer = new Renderer();
+ } else {
+ // Otherwise, update the renderer for the new properties.
+ mRenderer.update();
+ }
+ }
+
+ /**
+ * Creates a decor surface for the TaskFragment if no decor surface exists, or changes the owner
+ * of the existing decor surface to be the specified TaskFragment.
+ *
+ * See {@link TaskFragmentOperation#OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE}.
+ */
+ private void createOrMoveDecorSurface(
+ @NonNull WindowContainerTransaction wct, @NonNull TaskFragmentContainer container) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+ wct.addTaskFragmentOperation(container.getTaskFragmentToken(), operation);
+ mDecorSurfaceOwner = container.getTaskFragmentToken();
+ }
+
+ private void removeDecorSurfaceAndDivider(@NonNull WindowContainerTransaction wct) {
+ if (mDecorSurfaceOwner != null) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+ wct.addTaskFragmentOperation(mDecorSurfaceOwner, operation);
+ mDecorSurfaceOwner = null;
+ }
+ removeDivider();
+ }
+
+ private void removeDivider() {
+ if (mRenderer != null) {
+ mRenderer.release();
+ }
+ mProperties = null;
+ mRenderer = null;
+ }
+
+ @VisibleForTesting
+ static int getInitialDividerPosition(@NonNull SplitContainer splitContainer) {
+ final Rect primaryBounds =
+ splitContainer.getPrimaryContainer().getLastRequestedBounds();
+ final Rect secondaryBounds =
+ splitContainer.getSecondaryContainer().getLastRequestedBounds();
+ if (isVerticalSplit(splitContainer)) {
+ return Math.min(primaryBounds.right, secondaryBounds.right);
+ } else {
+ return Math.min(primaryBounds.bottom, secondaryBounds.bottom);
+ }
+ }
+
+ private static boolean isVerticalSplit(@NonNull SplitContainer splitContainer) {
+ final int layoutDirection = splitContainer.getCurrentSplitAttributes().getLayoutDirection();
+ switch(layoutDirection) {
+ case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT:
+ case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT:
+ case SplitAttributes.LayoutDirection.LOCALE:
+ return true;
+ case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM:
+ case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP:
+ return false;
+ default:
+ throw new IllegalArgumentException("Invalid layout direction:" + layoutDirection);
+ }
+ }
+
+ private static void safeReleaseSurfaceControl(@Nullable SurfaceControl sc) {
+ if (sc != null) {
+ sc.release();
+ }
+ }
+
+ private static int getDividerWidthPx(@NonNull DividerAttributes dividerAttributes) {
int dividerWidthDp = dividerAttributes.getWidthDp();
+ return convertDpToPixel(dividerWidthDp);
+ }
+ private static int convertDpToPixel(int dp) {
// TODO(b/329193115) support divider on secondary display
final Context applicationContext = ActivityThread.currentActivityThread().getApplication();
return (int) TypedValue.applyDimension(
COMPLEX_UNIT_DIP,
- dividerWidthDp,
+ dp,
applicationContext.getResources().getDisplayMetrics());
}
+ private static int getDimensionDp(@IdRes int resId) {
+ final Context context = ActivityThread.currentActivityThread().getApplication();
+ final int px = context.getResources().getDimensionPixelSize(resId);
+ return (int) TypedValue.convertPixelsToDimension(
+ COMPLEX_UNIT_DIP,
+ px,
+ context.getResources().getDisplayMetrics());
+ }
+
/**
* Returns the container bound offset that is a result of the presence of a divider.
*
@@ -140,6 +365,12 @@
widthDp = DEFAULT_DIVIDER_WIDTH_DP;
}
+ if (dividerAttributes.getDividerType() == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) {
+ // Draggable divider width must be larger than the drag handle size.
+ widthDp = Math.max(widthDp,
+ getDimensionDp(R.dimen.activity_embedding_divider_touch_target_width));
+ }
+
float minRatio = dividerAttributes.getPrimaryMinRatio();
if (minRatio == RATIO_UNSET) {
minRatio = DEFAULT_MIN_RATIO;
@@ -156,4 +387,231 @@
.setPrimaryMaxRatio(maxRatio)
.build();
}
+
+ /**
+ * Properties for the {@link DividerPresenter}. The rendering of the divider solely depends on
+ * these properties. When any value is updated, the divider is re-rendered. The Properties
+ * instance is created only when all the pre-conditions of drawing a divider are met.
+ */
+ @VisibleForTesting
+ static class Properties {
+ private static final int CONFIGURATION_MASK_FOR_DIVIDER =
+ ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+ @NonNull
+ private final Configuration mConfiguration;
+ @NonNull
+ private final DividerAttributes mDividerAttributes;
+ @NonNull
+ private final SurfaceControl mDecorSurface;
+
+ /** The initial position of the divider calculated based on container bounds. */
+ private final int mInitialDividerPosition;
+
+ /** Whether the split is vertical, such as left-to-right or right-to-left split. */
+ private final boolean mIsVerticalSplit;
+
+ private final int mDisplayId;
+
+ @VisibleForTesting
+ Properties(
+ @NonNull Configuration configuration,
+ @NonNull DividerAttributes dividerAttributes,
+ @NonNull SurfaceControl decorSurface,
+ int initialDividerPosition,
+ boolean isVerticalSplit,
+ int displayId) {
+ mConfiguration = configuration;
+ mDividerAttributes = dividerAttributes;
+ mDecorSurface = decorSurface;
+ mInitialDividerPosition = initialDividerPosition;
+ mIsVerticalSplit = isVerticalSplit;
+ mDisplayId = displayId;
+ }
+
+ /**
+ * Compares whether two Properties objects are equal for rendering the divider. The
+ * Configuration is checked for rendering related fields, and other fields are checked for
+ * regular equality.
+ */
+ private static boolean equalsForDivider(@Nullable Properties a, @Nullable Properties b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return areSameSurfaces(a.mDecorSurface, b.mDecorSurface)
+ && Objects.equals(a.mDividerAttributes, b.mDividerAttributes)
+ && areConfigurationsEqualForDivider(a.mConfiguration, b.mConfiguration)
+ && a.mInitialDividerPosition == b.mInitialDividerPosition
+ && a.mIsVerticalSplit == b.mIsVerticalSplit
+ && a.mDisplayId == b.mDisplayId;
+ }
+
+ private static boolean areSameSurfaces(
+ @Nullable SurfaceControl sc1, @Nullable SurfaceControl sc2) {
+ if (sc1 == sc2) {
+ // If both are null or both refer to the same object.
+ return true;
+ }
+ if (sc1 == null || sc2 == null) {
+ return false;
+ }
+ return sc1.isSameSurface(sc2);
+ }
+
+ private static boolean areConfigurationsEqualForDivider(
+ @NonNull Configuration a, @NonNull Configuration b) {
+ final int diff = a.diff(b);
+ return (diff & CONFIGURATION_MASK_FOR_DIVIDER) == 0;
+ }
+ }
+
+ /**
+ * Handles the rendering of the divider. When the decor surface is updated, the renderer is
+ * recreated. When other fields in the Properties are changed, the renderer is updated.
+ */
+ @VisibleForTesting
+ class Renderer {
+ @NonNull
+ private final SurfaceControl mDividerSurface;
+ @NonNull
+ private final WindowlessWindowManager mWindowlessWindowManager;
+ @NonNull
+ private final SurfaceControlViewHost mViewHost;
+ @NonNull
+ private final FrameLayout mDividerLayout;
+ private final int mDividerWidthPx;
+
+ private Renderer() {
+ mDividerWidthPx = getDividerWidthPx(mProperties.mDividerAttributes);
+
+ mDividerSurface = createChildSurface("DividerSurface", true /* visible */);
+ mWindowlessWindowManager = new WindowlessWindowManager(
+ mProperties.mConfiguration,
+ mDividerSurface,
+ new InputTransferToken());
+
+ final Context context = ActivityThread.currentActivityThread().getApplication();
+ final DisplayManager displayManager = context.getSystemService(DisplayManager.class);
+ mViewHost = new SurfaceControlViewHost(
+ context, displayManager.getDisplay(mProperties.mDisplayId),
+ mWindowlessWindowManager, "DividerContainer");
+ mDividerLayout = new FrameLayout(context);
+
+ update();
+ }
+
+ /** Updates the divider when properties are changed */
+ @VisibleForTesting
+ void update() {
+ mWindowlessWindowManager.setConfiguration(mProperties.mConfiguration);
+ updateSurface();
+ updateLayout();
+ updateDivider();
+ }
+
+ @VisibleForTesting
+ void release() {
+ mViewHost.release();
+ // TODO handle synchronization between surface transactions and WCT.
+ new SurfaceControl.Transaction().remove(mDividerSurface).apply();
+ safeReleaseSurfaceControl(mDividerSurface);
+ }
+
+ private void updateSurface() {
+ final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+ // TODO handle synchronization between surface transactions and WCT.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ if (mProperties.mIsVerticalSplit) {
+ t.setPosition(mDividerSurface, mProperties.mInitialDividerPosition, 0.0f);
+ t.setWindowCrop(mDividerSurface, mDividerWidthPx, taskBounds.height());
+ } else {
+ t.setPosition(mDividerSurface, 0.0f, mProperties.mInitialDividerPosition);
+ t.setWindowCrop(mDividerSurface, taskBounds.width(), mDividerWidthPx);
+ }
+ t.apply();
+ }
+
+ private void updateLayout() {
+ final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+ final WindowManager.LayoutParams lp = mProperties.mIsVerticalSplit
+ ? new WindowManager.LayoutParams(
+ mDividerWidthPx,
+ taskBounds.height(),
+ TYPE_APPLICATION_PANEL,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT)
+ : new WindowManager.LayoutParams(
+ taskBounds.width(),
+ mDividerWidthPx,
+ TYPE_APPLICATION_PANEL,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle(WINDOW_NAME);
+ mViewHost.setView(mDividerLayout, lp);
+ }
+
+ private void updateDivider() {
+ mDividerLayout.removeAllViews();
+ mDividerLayout.setBackgroundColor(DEFAULT_DIVIDER_COLOR.toArgb());
+ if (mProperties.mDividerAttributes.getDividerType()
+ == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) {
+ drawDragHandle();
+ }
+ mViewHost.getView().invalidate();
+ }
+
+ private void drawDragHandle() {
+ final Context context = mDividerLayout.getContext();
+ final ImageButton button = new ImageButton(context);
+ final FrameLayout.LayoutParams params = mProperties.mIsVerticalSplit
+ ? new FrameLayout.LayoutParams(
+ context.getResources().getDimensionPixelSize(
+ R.dimen.activity_embedding_divider_touch_target_width),
+ context.getResources().getDimensionPixelSize(
+ R.dimen.activity_embedding_divider_touch_target_height))
+ : new FrameLayout.LayoutParams(
+ context.getResources().getDimensionPixelSize(
+ R.dimen.activity_embedding_divider_touch_target_height),
+ context.getResources().getDimensionPixelSize(
+ R.dimen.activity_embedding_divider_touch_target_width));
+ params.gravity = Gravity.CENTER;
+ button.setLayoutParams(params);
+ button.setBackgroundColor(R.color.transparent);
+
+ final Drawable handle = context.getResources().getDrawable(
+ R.drawable.activity_embedding_divider_handle, context.getTheme());
+ if (mProperties.mIsVerticalSplit) {
+ button.setImageDrawable(handle);
+ } else {
+ // Rotate the handle drawable
+ RotateDrawable rotatedHandle = new RotateDrawable();
+ rotatedHandle.setFromDegrees(90f);
+ rotatedHandle.setToDegrees(90f);
+ rotatedHandle.setPivotXRelative(true);
+ rotatedHandle.setPivotYRelative(true);
+ rotatedHandle.setPivotX(0.5f);
+ rotatedHandle.setPivotY(0.5f);
+ rotatedHandle.setLevel(1);
+ rotatedHandle.setDrawable(handle);
+
+ button.setImageDrawable(rotatedHandle);
+ }
+ mDividerLayout.addView(button);
+ }
+
+ @NonNull
+ private SurfaceControl createChildSurface(@NonNull String name, boolean visible) {
+ final Rect bounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+ return new SurfaceControl.Builder()
+ .setParent(mProperties.mDecorSurface)
+ .setName(name)
+ .setHidden(!visible)
+ .setCallsite("DividerManager.createChildSurface")
+ .setBufferSize(bounds.width(), bounds.height())
+ .setColorLayer()
+ .build();
+ }
+ }
}
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 80afb16d..3f4dddf 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -168,11 +168,14 @@
* @param fragmentToken token of an existing TaskFragment.
*/
void expandTaskFragment(@NonNull WindowContainerTransaction wct,
- @NonNull IBinder fragmentToken) {
+ @NonNull TaskFragmentContainer container) {
+ final IBinder fragmentToken = container.getTaskFragmentToken();
resizeTaskFragment(wct, fragmentToken, new Rect());
clearAdjacentTaskFragments(wct, fragmentToken);
updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED);
updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT);
+
+ container.getTaskContainer().updateDivider(wct);
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 0cc4b1f..1bc8264 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -844,6 +844,7 @@
// Checks if container should be updated before apply new parentInfo.
final boolean shouldUpdateContainer = taskContainer.shouldUpdateContainer(parentInfo);
taskContainer.updateTaskFragmentParentInfo(parentInfo);
+ taskContainer.updateDivider(wct);
// If the last direct activity of the host task is dismissed and the overlay container is
// the only taskFragment, the overlay container should also be dismissed.
@@ -1224,7 +1225,7 @@
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (shouldContainerBeExpanded(container)) {
// Make sure that the existing container is expanded.
- mPresenter.expandTaskFragment(wct, container.getTaskFragmentToken());
+ mPresenter.expandTaskFragment(wct, container);
} else {
// Put activity into a new expanded container.
final TaskFragmentContainer newContainer = newContainer(activity, getTaskId(activity));
@@ -1928,7 +1929,7 @@
}
if (shouldContainerBeExpanded(container)) {
if (container.getInfo() != null) {
- mPresenter.expandTaskFragment(wct, container.getTaskFragmentToken());
+ mPresenter.expandTaskFragment(wct, container);
}
// If the info is not available yet the task fragment will be expanded when it's ready
return;
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 f680694..20bc820 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -368,6 +368,7 @@
updateTaskFragmentWindowingModeIfRegistered(wct, secondaryContainer, windowingMode);
updateAnimationParams(wct, primaryContainer.getTaskFragmentToken(), splitAttributes);
updateAnimationParams(wct, secondaryContainer.getTaskFragmentToken(), splitAttributes);
+ taskContainer.updateDivider(wct);
}
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@@ -686,8 +687,8 @@
splitContainer.getPrimaryContainer().getTaskFragmentToken();
final IBinder secondaryToken =
splitContainer.getSecondaryContainer().getTaskFragmentToken();
- expandTaskFragment(wct, primaryToken);
- expandTaskFragment(wct, secondaryToken);
+ expandTaskFragment(wct, splitContainer.getPrimaryContainer());
+ expandTaskFragment(wct, splitContainer.getSecondaryContainer());
// Set the companion TaskFragment when the two containers stacked.
setCompanionTaskFragment(wct, primaryToken, secondaryToken,
splitContainer.getSplitRule(), true /* isStacked */);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 73109e2..e75a317 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -77,6 +77,9 @@
private boolean mHasDirectActivity;
+ @Nullable
+ private TaskFragmentParentInfo mTaskFragmentParentInfo;
+
/**
* TaskFragments that the organizer has requested to be closed. They should be removed when
* the organizer receives
@@ -85,14 +88,17 @@
*/
final Set<IBinder> mFinishedContainer = new ArraySet<>();
+ // TODO(b/293654166): move DividerPresenter to SplitController.
+ @NonNull
+ final DividerPresenter mDividerPresenter;
+
/**
* The {@link TaskContainer} constructor
*
- * @param taskId The ID of the Task, which must match {@link Activity#getTaskId()} with
- * {@code activityInTask}.
+ * @param taskId The ID of the Task, which must match {@link Activity#getTaskId()} with
+ * {@code activityInTask}.
* @param activityInTask The {@link Activity} in the Task with {@code taskId}. It is used to
* initialize the {@link TaskContainer} properties.
- *
*/
TaskContainer(int taskId, @NonNull Activity activityInTask) {
if (taskId == INVALID_TASK_ID) {
@@ -107,6 +113,7 @@
// the host task is visible and has an activity in the task.
mIsVisible = true;
mHasDirectActivity = true;
+ mDividerPresenter = new DividerPresenter();
}
int getTaskId() {
@@ -136,10 +143,12 @@
}
void updateTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
+ // TODO(b/293654166): cache the TaskFragmentParentInfo and remove these fields.
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.getDisplayId();
mIsVisible = info.isVisible();
mHasDirectActivity = info.hasDirectActivity();
+ mTaskFragmentParentInfo = info;
}
/**
@@ -161,8 +170,8 @@
* Returns the windowing mode for the TaskFragments below this Task, which should be split with
* other TaskFragments.
*
- * @param taskFragmentBounds Requested bounds for the TaskFragment. It will be empty when
- * the pair of TaskFragments are stacked due to the limited space.
+ * @param taskFragmentBounds Requested bounds for the TaskFragment. It will be empty when
+ * the pair of TaskFragments are stacked due to the limited space.
*/
@WindowingMode
int getWindowingModeForTaskFragment(@Nullable Rect taskFragmentBounds) {
@@ -228,7 +237,7 @@
@Nullable
TaskFragmentContainer getTopNonFinishingTaskFragmentContainer(boolean includePin,
- boolean includeOverlay) {
+ boolean includeOverlay) {
for (int i = mContainers.size() - 1; i >= 0; i--) {
final TaskFragmentContainer container = mContainers.get(i);
if (!includePin && isTaskFragmentContainerPinned(container)) {
@@ -283,7 +292,7 @@
return mContainers.indexOf(child);
}
- /** Whether the Task is in an intermediate state waiting for the server update.*/
+ /** Whether the Task is in an intermediate state waiting for the server update. */
boolean isInIntermediateState() {
for (TaskFragmentContainer container : mContainers) {
if (container.isInIntermediateState()) {
@@ -389,6 +398,26 @@
return mContainers;
}
+ void updateDivider(@NonNull WindowContainerTransaction wct) {
+ if (mTaskFragmentParentInfo != null) {
+ // Update divider only if TaskFragmentParentInfo is available.
+ mDividerPresenter.updateDivider(
+ wct, mTaskFragmentParentInfo, getTopNonFinishingSplitContainer());
+ }
+ }
+
+ @Nullable
+ private SplitContainer getTopNonFinishingSplitContainer() {
+ for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+ final SplitContainer splitContainer = mSplitContainers.get(i);
+ if (!splitContainer.getPrimaryContainer().isFinished()
+ && !splitContainer.getSecondaryContainer().isFinished()) {
+ return splitContainer;
+ }
+ }
+ return null;
+ }
+
private void onTaskFragmentContainerUpdated() {
// TODO(b/300211704): Find a better mechanism to handle the z-order in case we introduce
// another special container that should also be on top in the future.
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 a6bf99d..e20a3e0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -748,6 +748,10 @@
}
}
+ @NonNull Rect getLastRequestedBounds() {
+ return mLastRequestedBounds;
+ }
+
/**
* Checks if last requested windowing mode is equal to the provided value.
* @see WindowContainerTransaction#setWindowingMode
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
index 2a277f4..4d1d807 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
@@ -16,22 +16,49 @@
package androidx.window.extensions.embedding;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
+import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
+
import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider;
+import static androidx.window.extensions.embedding.DividerPresenter.getInitialDividerPosition;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.Display;
+import android.view.SurfaceControl;
+import android.window.TaskFragmentOperation;
+import android.window.TaskFragmentParentInfo;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.window.flags.Flags;
+
+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;
/**
* Test class for {@link DividerPresenter}.
@@ -43,6 +70,167 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DividerPresenterTest {
+ @Rule
+ public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
+
+ @Mock
+ private DividerPresenter.Renderer mRenderer;
+
+ @Mock
+ private WindowContainerTransaction mTransaction;
+
+ @Mock
+ private TaskFragmentParentInfo mParentInfo;
+
+ @Mock
+ private SplitContainer mSplitContainer;
+
+ @Mock
+ private SurfaceControl mSurfaceControl;
+
+ private DividerPresenter mDividerPresenter;
+
+ private final IBinder mPrimaryContainerToken = new Binder();
+
+ private final IBinder mSecondaryContainerToken = new Binder();
+
+ private final IBinder mAnotherContainerToken = new Binder();
+
+ private DividerPresenter.Properties mProperties;
+
+ private static final DividerAttributes DEFAULT_DIVIDER_ATTRIBUTES =
+ new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE).build();
+
+ private static final DividerAttributes ANOTHER_DIVIDER_ATTRIBUTES =
+ new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE)
+ .setWidthDp(10).build();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_EMBEDDING_INTERACTIVE_DIVIDER_FLAG);
+
+ when(mParentInfo.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY);
+ when(mParentInfo.getConfiguration()).thenReturn(new Configuration());
+ when(mParentInfo.getDecorSurface()).thenReturn(mSurfaceControl);
+
+ when(mSplitContainer.getCurrentSplitAttributes()).thenReturn(
+ new SplitAttributes.Builder()
+ .setDividerAttributes(DEFAULT_DIVIDER_ATTRIBUTES)
+ .build());
+ final TaskFragmentContainer mockPrimaryContainer =
+ createMockTaskFragmentContainer(
+ mPrimaryContainerToken, new Rect(0, 0, 950, 1000));
+ final TaskFragmentContainer mockSecondaryContainer =
+ createMockTaskFragmentContainer(
+ mSecondaryContainerToken, new Rect(1000, 0, 2000, 1000));
+ when(mSplitContainer.getPrimaryContainer()).thenReturn(mockPrimaryContainer);
+ when(mSplitContainer.getSecondaryContainer()).thenReturn(mockSecondaryContainer);
+
+ mProperties = new DividerPresenter.Properties(
+ new Configuration(),
+ DEFAULT_DIVIDER_ATTRIBUTES,
+ mSurfaceControl,
+ getInitialDividerPosition(mSplitContainer),
+ true /* isVerticalSplit */,
+ Display.DEFAULT_DISPLAY);
+
+ mDividerPresenter = new DividerPresenter();
+ mDividerPresenter.mProperties = mProperties;
+ mDividerPresenter.mRenderer = mRenderer;
+ mDividerPresenter.mDecorSurfaceOwner = mPrimaryContainerToken;
+ }
+
+ @Test
+ public void testUpdateDivider() {
+ when(mSplitContainer.getCurrentSplitAttributes()).thenReturn(
+ new SplitAttributes.Builder()
+ .setDividerAttributes(ANOTHER_DIVIDER_ATTRIBUTES)
+ .build());
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ mSplitContainer);
+
+ assertNotEquals(mProperties, mDividerPresenter.mProperties);
+ verify(mRenderer).update();
+ verify(mTransaction, never()).addTaskFragmentOperation(any(), any());
+ }
+
+ @Test
+ public void testUpdateDivider_updateDecorSurfaceOwnerIfPrimaryContainerChanged() {
+ final TaskFragmentContainer mockPrimaryContainer =
+ createMockTaskFragmentContainer(
+ mAnotherContainerToken, new Rect(0, 0, 750, 1000));
+ final TaskFragmentContainer mockSecondaryContainer =
+ createMockTaskFragmentContainer(
+ mSecondaryContainerToken, new Rect(800, 0, 2000, 1000));
+ when(mSplitContainer.getPrimaryContainer()).thenReturn(mockPrimaryContainer);
+ when(mSplitContainer.getSecondaryContainer()).thenReturn(mockSecondaryContainer);
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ mSplitContainer);
+
+ assertNotEquals(mProperties, mDividerPresenter.mProperties);
+ verify(mRenderer).update();
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+ assertEquals(mAnotherContainerToken, mDividerPresenter.mDecorSurfaceOwner);
+ verify(mTransaction).addTaskFragmentOperation(mAnotherContainerToken, operation);
+ }
+
+ @Test
+ public void testUpdateDivider_noChangeIfPropertiesIdentical() {
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ mSplitContainer);
+
+ assertEquals(mProperties, mDividerPresenter.mProperties);
+ verify(mRenderer, never()).update();
+ verify(mTransaction, never()).addTaskFragmentOperation(any(), any());
+ }
+
+ @Test
+ public void testUpdateDivider_dividerRemovedWhenSplitContainerIsNull() {
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ null /* splitContainer */);
+ final TaskFragmentOperation taskFragmentOperation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+
+ verify(mTransaction).addTaskFragmentOperation(
+ mPrimaryContainerToken, taskFragmentOperation);
+ verify(mRenderer).release();
+ assertNull(mDividerPresenter.mRenderer);
+ assertNull(mDividerPresenter.mProperties);
+ assertNull(mDividerPresenter.mDecorSurfaceOwner);
+ }
+
+ @Test
+ public void testUpdateDivider_dividerRemovedWhenDividerAttributesIsNull() {
+ when(mSplitContainer.getCurrentSplitAttributes()).thenReturn(
+ new SplitAttributes.Builder().setDividerAttributes(null).build());
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ mSplitContainer);
+ final TaskFragmentOperation taskFragmentOperation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+
+ verify(mTransaction).addTaskFragmentOperation(
+ mPrimaryContainerToken, taskFragmentOperation);
+ verify(mRenderer).release();
+ assertNull(mDividerPresenter.mRenderer);
+ assertNull(mDividerPresenter.mProperties);
+ assertNull(mDividerPresenter.mDecorSurfaceOwner);
+ }
+
@Test
public void testSanitizeDividerAttributes_setDefaultValues() {
DividerAttributes attributes =
@@ -61,7 +249,7 @@
public void testSanitizeDividerAttributes_notChangingValidValues() {
DividerAttributes attributes =
new DividerAttributes.Builder(DividerAttributes.DIVIDER_TYPE_DRAGGABLE)
- .setWidthDp(10)
+ .setWidthDp(24)
.setPrimaryMinRatio(0.3f)
.setPrimaryMaxRatio(0.7f)
.build();
@@ -123,6 +311,14 @@
dividerWidthPx, splitType, expectedTopLeftOffset, expectedBottomRightOffset);
}
+ private TaskFragmentContainer createMockTaskFragmentContainer(
+ @NonNull IBinder token, @NonNull Rect bounds) {
+ final TaskFragmentContainer container = mock(TaskFragmentContainer.class);
+ when(container.getTaskFragmentToken()).thenReturn(token);
+ when(container.getLastRequestedBounds()).thenReturn(bounds);
+ return container;
+ }
+
private void assertDividerOffsetEquals(
int dividerWidthPx,
@NonNull SplitAttributes.SplitType splitType,
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index dd087e8..6f37e9c 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -107,7 +107,7 @@
mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
container.setInfo(mTransaction, info);
- mOrganizer.expandTaskFragment(mTransaction, container.getTaskFragmentToken());
+ mOrganizer.expandTaskFragment(mTransaction, container);
verify(mTransaction).setWindowingMode(container.getInfo().getToken(),
WINDOWING_MODE_UNDEFINED);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index cdb37ac..c246a19 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -642,7 +642,7 @@
false /* isOnReparent */);
assertTrue(result);
- verify(mSplitPresenter).expandTaskFragment(mTransaction, container.getTaskFragmentToken());
+ verify(mSplitPresenter).expandTaskFragment(mTransaction, container);
}
@Test
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 941b4e1..62d8aa3 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
@@ -665,8 +665,8 @@
assertEquals(RESULT_EXPANDED, mPresenter.expandSplitContainerIfNeeded(mTransaction,
splitContainer, mActivity, secondaryActivity, null /* secondaryIntent */));
- verify(mPresenter).expandTaskFragment(mTransaction, primaryTf.getTaskFragmentToken());
- verify(mPresenter).expandTaskFragment(mTransaction, secondaryTf.getTaskFragmentToken());
+ verify(mPresenter).expandTaskFragment(mTransaction, primaryTf);
+ verify(mPresenter).expandTaskFragment(mTransaction, secondaryTf);
splitContainer.updateCurrentSplitAttributes(SPLIT_ATTRIBUTES);
clearInvocations(mPresenter);
@@ -675,8 +675,8 @@
splitContainer, mActivity, null /* secondaryActivity */,
new Intent(ApplicationProvider.getApplicationContext(),
MinimumDimensionActivity.class)));
- verify(mPresenter).expandTaskFragment(mTransaction, primaryTf.getTaskFragmentToken());
- verify(mPresenter).expandTaskFragment(mTransaction, secondaryTf.getTaskFragmentToken());
+ verify(mPresenter).expandTaskFragment(mTransaction, primaryTf);
+ verify(mPresenter).expandTaskFragment(mTransaction, secondaryTf);
}
@Test
diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp
index 1686d0d..1ad19c9 100644
--- a/libs/WindowManager/Shell/multivalentTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentTests/Android.bp
@@ -46,6 +46,7 @@
exclude_srcs: ["src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt"],
static_libs: [
"junit",
+ "androidx.core_core-animation-testing",
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
@@ -64,6 +65,7 @@
static_libs: [
"WindowManager-Shell",
"junit",
+ "androidx.core_core-animation-testing",
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetControllerTest.kt
new file mode 100644
index 0000000..2ac7791
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetControllerTest.kt
@@ -0,0 +1,180 @@
+/*
+ * 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.wm.shell.bubbles.bar
+
+import android.content.Context
+import android.graphics.Insets
+import android.graphics.Rect
+import android.view.View
+import android.view.WindowManager
+import android.widget.FrameLayout
+import androidx.core.animation.AnimatorTestRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.protolog.common.ProtoLog
+import com.android.wm.shell.R
+import com.android.wm.shell.bubbles.BubblePositioner
+import com.android.wm.shell.bubbles.DeviceConfig
+import com.android.wm.shell.bubbles.bar.BubbleBarDropTargetController.Companion.DROP_TARGET_ALPHA_IN_DURATION
+import com.android.wm.shell.bubbles.bar.BubbleBarDropTargetController.Companion.DROP_TARGET_ALPHA_OUT_DURATION
+import com.android.wm.shell.bubbles.bar.BubbleBarDropTargetController.Companion.DROP_TARGET_SCALE
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [BubbleBarDropTargetController] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubbleBarDropTargetControllerTest {
+
+ companion object {
+ @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule()
+ }
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private lateinit var controller: BubbleBarDropTargetController
+ private lateinit var positioner: BubblePositioner
+ private lateinit var container: FrameLayout
+
+ @Before
+ fun setUp() {
+ ProtoLog.REQUIRE_PROTOLOGTOOL = false
+ container = FrameLayout(context)
+ val windowManager = context.getSystemService(WindowManager::class.java)
+ positioner = BubblePositioner(context, windowManager)
+ positioner.setShowingInBubbleBar(true)
+ val deviceConfig =
+ DeviceConfig(
+ windowBounds = Rect(0, 0, 2000, 2600),
+ isLargeScreen = true,
+ isSmallTablet = false,
+ isLandscape = true,
+ isRtl = false,
+ insets = Insets.of(10, 20, 30, 40)
+ )
+ positioner.update(deviceConfig)
+ positioner.bubbleBarBounds = Rect(1800, 2400, 1970, 2560)
+
+ controller = BubbleBarDropTargetController(context, container, positioner)
+ }
+
+ @Test
+ fun show_moveLeftToRight_isVisibleWithExpectedBounds() {
+ val expectedBoundsOnLeft = getExpectedDropTargetBounds(onLeft = true)
+ val expectedBoundsOnRight = getExpectedDropTargetBounds(onLeft = false)
+
+ runOnMainSync { controller.show(BubbleBarLocation.LEFT) }
+ waitForAnimateIn()
+ val viewOnLeft = getDropTargetView()
+ assertThat(viewOnLeft).isNotNull()
+ assertThat(viewOnLeft!!.alpha).isEqualTo(1f)
+ assertThat(viewOnLeft.layoutParams.width).isEqualTo(expectedBoundsOnLeft.width())
+ assertThat(viewOnLeft.layoutParams.height).isEqualTo(expectedBoundsOnLeft.height())
+ assertThat(viewOnLeft.x).isEqualTo(expectedBoundsOnLeft.left)
+ assertThat(viewOnLeft.y).isEqualTo(expectedBoundsOnLeft.top)
+
+ runOnMainSync { controller.show(BubbleBarLocation.RIGHT) }
+ waitForAnimateOut()
+ waitForAnimateIn()
+ val viewOnRight = getDropTargetView()
+ assertThat(viewOnRight).isNotNull()
+ assertThat(viewOnRight!!.alpha).isEqualTo(1f)
+ assertThat(viewOnRight.layoutParams.width).isEqualTo(expectedBoundsOnRight.width())
+ assertThat(viewOnRight.layoutParams.height).isEqualTo(expectedBoundsOnRight.height())
+ assertThat(viewOnRight.x).isEqualTo(expectedBoundsOnRight.left)
+ assertThat(viewOnRight.y).isEqualTo(expectedBoundsOnRight.top)
+ }
+
+ @Test
+ fun toggleSetHidden_dropTargetShown_updatesAlpha() {
+ runOnMainSync { controller.show(BubbleBarLocation.RIGHT) }
+ waitForAnimateIn()
+ val view = getDropTargetView()
+ assertThat(view).isNotNull()
+ assertThat(view!!.alpha).isEqualTo(1f)
+
+ runOnMainSync { controller.setHidden(true) }
+ waitForAnimateOut()
+ val hiddenView = getDropTargetView()
+ assertThat(hiddenView).isNotNull()
+ assertThat(hiddenView!!.alpha).isEqualTo(0f)
+
+ runOnMainSync { controller.setHidden(false) }
+ waitForAnimateIn()
+ val shownView = getDropTargetView()
+ assertThat(shownView).isNotNull()
+ assertThat(shownView!!.alpha).isEqualTo(1f)
+ }
+
+ @Test
+ fun toggleSetHidden_dropTargetNotShown_viewNotCreated() {
+ runOnMainSync { controller.setHidden(true) }
+ waitForAnimateOut()
+ assertThat(getDropTargetView()).isNull()
+ runOnMainSync { controller.setHidden(false) }
+ waitForAnimateIn()
+ assertThat(getDropTargetView()).isNull()
+ }
+
+ @Test
+ fun dismiss_dropTargetShown_viewRemoved() {
+ runOnMainSync { controller.show(BubbleBarLocation.LEFT) }
+ waitForAnimateIn()
+ assertThat(getDropTargetView()).isNotNull()
+ runOnMainSync { controller.dismiss() }
+ waitForAnimateOut()
+ assertThat(getDropTargetView()).isNull()
+ }
+
+ @Test
+ fun dismiss_dropTargetNotShown_doesNothing() {
+ runOnMainSync { controller.dismiss() }
+ waitForAnimateOut()
+ assertThat(getDropTargetView()).isNull()
+ }
+
+ private fun getDropTargetView(): View? = container.findViewById(R.id.bubble_bar_drop_target)
+
+ private fun getExpectedDropTargetBounds(onLeft: Boolean): Rect {
+ val rect = Rect()
+ positioner.getBubbleBarExpandedViewBounds(onLeft, false /* isOveflowExpanded */, rect)
+ // Scale the rect to expected size, but keep the center point the same
+ val centerX = rect.centerX()
+ val centerY = rect.centerY()
+ rect.scale(DROP_TARGET_SCALE)
+ rect.offset(centerX - rect.centerX(), centerY - rect.centerY())
+ return rect
+ }
+
+ private fun runOnMainSync(runnable: Runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable)
+ }
+
+ private fun waitForAnimateIn() {
+ // Advance animator for on-device test
+ runOnMainSync { animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_IN_DURATION) }
+ }
+
+ private fun waitForAnimateOut() {
+ // Advance animator for on-device test
+ runOnMainSync { animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_OUT_DURATION) }
+ }
+}
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_resize_veil_background.xml b/libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml
similarity index 61%
rename from libs/WindowManager/Shell/res/drawable/desktop_mode_resize_veil_background.xml
rename to libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml
index 1f3e3a4..ab1ab98 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_mode_resize_veil_background.xml
+++ b/libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
@@ -14,7 +13,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape android:shape="rectangle"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@android:color/white" />
-</shape>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:alpha="0.35" android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml b/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml
index 468b5c2..9dcde3b 100644
--- a/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2024 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +13,12 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape android:shape="rectangle"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="#bf309fb5" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
<corners android:radius="@dimen/bubble_bar_expanded_view_corner_radius" />
- <stroke android:width="1dp" android:color="#A00080FF"/>
+ <solid android:color="@color/bubble_drop_target_background_color" />
+ <stroke
+ android:width="1dp"
+ android:color="?androidprv:attr/materialColorPrimaryContainer" />
</shape>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_resize_veil.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_resize_veil.xml
index a4bbd89..147f991 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_resize_veil.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_resize_veil.xml
@@ -16,13 +16,12 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/desktop_mode_resize_veil_background">
+ android:layout_height="match_parent">
<ImageView
android:id="@+id/veil_application_icon"
- android:layout_width="96dp"
- android:layout_height="96dp"
+ android:layout_width="@dimen/desktop_mode_resize_veil_icon_size"
+ android:layout_height="@dimen/desktop_mode_resize_veil_icon_size"
android:layout_gravity="center"
android:contentDescription="@string/app_icon_text" />
</FrameLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index f7d49908..9a26b7e 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -35,7 +35,7 @@
<string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"à€¯à¥ à€à€ª à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€®à¥à€¡à€®à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€š à€®à€¿à€²à¥à€Šà¥à€š"</string>
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"à€¯à¥ à€à€ª à€à€à€à€Ÿ à€µà€¿à€šà¥à€¡à¥à€®à€Ÿ à€®à€Ÿà€€à¥à€° à€à¥à€²à¥à€š à€®à€¿à€²à¥à€"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"à€¯à¥ à€à€ªà€²à¥ à€žà€¹à€Ÿà€¯à€ à€ªà¥à€°à€Šà€°à¥à€¶à€šà€®à€Ÿ à€à€Ÿà€® à€šà€à€°à¥à€šà€žà€à¥à€à¥€"</string>
- <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"à€
à€šà¥à€ªà¥à€°à€¯à¥à€à€²à¥ à€žà€¹à€Ÿà€¯à€ à€ªà¥à€°à€Šà€°à¥à€¶à€šà€¹à€°à¥à€®à€Ÿ à€²à€à¥à€ à€žà¥à€µà€¿à€§à€Ÿà€²à€Ÿà€ à€žà€®à€°à¥à€¥à€š à€à€°à¥à€Šà¥à€šà¥€"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"à€à€ªà€²à¥ à€žà€¹à€Ÿà€¯à€ à€ªà¥à€°à€Šà€°à¥à€¶à€šà€¹à€°à¥à€®à€Ÿ à€²à€à¥à€ à€žà¥à€µà€¿à€§à€Ÿà€²à€Ÿà€ à€žà€®à€°à¥à€¥à€š à€à€°à¥à€Šà¥à€šà¥€"</string>
<string name="accessibility_divider" msgid="6407584574218956849">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€¡à€¿à€à€Ÿà€à€¡à€°"</string>
<string name="divider_title" msgid="1963391955593749442">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€¡à€¿à€à€Ÿà€à€¡à€°"</string>
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"à€¬à€Ÿà€¯à€Ÿà€ à€à€Ÿà€ à€«à¥à€² à€žà¥à€à¥à€°à€¿à€š"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 43ce166..70371f6 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -213,7 +213,7 @@
<dimen name="bubble_swap_animation_offset">15dp</dimen>
<!-- How far offscreen the bubble stack rests. There's some padding around the bubble so
add 3dp to the desired overhang. -->
- <dimen name="bubble_stack_offscreen">3dp</dimen>
+ <dimen name="bubble_stack_offscreen">2.5dp</dimen>
<!-- How far down the screen the stack starts. -->
<dimen name="bubble_stack_starting_offset_y">120dp</dimen>
<!-- Space between the pointer triangle and the bubble expanded view -->
@@ -506,6 +506,9 @@
<!-- The radius of the caption menu shadow. -->
<dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen>
+ <!-- The size of the icon shown in the resize veil. -->
+ <dimen name="desktop_mode_resize_veil_icon_size">96dp</dimen>
+
<dimen name="freeform_resize_handle">15dp</dimen>
<dimen name="freeform_resize_corner">44dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetController.kt
index 55ec6cd..f6b4653 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDropTargetController.kt
@@ -21,6 +21,10 @@
import android.view.View
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
+import androidx.annotation.VisibleForTesting
+import androidx.core.animation.Animator
+import androidx.core.animation.AnimatorListenerAdapter
+import androidx.core.animation.ObjectAnimator
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.common.bubbles.BubbleBarLocation
@@ -33,6 +37,7 @@
) {
private var dropTargetView: View? = null
+ private var animator: ObjectAnimator? = null
private val tempRect: Rect by lazy(LazyThreadSafetyMode.NONE) { Rect() }
/**
@@ -57,7 +62,8 @@
/**
* Set the view hidden or not
*
- * Requires the drop target to be first shown by calling [show]. Otherwise does not do anything.
+ * Requires the drop target to be first shown by calling [animateIn]. Otherwise does not do
+ * anything.
*/
fun setHidden(hidden: Boolean) {
val targetView = dropTargetView ?: return
@@ -106,20 +112,40 @@
}
private fun View.animateIn() {
- animate().alpha(1f).setDuration(DROP_TARGET_ALPHA_IN_DURATION).start()
+ animator?.cancel()
+ animator =
+ ObjectAnimator.ofFloat(this, View.ALPHA, 1f)
+ .setDuration(DROP_TARGET_ALPHA_IN_DURATION)
+ .addEndAction { animator = null }
+ animator?.start()
}
private fun View.animateOut(endAction: Runnable? = null) {
- animate()
- .alpha(0f)
- .setDuration(DROP_TARGET_ALPHA_OUT_DURATION)
- .withEndAction(endAction)
- .start()
+ animator?.cancel()
+ animator =
+ ObjectAnimator.ofFloat(this, View.ALPHA, 0f)
+ .setDuration(DROP_TARGET_ALPHA_OUT_DURATION)
+ .addEndAction {
+ endAction?.run()
+ animator = null
+ }
+ animator?.start()
+ }
+
+ private fun <T : Animator> T.addEndAction(runnable: Runnable): T {
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ runnable.run()
+ }
+ }
+ )
+ return this
}
companion object {
- private const val DROP_TARGET_ALPHA_IN_DURATION = 150L
- private const val DROP_TARGET_ALPHA_OUT_DURATION = 100L
- private const val DROP_TARGET_SCALE = 0.9f
+ @VisibleForTesting const val DROP_TARGET_ALPHA_IN_DURATION = 150L
+ @VisibleForTesting const val DROP_TARGET_ALPHA_OUT_DURATION = 100L
+ @VisibleForTesting const val DROP_TARGET_SCALE = 0.9f
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
index 4c34971..9e8dfb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
@@ -21,11 +21,9 @@
import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.os.UserHandle
-import android.view.WindowManager
import android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.R
-import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL
import com.android.wm.shell.util.KtProtoLog
import java.util.Arrays
@@ -37,7 +35,8 @@
private val context: Context,
private val packageManager: PackageManager,
private val staticAppsSupportingMultiInstance: Array<String> = context.resources
- .getStringArray(R.array.config_appsSupportMultiInstancesSplit)) {
+ .getStringArray(R.array.config_appsSupportMultiInstancesSplit),
+ private val supportsMultiInstanceProperty: Boolean) {
/**
* Returns whether a specific component desires to be launched in multiple instances.
@@ -59,6 +58,11 @@
}
}
+ if (!supportsMultiInstanceProperty) {
+ // If not checking the multi-instance properties, then return early
+ return false;
+ }
+
// Check the activity property first
try {
val activityProp = packageManager.getProperty(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index e4cf6d1..98dccbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -48,6 +48,7 @@
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import android.window.InputTransferToken;
@@ -348,7 +349,7 @@
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId,
- boolean dragResizing) {}
+ boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {}
@Override
public void insetsControlChanged(InsetsState insetsState,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 8d489e1..5122114 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -29,6 +29,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.launcher3.icons.IconProvider;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ProtoLogController;
import com.android.wm.shell.R;
import com.android.wm.shell.RootDisplayAreaOrganizer;
@@ -326,7 +327,8 @@
@WMSingleton
@Provides
static MultiInstanceHelper provideMultiInstanceHelper(Context context) {
- return new MultiInstanceHelper(context, context.getPackageManager());
+ return new MultiInstanceHelper(context, context.getPackageManager(),
+ Flags.supportsMultiInstanceSystemUi());
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 838603f..5889da1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -49,7 +49,7 @@
/** Called when requested to go to desktop mode from the current focused app. */
- void enterDesktop(int displayId);
+ void moveFocusedTaskToDesktop(int displayId);
/** Called when requested to go to fullscreen from the current focused desktop app. */
void moveFocusedTaskToFullscreen(int displayId);
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 992e5ae..1b1c967 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
@@ -263,7 +263,7 @@
}
/** Enter desktop by using the focused task in given `displayId` */
- fun enterDesktop(displayId: Int) {
+ fun moveFocusedTaskToDesktop(displayId: Int) {
val allFocusedTasks =
shellTaskOrganizer.getRunningTasks(displayId).filter { taskInfo ->
taskInfo.isFocused &&
@@ -1166,7 +1166,7 @@
pendingIntentLaunchFlags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED
)
isPendingIntentBackgroundActivityLaunchAllowedByPermission = true
}
@@ -1212,9 +1212,9 @@
}
}
- override fun enterDesktop(displayId: Int) {
+ override fun moveFocusedTaskToDesktop(displayId: Int) {
mainExecutor.execute {
- this@DesktopTasksController.enterDesktop(displayId)
+ this@DesktopTasksController.moveFocusedTaskToDesktop(displayId)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index af26e29..b830a41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -15,6 +15,7 @@
import android.content.Intent
import android.content.Intent.FILL_IN_COMPONENT
import android.graphics.Rect
+import android.os.Bundle
import android.os.IBinder
import android.os.SystemClock
import android.view.SurfaceControl
@@ -124,7 +125,7 @@
options.toBundle()
)
val wct = WindowContainerTransaction()
- wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle())
+ wct.sendPendingIntent(pendingIntent, launchHomeIntent, Bundle())
val startTransitionToken = transitions
.startTransition(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, wct, this)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index eb82da8..6a7d297 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.draganddrop;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
@@ -301,16 +302,14 @@
position);
final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true);
+ baseActivityOpts.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_DENIED);
// TODO(b/255649902): Rework this so that SplitScreenController can always use the options
// instead of a fillInIntent since it's assuming that the PendingIntent is mutable
baseActivityOpts.setPendingIntentLaunchFlags(FLAG_ACTIVITY_NEW_TASK
| FLAG_ACTIVITY_MULTIPLE_TASK);
final Bundle opts = baseActivityOpts.toBundle();
- // Put BAL flags to avoid activity start aborted.
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
-
mStarter.startIntent(session.launchableIntent,
session.launchableIntent.getCreatorUserHandle().getIdentifier(),
null /* fillIntent */, position, opts);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 62156fc..6b5bdd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -64,6 +64,8 @@
private TvPipBackgroundView mPipBackgroundView;
private boolean mIsReloading;
+ private static final int PIP_MENU_FORCE_CLOSE_DELAY_MS = 10_000;
+ private final Runnable mClosePipMenuRunnable = this::closeMenu;
@TvPipMenuMode
private int mCurrentMenuMode = MODE_NO_MENU;
@@ -280,6 +282,7 @@
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: closeMenu()", TAG);
requestMenuMode(MODE_NO_MENU);
+ mMainHandler.removeCallbacks(mClosePipMenuRunnable);
}
@Override
@@ -488,13 +491,17 @@
private void requestMenuMode(@TvPipMenuMode int menuMode) {
if (isMenuOpen() == isMenuOpen(menuMode)) {
+ if (mMainHandler.hasCallbacks(mClosePipMenuRunnable)) {
+ mMainHandler.removeCallbacks(mClosePipMenuRunnable);
+ mMainHandler.postDelayed(mClosePipMenuRunnable, PIP_MENU_FORCE_CLOSE_DELAY_MS);
+ }
// No need to request a focus change. We can directly switch to the new mode.
switchToMenuMode(menuMode);
} else {
if (isMenuOpen(menuMode)) {
+ mMainHandler.postDelayed(mClosePipMenuRunnable, PIP_MENU_FORCE_CLOSE_DELAY_MS);
mMenuModeOnFocus = menuMode;
}
-
// Send a request to gain window focus if the menu is open, or lose window focus
// otherwise. Once the focus change happens, we will request the new mode in the
// callback {@link #onPipWindowFocusChanged}.
@@ -584,6 +591,14 @@
}
@Override
+ public void onUserInteracting() {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onUserInteracting - mCurrentMenuMode=%s", TAG, getMenuModeString());
+ mMainHandler.removeCallbacks(mClosePipMenuRunnable);
+ mMainHandler.postDelayed(mClosePipMenuRunnable, PIP_MENU_FORCE_CLOSE_DELAY_MS);
+
+ }
+ @Override
public void onPipMovement(int keycode) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: onPipMovement - mCurrentMenuMode=%s", TAG, getMenuModeString());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index b259e8d..4a767ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -491,30 +491,33 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP) {
-
if (event.getKeyCode() == KEYCODE_BACK) {
mListener.onExitCurrentMenuMode();
return true;
}
-
- if (mCurrentMenuMode == MODE_MOVE_MENU && !mA11yManager.isEnabled()) {
- switch (event.getKeyCode()) {
- case KEYCODE_DPAD_UP:
- case KEYCODE_DPAD_DOWN:
- case KEYCODE_DPAD_LEFT:
- case KEYCODE_DPAD_RIGHT:
+ switch (event.getKeyCode()) {
+ case KEYCODE_DPAD_UP:
+ case KEYCODE_DPAD_DOWN:
+ case KEYCODE_DPAD_LEFT:
+ case KEYCODE_DPAD_RIGHT:
+ mListener.onUserInteracting();
+ if (mCurrentMenuMode == MODE_MOVE_MENU && !mA11yManager.isEnabled()) {
mListener.onPipMovement(event.getKeyCode());
return true;
- case KEYCODE_ENTER:
- case KEYCODE_DPAD_CENTER:
+ }
+ break;
+ case KEYCODE_ENTER:
+ case KEYCODE_DPAD_CENTER:
+ mListener.onUserInteracting();
+ if (mCurrentMenuMode == MODE_MOVE_MENU && !mA11yManager.isEnabled()) {
mListener.onExitCurrentMenuMode();
return true;
- default:
- // Dispatch key event as normal below
- }
+ }
+ break;
+ default:
+ // Dispatch key event as normal below
}
}
-
return super.dispatchKeyEvent(event);
}
@@ -637,6 +640,11 @@
interface Listener {
/**
+ * Called when any button (that affects the menu) on current menu mode was pressed.
+ */
+ void onUserInteracting();
+
+ /**
* Called when a button for exiting the current menu mode was pressed.
*/
void onExitCurrentMenuMode();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 1a0c011..ceac40d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -23,6 +23,7 @@
import android.annotation.BinderThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.graphics.Paint;
@@ -42,6 +43,7 @@
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import android.window.SnapshotDrawerUtils;
import android.window.StartingWindowInfo;
@@ -214,7 +216,7 @@
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, InsetsState insetsState,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int seqId,
- boolean dragResizing) {
+ boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {
final TaskSnapshotWindow snapshot = mOuter.get();
if (snapshot == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 9130edf..74e85f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -334,6 +334,7 @@
boolean isDisplayRotationAnimationStarted = false;
final boolean isDreamTransition = isDreamTransition(info);
final boolean isOnlyTranslucent = isOnlyTranslucent(info);
+ final boolean isActivityLevel = isActivityLevelOnly(info);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -502,8 +503,35 @@
: new Rect(change.getEndAbsBounds());
clipRect.offsetTo(0, 0);
+ final TransitionInfo.Root animRoot = TransitionUtil.getRootFor(change, info);
+ final Point animRelOffset = new Point(
+ change.getEndAbsBounds().left - animRoot.getOffset().x,
+ change.getEndAbsBounds().top - animRoot.getOffset().y);
+ if (change.getActivityComponent() != null && !isActivityLevel) {
+ // At this point, this is an independent activity change in a non-activity
+ // transition. This means that an activity transition got erroneously combined
+ // with another ongoing transition. This then means that the animation root may
+ // not tightly fit the activities, so we have to put them in a separate crop.
+ final int layer = Transitions.calculateAnimLayer(change, i,
+ info.getChanges().size(), info.getType());
+ final SurfaceControl leash = new SurfaceControl.Builder()
+ .setName("Transition ActivityWrap: "
+ + change.getActivityComponent().toShortString())
+ .setParent(animRoot.getLeash())
+ .setContainerLayer().build();
+ startTransaction.setCrop(leash, clipRect);
+ startTransaction.setPosition(leash, animRelOffset.x, animRelOffset.y);
+ startTransaction.setLayer(leash, layer);
+ startTransaction.show(leash);
+ startTransaction.reparent(change.getLeash(), leash);
+ startTransaction.setPosition(change.getLeash(), 0, 0);
+ animRelOffset.set(0, 0);
+ finishTransaction.reparent(leash, null);
+ leash.release();
+ }
+
buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
- mTransactionPool, mMainExecutor, change.getEndRelOffset(), cornerRadius,
+ mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
clipRect);
if (info.getAnimationOptions() != null) {
@@ -612,6 +640,18 @@
return (translucentOpen + translucentClose) > 0;
}
+ /**
+ * Does `info` only contain activity-level changes? This kinda assumes that if so, they are
+ * all in one task.
+ */
+ private static boolean isActivityLevelOnly(@NonNull TransitionInfo info) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getActivityComponent() == null) return false;
+ }
+ return true;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index ccd0b2d..a77602b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -31,7 +31,6 @@
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
-import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -496,6 +495,7 @@
if (mode == TRANSIT_TO_FRONT) {
// When the window is moved to front, make sure the crop is updated to prevent it
// from using the old crop.
+ t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
t.setWindowCrop(leash, change.getEndAbsBounds().width(),
change.getEndAbsBounds().height());
}
@@ -507,6 +507,8 @@
t.setMatrix(leash, 1, 0, 0, 1);
t.setAlpha(leash, 1.f);
t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
+ t.setWindowCrop(leash, change.getEndAbsBounds().width(),
+ change.getEndAbsBounds().height());
}
continue;
}
@@ -530,6 +532,44 @@
}
}
+ static int calculateAnimLayer(@NonNull TransitionInfo.Change change, int i,
+ int numChanges, @WindowManager.TransitionType int transitType) {
+ // Put animating stuff above this line and put static stuff below it.
+ final int zSplitLine = numChanges + 1;
+ final boolean isOpening = isOpeningType(transitType);
+ final boolean isClosing = isClosingType(transitType);
+ final int mode = change.getMode();
+ // Put all the OPEN/SHOW on top
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ if (isOpening
+ // This is for when an activity launches while a different transition is
+ // collecting.
+ || change.hasFlags(FLAG_MOVED_TO_TOP)) {
+ // put on top
+ return zSplitLine + numChanges - i;
+ } else {
+ // put on bottom
+ return zSplitLine - i;
+ }
+ } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
+ if (isOpening) {
+ // put on bottom and leave visible
+ return zSplitLine - i;
+ } else {
+ // put on top
+ return zSplitLine + numChanges - i;
+ }
+ } else { // CHANGE or other
+ if (isClosing || TransitionUtil.isOrderOnly(change)) {
+ // Put below CLOSE mode (in the "static" section).
+ return zSplitLine - i;
+ } else {
+ // Put above CLOSE mode.
+ return zSplitLine + numChanges - i;
+ }
+ }
+ }
+
/**
* Reparents all participants into a shared parent and orders them based on: the global transit
* type, their transit mode, and their destination z-order.
@@ -537,19 +577,14 @@
private static void setupAnimHierarchy(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
final int type = info.getType();
- final boolean isOpening = isOpeningType(type);
- final boolean isClosing = isClosingType(type);
for (int i = 0; i < info.getRootCount(); ++i) {
t.show(info.getRoot(i).getLeash());
}
final int numChanges = info.getChanges().size();
- // Put animating stuff above this line and put static stuff below it.
- final int zSplitLine = numChanges + 1;
// changes should be ordered top-to-bottom in z
for (int i = numChanges - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = change.getLeash();
- final int mode = change.getMode();
// Don't reparent anything that isn't independent within its parents
if (!TransitionInfo.isIndependent(change, info)) {
@@ -558,50 +593,14 @@
boolean hasParent = change.getParent() != null;
- final int rootIdx = TransitionUtil.rootIndexFor(change, info);
+ final TransitionInfo.Root root = TransitionUtil.getRootFor(change, info);
if (!hasParent) {
- t.reparent(leash, info.getRoot(rootIdx).getLeash());
+ t.reparent(leash, root.getLeash());
t.setPosition(leash,
- change.getStartAbsBounds().left - info.getRoot(rootIdx).getOffset().x,
- change.getStartAbsBounds().top - info.getRoot(rootIdx).getOffset().y);
+ change.getStartAbsBounds().left - root.getOffset().x,
+ change.getStartAbsBounds().top - root.getOffset().y);
}
- final int layer;
- // Put all the OPEN/SHOW on top
- if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
- // Wallpaper is always at the bottom, opening wallpaper on top of closing one.
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
- layer = -zSplitLine + numChanges - i;
- } else {
- layer = -zSplitLine - i;
- }
- } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
- if (isOpening
- // This is for when an activity launches while a different transition is
- // collecting.
- || change.hasFlags(FLAG_MOVED_TO_TOP)) {
- // put on top
- layer = zSplitLine + numChanges - i;
- } else {
- // put on bottom
- layer = zSplitLine - i;
- }
- } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
- if (isOpening) {
- // put on bottom and leave visible
- layer = zSplitLine - i;
- } else {
- // put on top
- layer = zSplitLine + numChanges - i;
- }
- } else { // CHANGE or other
- if (isClosing || TransitionUtil.isOrderOnly(change)) {
- // Put below CLOSE mode (in the "static" section).
- layer = zSplitLine - i;
- } else {
- // Put above CLOSE mode.
- layer = zSplitLine + numChanges - i;
- }
- }
+ final int layer = calculateAnimLayer(change, i, numChanges, type);
t.setLayer(leash, layer);
}
}
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 4c9e171..ad290c6 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
@@ -451,7 +451,7 @@
* until a resize event calls showResizeVeil below.
*/
void createResizeVeil() {
- mResizeVeil = new ResizeVeil(mContext, mAppIconDrawable, mTaskInfo,
+ mResizeVeil = new ResizeVeil(mContext, mAppIconDrawable, mTaskInfo, mTaskSurface,
mSurfaceControlBuilderSupplier, mDisplay, mSurfaceControlTransactionSupplier);
}
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 6f8b3d5..76096b0 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
@@ -18,6 +18,7 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
@@ -178,10 +179,11 @@
for (TransitionInfo.Change change: info.getChanges()) {
final SurfaceControl sc = change.getLeash();
final Rect endBounds = change.getEndAbsBounds();
+ final Point endPosition = change.getEndRelOffset();
startTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height())
- .setPosition(sc, endBounds.left, endBounds.top);
+ .setPosition(sc, endPosition.x, endPosition.y);
finishTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height())
- .setPosition(sc, endBounds.left, endBounds.top);
+ .setPosition(sc, endPosition.x, endPosition.y);
}
startTransaction.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index b0d3b50..d072f8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -23,13 +23,16 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
@@ -37,6 +40,7 @@
import android.window.TaskConstants;
import com.android.wm.shell.R;
+import com.android.wm.shell.common.SurfaceUtils;
import java.util.function.Supplier;
@@ -45,19 +49,36 @@
*/
public class ResizeVeil {
private static final int RESIZE_ALPHA_DURATION = 100;
+
+ private static final int VEIL_CONTAINER_LAYER = TaskConstants.TASK_CHILD_LAYER_RESIZE_VEIL;
+ /** The background is a child of the veil container layer and goes at the bottom. */
+ private static final int VEIL_BACKGROUND_LAYER = 0;
+ /** The icon is a child of the veil container layer and goes in front of the background. */
+ private static final int VEIL_ICON_LAYER = 1;
+
private final Context mContext;
private final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
+ private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final Drawable mAppIcon;
private ImageView mIconView;
+ private int mIconSize;
private SurfaceControl mParentSurface;
+
+ /** A container surface to host the veil background and icon child surfaces. */
private SurfaceControl mVeilSurface;
+ /** A color surface for the veil background. */
+ private SurfaceControl mBackgroundSurface;
+ /** A surface that hosts a windowless window with the app icon. */
+ private SurfaceControl mIconSurface;
+
private final RunningTaskInfo mTaskInfo;
private SurfaceControlViewHost mViewHost;
private final Display mDisplay;
private ValueAnimator mVeilAnimator;
public ResizeVeil(Context context, Drawable appIcon, RunningTaskInfo taskInfo,
+ SurfaceControl taskSurface,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, Display display,
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier) {
mContext = context;
@@ -65,6 +86,7 @@
mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier;
mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mTaskInfo = taskInfo;
+ mParentSurface = taskSurface;
mDisplay = display;
setupResizeVeil();
}
@@ -73,34 +95,44 @@
* Create the veil in its default invisible state.
*/
private void setupResizeVeil() {
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
- mVeilSurface = builder
- .setName("Resize veil of Task= " + mTaskInfo.taskId)
+ mVeilSurface = mSurfaceControlBuilderSupplier.get()
.setContainerLayer()
+ .setName("Resize veil of Task=" + mTaskInfo.taskId)
+ .setHidden(true)
+ .setParent(mParentSurface)
+ .setCallsite("ResizeVeil#setupResizeVeil")
.build();
- View v = LayoutInflater.from(mContext)
- .inflate(R.layout.desktop_mode_resize_veil, null);
+ mBackgroundSurface = SurfaceUtils.makeColorLayer(mVeilSurface,
+ "Resize veil background of Task=" + mTaskInfo.taskId, mSurfaceSession);
+ mIconSurface = mSurfaceControlBuilderSupplier.get()
+ .setName("Resize veil icon of Task= " + mTaskInfo.taskId)
+ .setContainerLayer()
+ .setParent(mVeilSurface)
+ .setHidden(true)
+ .setCallsite("ResizeVeil#setupResizeVeil")
+ .build();
- t.setPosition(mVeilSurface, 0, 0)
- .setLayer(mVeilSurface, TaskConstants.TASK_CHILD_LAYER_RESIZE_VEIL)
- .apply();
- Rect taskBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ mIconSize = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.desktop_mode_resize_veil_icon_size);
+ final View root = LayoutInflater.from(mContext)
+ .inflate(R.layout.desktop_mode_resize_veil, null /* root */);
+ mIconView = root.findViewById(R.id.veil_application_icon);
+ mIconView.setImageDrawable(mAppIcon);
+
final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(taskBounds.width(),
- taskBounds.height(),
+ new WindowManager.LayoutParams(
+ mIconSize,
+ mIconSize,
WindowManager.LayoutParams.TYPE_APPLICATION,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
- lp.setTitle("Resize veil of Task=" + mTaskInfo.taskId);
+ lp.setTitle("Resize veil icon window of Task=" + mTaskInfo.taskId);
lp.setTrustedOverlay();
- WindowlessWindowManager windowManager = new WindowlessWindowManager(mTaskInfo.configuration,
- mVeilSurface, null /* hostInputToken */);
- mViewHost = new SurfaceControlViewHost(mContext, mDisplay, windowManager, "ResizeVeil");
- mViewHost.setView(v, lp);
- mIconView = mViewHost.getView().findViewById(R.id.veil_application_icon);
- mIconView.setImageDrawable(mAppIcon);
+ final WindowlessWindowManager wwm = new WindowlessWindowManager(mTaskInfo.configuration,
+ mIconSurface, null /* hostInputToken */);
+ mViewHost = new SurfaceControlViewHost(mContext, mDisplay, wwm, "ResizeVeil");
+ mViewHost.setView(root, lp);
}
/**
@@ -120,46 +152,74 @@
mParentSurface = parentSurface;
}
- int backgroundColorId = getBackgroundColorId();
- mViewHost.getView().setBackgroundColor(mContext.getColor(backgroundColorId));
+ t.show(mVeilSurface);
+ t.setLayer(mVeilSurface, VEIL_CONTAINER_LAYER);
+ t.setLayer(mIconSurface, VEIL_ICON_LAYER);
+ t.setLayer(mBackgroundSurface, VEIL_BACKGROUND_LAYER);
+ t.setColor(mBackgroundSurface,
+ Color.valueOf(mContext.getColor(getBackgroundColorId())).getComponents());
relayout(taskBounds, t);
if (fadeIn) {
cancelAnimation();
+ final SurfaceControl.Transaction veilAnimT = mSurfaceControlTransactionSupplier.get();
mVeilAnimator = new ValueAnimator();
mVeilAnimator.setFloatValues(0f, 1f);
mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
mVeilAnimator.addUpdateListener(animation -> {
- t.setAlpha(mVeilSurface, mVeilAnimator.getAnimatedFraction());
- t.apply();
+ veilAnimT.setAlpha(mBackgroundSurface, mVeilAnimator.getAnimatedFraction());
+ veilAnimT.apply();
});
mVeilAnimator.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ veilAnimT.show(mBackgroundSurface)
+ .setAlpha(mBackgroundSurface, 0)
+ .apply();
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
- t.setAlpha(mVeilSurface, 1);
- t.apply();
+ veilAnimT.setAlpha(mBackgroundSurface, 1).apply();
}
});
+ final SurfaceControl.Transaction iconAnimT = mSurfaceControlTransactionSupplier.get();
final ValueAnimator iconAnimator = new ValueAnimator();
iconAnimator.setFloatValues(0f, 1f);
iconAnimator.setDuration(RESIZE_ALPHA_DURATION);
iconAnimator.addUpdateListener(animation -> {
- mIconView.setAlpha(animation.getAnimatedFraction());
+ iconAnimT.setAlpha(mIconSurface, animation.getAnimatedFraction());
+ iconAnimT.apply();
});
+ iconAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ iconAnimT.show(mIconSurface)
+ .setAlpha(mIconSurface, 0)
+ .apply();
+ }
- t.show(mVeilSurface)
- .addTransactionCommittedListener(
- mContext.getMainExecutor(), () -> {
- mVeilAnimator.start();
- iconAnimator.start();
- })
- .setAlpha(mVeilSurface, 0);
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ iconAnimT.setAlpha(mIconSurface, 1).apply();
+ }
+ });
+ // Let the animators show it with the correct alpha value once the animation starts.
+ t.hide(mIconSurface);
+ t.hide(mBackgroundSurface);
+ t.apply();
+
+ mVeilAnimator.start();
+ iconAnimator.start();
} else {
- // Show the veil immediately at full opacity.
- t.show(mVeilSurface).setAlpha(mVeilSurface, 1);
+ // Show the veil immediately.
+ t.show(mIconSurface);
+ t.show(mBackgroundSurface);
+ t.setAlpha(mIconSurface, 1);
+ t.setAlpha(mBackgroundSurface, 1);
+ t.apply();
}
- mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
/**
@@ -175,8 +235,9 @@
* @param newBounds bounds to update veil to.
*/
private void relayout(Rect newBounds, SurfaceControl.Transaction t) {
- mViewHost.relayout(newBounds.width(), newBounds.height());
t.setWindowCrop(mVeilSurface, newBounds.width(), newBounds.height());
+ final PointF iconPosition = calculateAppIconPosition(newBounds);
+ t.setPosition(mIconSurface, iconPosition.x, iconPosition.y);
t.setPosition(mParentSurface, newBounds.left, newBounds.top);
t.setWindowCrop(mParentSurface, newBounds.width(), newBounds.height());
}
@@ -204,7 +265,7 @@
mVeilAnimator.end();
}
relayout(newBounds, t);
- mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
+ t.apply();
}
/**
@@ -217,14 +278,16 @@
mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
mVeilAnimator.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.setAlpha(mVeilSurface, 1 - mVeilAnimator.getAnimatedFraction());
+ t.setAlpha(mBackgroundSurface, 1 - mVeilAnimator.getAnimatedFraction());
+ t.setAlpha(mIconSurface, 1 - mVeilAnimator.getAnimatedFraction());
t.apply();
});
mVeilAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.hide(mVeilSurface);
+ t.hide(mBackgroundSurface);
+ t.hide(mIconSurface);
t.apply();
}
});
@@ -242,6 +305,11 @@
}
}
+ private PointF calculateAppIconPosition(Rect parentBounds) {
+ return new PointF((float) parentBounds.width() / 2 - (float) mIconSize / 2,
+ (float) parentBounds.height() / 2 - (float) mIconSize / 2);
+ }
+
private void cancelAnimation() {
if (mVeilAnimator != null) {
mVeilAnimator.removeAllUpdateListeners();
@@ -260,11 +328,19 @@
mViewHost.release();
mViewHost = null;
}
+ final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+ if (mBackgroundSurface != null) {
+ t.remove(mBackgroundSurface);
+ mBackgroundSurface = null;
+ }
+ if (mIconSurface != null) {
+ t.remove(mIconSurface);
+ mIconSurface = null;
+ }
if (mVeilSurface != null) {
- final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
t.remove(mVeilSurface);
mVeilSurface = null;
- t.apply();
}
+ t.apply();
}
}
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 c12a93e..5fce5d2 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
@@ -18,6 +18,7 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
@@ -179,10 +180,11 @@
for (TransitionInfo.Change change: info.getChanges()) {
final SurfaceControl sc = change.getLeash();
final Rect endBounds = change.getEndAbsBounds();
+ final Point endPosition = change.getEndRelOffset();
startTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height())
- .setPosition(sc, endBounds.left, endBounds.top);
+ .setPosition(sc, endPosition.x, endPosition.y);
finishTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height())
- .setPosition(sc, endBounds.left, endBounds.top);
+ .setPosition(sc, endPosition.x, endPosition.y);
}
startTransaction.apply();
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 1ccc7d8..5f25d70 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -24,6 +24,7 @@
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.helpers.WindowUtils
import android.tools.traces.parsers.toFlickerComponent
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -181,6 +182,12 @@
}
}
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 312446524)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
index 2f5fe11..bec91e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
@@ -32,9 +32,12 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.eq
+import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@@ -77,7 +80,7 @@
@Test
fun supportsMultiInstanceSplit_inStaticAllowList() {
val allowList = arrayOf(TEST_PACKAGE)
- val helper = MultiInstanceHelper(mContext, context.packageManager, allowList)
+ val helper = MultiInstanceHelper(mContext, context.packageManager, allowList, true)
val component = ComponentName(TEST_PACKAGE, TEST_ACTIVITY)
assertEquals(true, helper.supportsMultiInstanceSplit(component))
}
@@ -85,7 +88,7 @@
@Test
fun supportsMultiInstanceSplit_notInStaticAllowList() {
val allowList = arrayOf(TEST_PACKAGE)
- val helper = MultiInstanceHelper(mContext, context.packageManager, allowList)
+ val helper = MultiInstanceHelper(mContext, context.packageManager, allowList, true)
val component = ComponentName(TEST_NOT_ALLOWED_PACKAGE, TEST_ACTIVITY)
assertEquals(false, helper.supportsMultiInstanceSplit(component))
}
@@ -104,7 +107,7 @@
eq(component.packageName)))
.thenReturn(appProp)
- val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+ val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
// Expect activity property to override application property
assertEquals(true, helper.supportsMultiInstanceSplit(component))
}
@@ -123,7 +126,7 @@
eq(component.packageName)))
.thenReturn(appProp)
- val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+ val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
// Expect activity property to override application property
assertEquals(false, helper.supportsMultiInstanceSplit(component))
}
@@ -141,7 +144,7 @@
eq(component.packageName)))
.thenReturn(appProp)
- val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+ val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
// Expect fall through to app property
assertEquals(true, helper.supportsMultiInstanceSplit(component))
}
@@ -158,10 +161,30 @@
eq(component.packageName)))
.thenThrow(PackageManager.NameNotFoundException())
- val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+ val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
assertEquals(false, helper.supportsMultiInstanceSplit(component))
}
+ @Test
+ @Throws(PackageManager.NameNotFoundException::class)
+ fun checkNoMultiInstancePropertyFlag_ignoreProperty() {
+ val component = ComponentName(TEST_PACKAGE, TEST_ACTIVITY)
+ val pm = mock<PackageManager>()
+ val activityProp = PackageManager.Property("", true, "", "")
+ whenever(pm.getProperty(eq(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI),
+ eq(component)))
+ .thenReturn(activityProp)
+ val appProp = PackageManager.Property("", true, "", "")
+ whenever(pm.getProperty(eq(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI),
+ eq(component.packageName)))
+ .thenReturn(appProp)
+
+ val helper = MultiInstanceHelper(mContext, pm, emptyArray(), false)
+ // Expect we only check the static list and not the property
+ assertEquals(false, helper.supportsMultiInstanceSplit(component))
+ verify(pm, never()).getProperty(any(), any<ComponentName>())
+ }
+
companion object {
val TEST_PACKAGE = "com.android.wm.shell.common"
val TEST_NOT_ALLOWED_PACKAGE = "com.android.wm.shell.common.fake";
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 254bf7d..4fbf2bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -833,7 +833,7 @@
verify(launchAdjacentController).launchAdjacentEnabled = true
}
@Test
- fun enterDesktop_fullscreenTaskIsMovedToDesktop() {
+ fun moveFocusedTaskToDesktop_fullscreenTaskIsMovedToDesktop() {
val task1 = setUpFullscreenTask()
val task2 = setUpFullscreenTask()
val task3 = setUpFullscreenTask()
@@ -842,7 +842,7 @@
task2.isFocused = false
task3.isFocused = false
- controller.enterDesktop(DEFAULT_DISPLAY)
+ controller.moveFocusedTaskToDesktop(DEFAULT_DISPLAY)
val wct = getLatestMoveToDesktopWct()
assertThat(wct.changes[task1.token.asBinder()]?.windowingMode)
@@ -850,7 +850,7 @@
}
@Test
- fun enterDesktop_splitScreenTaskIsMovedToDesktop() {
+ fun moveFocusedTaskToDesktop_splitScreenTaskIsMovedToDesktop() {
val task1 = setUpSplitScreenTask()
val task2 = setUpFullscreenTask()
val task3 = setUpFullscreenTask()
@@ -863,7 +863,7 @@
task4.parentTaskId = task1.taskId
- controller.enterDesktop(DEFAULT_DISPLAY)
+ controller.moveFocusedTaskToDesktop(DEFAULT_DISPLAY)
val wct = getLatestMoveToDesktopWct()
assertThat(wct.changes[task4.token.asBinder()]?.windowingMode)
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 ce7b633..9174556 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
@@ -2,6 +2,7 @@
import android.app.ActivityManager
import android.app.WindowConfiguration
+import android.graphics.Point
import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
@@ -11,6 +12,7 @@
import android.view.Surface.ROTATION_90
import android.view.SurfaceControl
import android.view.WindowManager
+import android.window.TransitionInfo
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
@@ -41,6 +43,8 @@
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.doReturn
import java.util.function.Supplier
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
/**
@@ -575,6 +579,32 @@
})
}
+ @Test
+ fun testStartAnimation_useEndRelOffset() {
+ val mockTransitionInfo = mock(TransitionInfo::class.java)
+ val changeMock = mock(TransitionInfo.Change::class.java)
+ val startTransaction = mock(SurfaceControl.Transaction::class.java)
+ val finishTransaction = mock(SurfaceControl.Transaction::class.java)
+ val point = Point(10, 20)
+ val bounds = Rect(1, 2, 3, 4)
+ `when`(changeMock.endRelOffset).thenReturn(point)
+ `when`(changeMock.endAbsBounds).thenReturn(bounds)
+ `when`(mockTransitionInfo.changes).thenReturn(listOf(changeMock))
+ `when`(startTransaction.setWindowCrop(any(),
+ eq(bounds.width()),
+ eq(bounds.height()))).thenReturn(startTransaction)
+ `when`(finishTransaction.setWindowCrop(any(),
+ eq(bounds.width()),
+ eq(bounds.height()))).thenReturn(finishTransaction)
+
+ taskPositioner.startAnimation(mockTransitionBinder, mockTransitionInfo, startTransaction,
+ finishTransaction, { _ -> })
+
+ verify(startTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(finishTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(changeMock).endRelOffset
+ }
+
private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
bounds == configuration.windowConfiguration.bounds
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 7f6e538..a9f4492 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
@@ -17,6 +17,7 @@
import android.app.ActivityManager
import android.app.WindowConfiguration
+import android.graphics.Point
import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
@@ -25,6 +26,7 @@
import android.view.Surface.ROTATION_270
import android.view.Surface.ROTATION_90
import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_CHANGE
import android.window.TransitionInfo
import android.window.WindowContainerToken
@@ -39,6 +41,7 @@
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 java.util.function.Supplier
import junit.framework.Assert
import org.junit.Before
import org.junit.Test
@@ -47,13 +50,13 @@
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.eq
+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`
-import org.mockito.MockitoAnnotations
-import java.util.function.Supplier
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
/**
* Tests for [VeiledResizeTaskPositioner].
@@ -439,6 +442,40 @@
Assert.assertFalse(taskPositioner.isResizingOrAnimating)
}
+ @Test
+ fun testStartAnimation_useEndRelOffset() {
+ val changeMock = mock(TransitionInfo.Change::class.java)
+ val startTransaction = mock(Transaction::class.java)
+ val finishTransaction = mock(Transaction::class.java)
+ val point = Point(10, 20)
+ val bounds = Rect(1, 2, 3, 4)
+ `when`(changeMock.endRelOffset).thenReturn(point)
+ `when`(changeMock.endAbsBounds).thenReturn(bounds)
+ `when`(mockTransitionInfo.changes).thenReturn(listOf(changeMock))
+ `when`(startTransaction.setWindowCrop(
+ any(),
+ eq(bounds.width()),
+ eq(bounds.height())
+ )).thenReturn(startTransaction)
+ `when`(finishTransaction.setWindowCrop(
+ any(),
+ eq(bounds.width()),
+ eq(bounds.height())
+ )).thenReturn(finishTransaction)
+
+ taskPositioner.startAnimation(
+ mockTransitionBinder,
+ mockTransitionInfo,
+ startTransaction,
+ finishTransaction,
+ mockFinishCallback
+ )
+
+ verify(startTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(finishTransaction).setPosition(any(), eq(point.x.toFloat()), eq(point.y.toFloat()))
+ verify(changeMock).endRelOffset
+ }
+
private fun performDrag(
startX: Float,
startY: Float,
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 76a0a64..659bcdc 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "clip_shader"
+ is_exported: true
namespace: "core_graphics"
description: "API for canvas shader clipping operations"
bug: "280116960"
@@ -9,6 +10,7 @@
flag {
name: "matrix_44"
+ is_exported: true
namespace: "core_graphics"
description: "API for 4x4 matrix and related canvas functions"
bug: "280116960"
@@ -16,6 +18,7 @@
flag {
name: "limited_hdr"
+ is_exported: true
namespace: "core_graphics"
description: "API to enable apps to restrict the amount of HDR headroom that is used"
bug: "234181960"
@@ -44,6 +47,7 @@
flag {
name: "gainmap_animations"
+ is_exported: true
namespace: "core_graphics"
description: "APIs to help enable animations involving gainmaps"
bug: "296482289"
@@ -51,6 +55,7 @@
flag {
name: "gainmap_constructor_with_metadata"
+ is_exported: true
namespace: "core_graphics"
description: "APIs to create a new gainmap with a bitmap for metadata."
bug: "304478551"
@@ -65,6 +70,7 @@
flag {
name: "requested_formats_v"
+ is_exported: true
namespace: "core_graphics"
description: "Enable r_8, r_16_uint, rg_1616_uint, and rgba_10101010 in the SDK"
bug: "292545615"
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index f33bcb7..19e59a7 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -8,7 +8,15 @@
}
flag {
+ name: "enable_location_bypass"
+ namespace: "location"
+ description: "Enable location bypass feature"
+ bug: "301150056"
+}
+
+flag {
name: "location_bypass"
+ is_exported: true
namespace: "location"
description: "Enable location bypass appops behavior"
bug: "329151785"
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6f7024a..1fe3c2e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5453,7 +5453,8 @@
String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
policy.isVolumeController(),
- projection == null ? null : projection.getProjection());
+ projection == null ? null : projection.getProjection(),
+ policy.getAttributionSource());
if (regId == null) {
return ERROR;
} else {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 447d3bb..80e5719 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -789,7 +789,7 @@
private @NonNull AudioRecord buildAudioPlaybackCaptureRecord() {
AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection();
- AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
+ AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ mContext)
.setMediaProjection(projection)
.addMix(audioMix).build();
@@ -853,7 +853,7 @@
.setFormat(mFormat)
.setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
.build();
- AudioPolicy audioPolicy = new AudioPolicy.Builder(null).addMix(audioMix).build();
+ AudioPolicy audioPolicy = new AudioPolicy.Builder(mContext).addMix(audioMix).build();
if (AudioManager.registerAudioPolicyStatic(audioPolicy) != 0) {
throw new UnsupportedOperationException("Error: could not register audio policy");
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 194da21..73deb17 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1353,7 +1353,8 @@
.setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
.build();
AudioPolicy audioPolicy =
- new AudioPolicy.Builder(/*context=*/ null).addMix(audioMix).build();
+ new AudioPolicy.Builder(/*context=*/ mContext).addMix(audioMix).build();
+
if (AudioManager.registerAudioPolicyStatic(audioPolicy) != 0) {
throw new UnsupportedOperationException("Error: could not register audio policy");
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 98bd3ca..e612645 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
+import android.content.AttributionSource;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioFormat;
@@ -361,7 +362,8 @@
String registerAudioPolicy(in AudioPolicyConfig policyConfig,
in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy,
boolean isTestFocusPolicy,
- boolean isVolumeController, in IMediaProjection projection);
+ boolean isVolumeController, in IMediaProjection projection,
+ in AttributionSource attributionSource);
oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index ab7c27f..2d7db5e 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -35,6 +35,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.IHwBinder;
import android.os.Looper;
import android.os.Message;
@@ -43,7 +44,6 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.util.Log;
-import android.util.Singleton;
import com.android.internal.util.FrameworkStatsLog;
@@ -264,71 +264,107 @@
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
- private static final Singleton<IMediaCasService> sService =
- new Singleton<IMediaCasService>() {
+ private static IMediaCasService sService = null;
+ private static Object sAidlLock = new Object();
+
+ /** DeathListener for AIDL service */
+ private static IBinder.DeathRecipient sDeathListener =
+ new IBinder.DeathRecipient() {
@Override
- protected IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get AIDL service");
- IMediaCasService serviceAidl =
- IMediaCasService.Stub.asInterface(
- ServiceManager.waitForDeclaredService(
- IMediaCasService.DESCRIPTOR + "/default"));
- if (serviceAidl != null) {
- return serviceAidl;
- }
- } catch (Exception eAidl) {
- Log.d(TAG, "Failed to get cas AIDL service");
+ public void binderDied() {
+ synchronized (sAidlLock) {
+ Log.d(TAG, "The service is dead");
+ sService.asBinder().unlinkToDeath(sDeathListener, 0);
+ sService = null;
}
- return null;
- }
- };
-
- private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
- new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
- @Override
- protected android.hardware.cas.V1_0.IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get cas@1.2 service");
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.getService(
- true /*wait*/);
- if (serviceV12 != null) {
- return serviceV12;
- }
- } catch (Exception eV1_2) {
- Log.d(TAG, "Failed to get cas@1.2 service");
- }
-
- try {
- Log.d(TAG, "Trying to get cas@1.1 service");
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.getService(
- true /*wait*/);
- if (serviceV11 != null) {
- return serviceV11;
- }
- } catch (Exception eV1_1) {
- Log.d(TAG, "Failed to get cas@1.1 service");
- }
-
- try {
- Log.d(TAG, "Trying to get cas@1.0 service");
- return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
- } catch (Exception eV1_0) {
- Log.d(TAG, "Failed to get cas@1.0 service");
- }
-
- return null;
}
};
static IMediaCasService getService() {
- return sService.get();
+ synchronized (sAidlLock) {
+ if (sService == null || !sService.asBinder().isBinderAlive()) {
+ try {
+ Log.d(TAG, "Trying to get AIDL service");
+ sService =
+ IMediaCasService.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(
+ IMediaCasService.DESCRIPTOR + "/default"));
+ if (sService != null) {
+ sService.asBinder().linkToDeath(sDeathListener, 0);
+ }
+ } catch (Exception eAidl) {
+ Log.d(TAG, "Failed to get cas AIDL service");
+ }
+ }
+ return sService;
+ }
}
+ private static android.hardware.cas.V1_0.IMediaCasService sServiceHidl = null;
+ private static Object sHidlLock = new Object();
+
+ /** Used to indicate the right end-point to handle the serviceDied method */
+ private static final long MEDIA_CAS_HIDL_COOKIE = 394;
+
+ /** DeathListener for HIDL service */
+ private static IHwBinder.DeathRecipient sDeathListenerHidl =
+ new IHwBinder.DeathRecipient() {
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == MEDIA_CAS_HIDL_COOKIE) {
+ synchronized (sHidlLock) {
+ sServiceHidl = null;
+ }
+ }
+ }
+ };
+
static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
- return sServiceHidl.get();
+ synchronized (sHidlLock) {
+ if (sServiceHidl != null) {
+ return sServiceHidl;
+ } else {
+ try {
+ Log.d(TAG, "Trying to get cas@1.2 service");
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
+ if (serviceV12 != null) {
+ sServiceHidl = serviceV12;
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ return sServiceHidl;
+ }
+ } catch (Exception eV1_2) {
+ Log.d(TAG, "Failed to get cas@1.2 service");
+ }
+
+ try {
+ Log.d(TAG, "Trying to get cas@1.1 service");
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
+ if (serviceV11 != null) {
+ sServiceHidl = serviceV11;
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ return sServiceHidl;
+ }
+ } catch (Exception eV1_1) {
+ Log.d(TAG, "Failed to get cas@1.1 service");
+ }
+
+ try {
+ Log.d(TAG, "Trying to get cas@1.0 service");
+ sServiceHidl =
+ android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
+ if (sServiceHidl != null) {
+ sServiceHidl.linkToDeath(sDeathListenerHidl, MEDIA_CAS_HIDL_COOKIE);
+ }
+ return sServiceHidl;
+ } catch (Exception eV1_0) {
+ Log.d(TAG, "Failed to get cas@1.0 service");
+ }
+ }
+ }
+ // Couldn't find an HIDL service, returning null.
+ return null;
}
private void validateInternalStates() {
@@ -756,7 +792,7 @@
* @return Whether the specified CA system is supported on this device.
*/
public static boolean isSystemIdSupported(int CA_system_id) {
- IMediaCasService service = sService.get();
+ IMediaCasService service = getService();
if (service != null) {
try {
return service.isSystemIdSupported(CA_system_id);
@@ -765,7 +801,7 @@
}
}
- android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = getServiceHidl();
if (serviceHidl != null) {
try {
return serviceHidl.isSystemIdSupported(CA_system_id);
@@ -781,7 +817,7 @@
* @return an array of descriptors for the available CA plugins.
*/
public static PluginDescriptor[] enumeratePlugins() {
- IMediaCasService service = sService.get();
+ IMediaCasService service = getService();
if (service != null) {
try {
AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
@@ -794,10 +830,11 @@
}
return results;
} catch (RemoteException e) {
+ Log.e(TAG, "Some exception while enumerating plugins");
}
}
- android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = getServiceHidl();
if (serviceHidl != null) {
try {
ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 1e3c154..cce3d4f 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -502,6 +502,10 @@
return;
}
+ if (mProviderInfo == null) {
+ return;
+ }
+
try {
mRemoteCallback.notifyProviderUpdated(mProviderInfo);
} catch (RemoteException ex) {
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index a53a8ce..e4eaaa3 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioSystem;
@@ -67,12 +68,19 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final int mDeviceSystemType; // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
+ // The (virtual) device ID that this AudioMix was registered for. This value is overwritten
+ // when registering this AudioMix with an AudioPolicy or attaching this AudioMix to an
+ // AudioPolicy to match the AudioPolicy attribution. Does not imply that it only modifies
+ // audio routing for this device ID.
+ private int mVirtualDeviceId;
+
/**
* All parameters are guaranteed valid through the Builder.
*/
private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
int routeFlags, int callbackFlags,
- int deviceType, @Nullable String deviceAddress, IBinder token) {
+ int deviceType, @Nullable String deviceAddress, IBinder token,
+ int virtualDeviceId) {
mRule = Objects.requireNonNull(rule);
mFormat = Objects.requireNonNull(format);
mRouteFlags = routeFlags;
@@ -81,6 +89,7 @@
mDeviceSystemType = deviceType;
mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
mToken = token;
+ mVirtualDeviceId = virtualDeviceId;
}
// CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -269,6 +278,11 @@
}
/** @hide */
+ public boolean matchesVirtualDeviceId(int deviceId) {
+ return mVirtualDeviceId == deviceId;
+ }
+
+ /** @hide */
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -311,6 +325,7 @@
mFormat.writeToParcel(dest, flags);
mRule.writeToParcel(dest, flags);
dest.writeStrongBinder(mToken);
+ dest.writeInt(mVirtualDeviceId);
}
public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
@@ -331,6 +346,7 @@
mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p));
mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
mixBuilder.setToken(p.readStrongBinder());
+ mixBuilder.setVirtualDeviceId(p.readInt());
return mixBuilder.build();
}
@@ -339,6 +355,15 @@
}
};
+ /**
+ * Updates the deviceId of the AudioMix to match with the AudioPolicy the mix is registered
+ * through.
+ * @hide
+ */
+ public void setVirtualDeviceId(int virtualDeviceId) {
+ mVirtualDeviceId = virtualDeviceId;
+ }
+
/** @hide */
@IntDef(flag = true,
value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
@@ -354,6 +379,7 @@
private int mRouteFlags = 0;
private int mCallbackFlags = 0;
private IBinder mToken = null;
+ private int mVirtualDeviceId = Context.DEVICE_ID_DEFAULT;
// an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
private String mDeviceAddress = null;
@@ -404,6 +430,15 @@
/**
* @hide
+ * Only used by AudioMix internally.
+ */
+ Builder setVirtualDeviceId(int virtualDeviceId) {
+ mVirtualDeviceId = virtualDeviceId;
+ return this;
+ }
+
+ /**
+ * @hide
* Only used by AudioPolicyConfig, not a public API.
* @param callbackFlags which callbacks are called from native
* @return the same Builder instance.
@@ -570,7 +605,7 @@
}
return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
- mDeviceAddress, mToken);
+ mDeviceAddress, mToken, mVirtualDeviceId);
}
private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 508c0a2b..293a8f8 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -27,6 +27,7 @@
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
@@ -146,6 +147,16 @@
return mProjection;
}
+ /** @hide */
+ public AttributionSource getAttributionSource() {
+ return getAttributionSource(mContext);
+ }
+
+ private static AttributionSource getAttributionSource(Context context) {
+ return context == null
+ ? AttributionSource.myAttributionSource() : context.getAttributionSource();
+ }
+
/**
* The parameters are guaranteed non-null through the Builder
*/
@@ -208,6 +219,9 @@
if (mix == null) {
throw new IllegalArgumentException("Illegal null AudioMix argument");
}
+ if (android.permission.flags.Flags.deviceAwarePermissionApisEnabled()) {
+ mix.setVirtualDeviceId(getAttributionSource(mContext).getDeviceId());
+ }
mMixes.add(mix);
return this;
}
@@ -358,6 +372,9 @@
if (mix == null) {
throw new IllegalArgumentException("Illegal null AudioMix in attachMixes");
} else {
+ if (android.permission.flags.Flags.deviceAwarePermissionApisEnabled()) {
+ mix.setVirtualDeviceId(getAttributionSource(mContext).getDeviceId());
+ }
zeMixes.add(mix);
}
}
@@ -400,6 +417,9 @@
if (mix == null) {
throw new IllegalArgumentException("Illegal null AudioMix in detachMixes");
} else {
+ if (android.permission.flags.Flags.deviceAwarePermissionApisEnabled()) {
+ mix.setVirtualDeviceId(getAttributionSource(mContext).getDeviceId());
+ }
zeMixes.add(mix);
}
}
diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig
index c3997e9..5bf1b4e 100644
--- a/media/java/android/media/flags/editing.aconfig
+++ b/media/java/android/media/flags/editing.aconfig
@@ -2,6 +2,7 @@
flag {
name: "add_media_metrics_editing"
+ is_exported: true
namespace: "media_solutions"
description: "Add media metrics for transcoding/editing events."
bug: "297487694"
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index bf39425..40929f7 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -2,6 +2,7 @@
flag {
name: "enable_rlp_callbacks_in_media_router2"
+ is_exported: true
namespace: "media_solutions"
description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
bug: "281067101"
@@ -16,6 +17,7 @@
flag {
name: "enable_audio_policies_device_and_bluetooth_controller"
+ is_exported: true
namespace: "media_solutions"
description: "Use Audio Policies implementation for device and Bluetooth route controllers."
bug: "280576228"
@@ -44,6 +46,7 @@
flag {
name: "enable_new_media_route_2_info_types"
+ is_exported: true
namespace: "media_solutions"
description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols."
bug: "301713440"
@@ -51,6 +54,7 @@
flag {
name: "enable_privileged_routing_for_media_routing_control"
+ is_exported: true
namespace: "media_solutions"
description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
bug: "305919655"
@@ -58,6 +62,7 @@
flag {
name: "enable_cross_user_routing_in_media_router2"
+ is_exported: true
namespace: "media_solutions"
description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
bug: "288580225"
@@ -72,6 +77,7 @@
flag {
name: "enable_built_in_speaker_route_suitability_statuses"
+ is_exported: true
namespace: "media_solutions"
description: "Make MediaRoute2Info provide information about routes suitability for transfer."
bug: "279555229"
@@ -79,6 +85,7 @@
flag {
name: "enable_notifying_activity_manager_with_media_session_status_change"
+ is_exported: true
namespace: "media_solutions"
description: "Notify ActivityManager with the changes in playback state of the media session."
bug: "295518668"
@@ -86,6 +93,7 @@
flag {
name: "enable_get_transferable_routes"
+ is_exported: true
namespace: "media_solutions"
description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
bug: "323154573"
@@ -100,6 +108,7 @@
flag {
name: "enable_screen_off_scanning"
+ is_exported: true
namespace: "media_solutions"
description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
bug: "281072508"
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index f110705..1731e5e 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -2,6 +2,7 @@
flag {
name: "broadcast_visibility_types"
+ is_exported: true
namespace: "media_tv"
description: "Constants for standardizing broadcast visibility types."
bug: "222402395"
@@ -9,6 +10,7 @@
flag {
name: "enable_ad_service_fw"
+ is_exported: true
namespace: "media_tv"
description: "Enable the TV client-side AD framework."
bug: "303506816"
@@ -16,6 +18,7 @@
flag {
name: "tiaf_v_apis"
+ is_exported: true
namespace: "media_tv"
description: "TIAF V3.0 APIs for Android V"
bug: "303323657"
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 0b86909..9a3527d 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -16,6 +16,8 @@
per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS
per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file surface_control_input_receiver.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file input_transfer_token.cpp = file:/services/core/java/com/android/server/wm/OWNERS
# Graphics
per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/native/android/surface_control_input_receiver.cpp b/native/android/surface_control_input_receiver.cpp
index da0defd..a84ec73 100644
--- a/native/android/surface_control_input_receiver.cpp
+++ b/native/android/surface_control_input_receiver.cpp
@@ -45,6 +45,8 @@
mClientToken(clientToken),
mInputTransferToken(inputTransferToken) {}
+ // The InputConsumer does not keep the InputReceiver alive so the receiver is cleared once the
+ // owner releases it.
~InputReceiver() {
remove();
}
@@ -190,7 +192,9 @@
void AInputReceiver_release(AInputReceiver* aInputReceiver) {
InputReceiver* inputReceiver = AInputReceiver_to_InputReceiver(aInputReceiver);
- inputReceiver->remove();
+ if (inputReceiver != nullptr) {
+ inputReceiver->remove();
+ }
delete inputReceiver;
}
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 7698e2b..0b3f291 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -50,7 +50,7 @@
],
defaults: ["framework-module-defaults"],
sdk_version: "module_current",
- min_sdk_version: "34", // should be 35 (making it 34 for compiling for `-next`)
+ min_sdk_version: "current",
installable: true,
optimize: {
enabled: false,
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index da292a81..80b2be2 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -268,10 +268,9 @@
}
@FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable {
- ctor public PollingFrame(int, @Nullable byte[], int, int, boolean);
method public int describeContents();
method @NonNull public byte[] getData();
- method public int getTimestamp();
+ method public long getTimestamp();
method public boolean getTriggeredAutoTransact();
method public int getType();
method public int getVendorSpecificGain();
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index c444740..7a78f3d 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -47,8 +47,8 @@
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
INfcDta getNfcDtaInterface(in String pkg);
int getState();
- boolean disable(boolean saveState);
- boolean enable();
+ boolean disable(boolean saveState, in String pkg);
+ boolean enable(in String pkg);
void pausePolling(int timeoutInMs);
void resumePolling();
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 0ebc3f5..7a7db31 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -1117,7 +1117,7 @@
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean enable() {
try {
- return sService.enable();
+ return sService.enable(mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -1126,7 +1126,7 @@
return false;
}
try {
- return sService.enable();
+ return sService.enable(mContext.getPackageName());
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -1156,7 +1156,7 @@
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable() {
try {
- return sService.disable(true);
+ return sService.disable(true, mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -1165,7 +1165,7 @@
return false;
}
try {
- return sService.disable(true);
+ return sService.disable(true, mContext.getPackageName());
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -1181,7 +1181,7 @@
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean disable(boolean persist) {
try {
- return sService.disable(persist);
+ return sService.disable(persist, mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -1190,7 +1190,7 @@
return false;
}
try {
- return sService.disable(persist);
+ return sService.disable(persist, mContext.getPackageName());
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index be3c248..572e20d 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -723,6 +723,8 @@
* delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
* multiple times will cause the value to be overwritten each time.
* @param pollingLoopFilter the polling loop filter to add, must be a valid hexadecimal string
+ * @param autoTransact when true, disable observe mode when this filter matches, when false,
+ * matching does not change the observe mode state
*/
@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
@@ -747,6 +749,8 @@
* multiple times will cause the value to be overwritten each time.
* @param pollingLoopPatternFilter the polling loop pattern filter to add, must be a valid
* regex to match a hexadecimal string
+ * @param autoTransact when true, disable observe mode when this filter matches, when false,
+ * matching does not change the observe mode state
*/
@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
public void addPollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter,
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
index af63a6e..654e8cc 100644
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -16,6 +16,7 @@
package android.nfc.cardemulation;
+import android.annotation.DurationMillisLong;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -148,7 +149,8 @@
private final int mType;
private final byte[] mData;
private final int mGain;
- private final int mTimestamp;
+ @DurationMillisLong
+ private final long mTimestamp;
private final boolean mTriggeredAutoTransact;
public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR =
@@ -180,16 +182,18 @@
* @param type the type of the frame
* @param data a byte array of the data contained in the frame
* @param gain the vendor-specific gain of the field
- * @param timestamp the timestamp in millisecones
+ * @param timestampMillis the timestamp in millisecones
* @param triggeredAutoTransact whether or not this frame triggered the device to start a
* transaction automatically
+ *
+ * @hide
*/
public PollingFrame(@PollingFrameType int type, @Nullable byte[] data,
- int gain, int timestamp, boolean triggeredAutoTransact) {
+ int gain, @DurationMillisLong long timestampMillis, boolean triggeredAutoTransact) {
mType = type;
mData = data == null ? new byte[0] : data;
mGain = gain;
- mTimestamp = timestamp;
+ mTimestamp = timestampMillis;
mTriggeredAutoTransact = triggeredAutoTransact;
}
@@ -230,7 +234,7 @@
* frames relative to each other.
* @return the timestamp in milliseconds
*/
- public int getTimestamp() {
+ public @DurationMillisLong long getTimestamp() {
return mTimestamp;
}
@@ -264,7 +268,7 @@
frame.putInt(KEY_POLLING_LOOP_GAIN, (byte) getVendorSpecificGain());
}
frame.putByteArray(KEY_POLLING_LOOP_DATA, getData());
- frame.putInt(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
+ frame.putLong(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
frame.putBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT, getTriggeredAutoTransact());
return frame;
}
@@ -273,7 +277,7 @@
public String toString() {
return "PollingFrame { Type: " + (char) getType()
+ ", gain: " + getVendorSpecificGain()
- + ", timestamp: " + Integer.toUnsignedString(getTimestamp())
+ + ", timestamp: " + Long.toUnsignedString(getTimestamp())
+ ", data: [" + HexFormat.ofDelimiter(" ").formatHex(getData()) + "] }";
}
}
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index ba084c0..6d4a17c 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -63,6 +63,7 @@
flag {
name: "enable_nfc_charging"
+ is_exported: true
namespace: "nfc"
description: "Flag for NFC charging changes"
bug: "292143899"
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 94d9aaa..abfccb0 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"toestel"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Hierdie app sal toegang tot hierdie toestemmings op jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hê"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om jou foon se apps te stroom?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s sal toegang hê tot enigiets wat sigbaar is of gespeel word op die foon, insluitend oudio, foto’s, wagwoorde en boodskappe.<br/><br/>%1$s sal apps kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toestemming om apps tussen jou toestelle te stroom"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek toestemming namens jou <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> om apps tussen jou toestelle te vertoon en te stroom"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toegang tot jou foon se foto’s, media en kennisgewings"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Laat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> toe om hierdie handeling uit te voer?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Laat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> toe om jou foon se apps en stelselkenmerke te stroom?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s sal toegang hê tot enigiets wat sigbaar is of gespeel word op jou foon, insluitend oudio, foto’s, betaalinligting, wagwoorde en boodskappe.<br/><br/>%1$s sal apps en stelselkenmerke kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en ander stelselkenmerke na toestelle in die omtrek te stroom"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
<string name="summary_generic" msgid="1761976003668044801">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en die gekose toestel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index b53ac74..0d69359 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"áá£áªá«"</string>
<string name="summary_glasses" msgid="2872254734959842579">"áá
áá°áá áªá« á á¥ááµá <xliff:g id="DEVICE_NAME">%1$s</xliff:g> áá á¥ááá
á ááá¶áœ á¥áá²á°ááµ ááááµáá³á"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> áá
á áášá ášáµááá á¥áá²á°ááµá áµ áááá±ááµ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ášáµáááá áá°áá áªá«áᜠá á¥ášáµ á¥áá²á«áµá°ááá ááááµááµ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s áŠá²á®á£ áá¶ááœá£ ášááá áááµ á¥á ááááá¶áœá ášáá® á áµáá áá ášáá³ášáá ááá ášáá«áá°áá ášááááá ááá áá³ášá» ááášááá¢<br/><br/>%1$s áá
á áááµ á¥áµáªá«áµááá± áµášáµ áá°áá áªá«ááœá á á¥ášáµ ááµá°ááá ááœááá¢"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"áá£áªá« á°á»á᪠á ááááá¶áœ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> á á¥ááµá áá£áªá«áᜠáá«ášá áá°áá áªá«ááœá á á¥ášáµ ááááá
ášá¥ááµáá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááá áááµ á¥ášá ášá áá"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ášá¥ááµáá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> á ááášá ááá³ášáµ á¥á áá°áá áªá«ááœá á á¥ášáµ áááµá°ááá áááµ á¥ášá ášá áá"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> áá
á áášá ášáµááá áá á¥áá²á°ááµ áááá±ááµ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"ášGoogle Play á ááááá¶áœ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ášáµáááá áá¶ááœá£ áá²á« á¥á áá³ááá«áᜠáááµášáµ ášá¥ááµáá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááá áááµ á¥ášá ášá áá"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> áá
á á¥ááá á¥áá²ááµáµ áááµ áá°á á?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ášáµáááá áá°áá áªá«áᜠá¥á ášá¥áááµ á£á
áªá«áµ á á¥ášáµ á¥áá²á«áµá°ááá ááááµááµ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s áŠá²á®á£ áá¶ááœá£ ášááá« áášáᣠášááá áááµ á¥á ááááá¶áœá ášáá® á áµááá áá ášáá³ášáá ááá ášáá«áá°áá ášááááá ááá áá³ášá» ááášááᢠášáá
á áááµ áá³ášá» á¥áµášáá«áµááá± áµášáµ <br/><br/>%1$s áá°áá áªá«ááœá á¥á ášá¥áááµ á£á
áªá«áµá á á¥ášáµ áááµá°ááá ááœááá¢"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ášá¥ááµáá <xliff:g id="DEVICE_NAME">%2$s</xliff:g> á ááášá á á á
á«á¢á« áá áá£áªá«áᜠáá°áá áªá«áᜠá¥á ááᜠášáµáááµ á£á
áªá«áµá á á¥ášáµ ááááá
áááµ á¥ášá ášá áá"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"áá£áªá«"</string>
<string name="summary_generic" msgid="1761976003668044801">"áá
áá°áá áªá« á¥áá° ášáá°áá á°á áµá á«á áášáá á áµááá á¥á á á°áášá á áá£áªá« áá«ášá ááµáá ááœáá"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index a1e09b2..183965e 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"Ø¬ÙØ§Ø²"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ø³ÙØªÙ
Ø§ÙØ³Ù
Ø§Ø ÙÙØ°Ø§ Ø§ÙØªØ·ØšÙ٠ؚاÙÙØµÙ٠إÙÙ ÙØ°Ù Ø§ÙØ£Ø°ÙÙØ§Øª عÙÙ \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ø§ÙØ³Ù
Ø§Ø ÙØªØ·ØšÙÙ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ؚاÙÙØµÙ٠إÙÙ ÙØ°Ù اÙÙ
عÙÙÙ
ات Ù
Ù ÙØ§ØªÙÙ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ÙÙ ØªØ±ÙØ¯ Ù
ÙØ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> إذÙÙØ§ ÙØšØ« Ø§ÙØªØ·ØšÙÙØ§Øª اÙÙ
ÙØ«ØšÙÙØªØ© عÙÙ ÙØ§ØªÙÙØ"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"Ø³ÙØªÙ
ÙÙÙ \"%1$s\" Ù
٠اÙÙØµÙ٠إÙÙ Ù٠اÙÙ
ØØªÙ٠اÙÙ
Ø¹Ø±ÙØ¶ Ø£Ù Ø§ÙØ°Ù ÙØªÙ
ت؎غÙÙ٠عÙ٠اÙÙØ§ØªÙØ ØšÙ
ا Ù٠ذÙ٠اÙÙ
ÙÙØ§Øª Ø§ÙØµÙØªÙØ© ÙØ§ÙØµÙØ± ÙÙÙÙ
ات اÙÙ
Ø±ÙØ± ÙØ§Ùرسا؊Ù.<br/><br/>Ø³ÙØªÙ
ÙÙÙ \"%1$s\" Ù
٠ؚث Ø§ÙØªØ·ØšÙÙØ§Øª Ø¥Ù٠أÙ٠تÙÙ٠إÙ
ÙØ§ÙÙØ© استخداÙ
ÙØ°Ø§ Ø§ÙØ¥Ø°Ù."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Ø§ÙØ®Ø¯Ù
ات Ø§ÙØªÙ تعÙ
Ù ØšÙÙ Ø§ÙØ£Ø¬Ùزة"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ÙØ·ÙØš تطؚÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" Ø§ÙØØµÙ٠عÙ٠إذ٠ÙÙØ§ØšØ©Ù ع٠\"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" ÙØšØ«Ù Ù
ØØªÙÙ Ø§ÙØªØ·ØšÙÙØ§Øª ØšÙÙ Ø£Ø¬ÙØ²ØªÙ."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ÙØ·ÙØš \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" Ø§ÙØØµÙ٠عÙ٠إذ٠ÙÙØ§ØšØ©Ù ع٠\"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" ÙØ¹Ø±Ø¶ Ø§ÙØªØ·ØšÙÙØ§Øª ÙØšØ«Ùا ØšÙÙ Ø£Ø¬ÙØ²ØªÙ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ø§ÙØ³Ù
Ø§Ø ÙØªØ·ØšÙÙ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ؚاÙÙØµÙ٠إÙÙ ÙØ°Ù اÙÙ
عÙÙÙ
ات Ù
Ù ÙØ§ØªÙÙ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"خدÙ
ات Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ÙØ·ÙØš تطؚÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" Ø§ÙØØµÙ٠عÙ٠إذ٠ÙÙØ§ØšØ©Ù ع٠\"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" ÙÙÙØµÙ٠إÙÙ Ø§ÙØµÙر ÙØ§ÙÙØ³Ø§ØŠØ· ÙØ§Ùإ؎عارات ÙÙ ÙØ§ØªÙÙ."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ÙÙ ØªØ±ÙØ¯ Ø§ÙØ³Ù
Ø§Ø ÙÙØªØ·ØšÙÙ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ØšØ§ØªÙØ®Ø§Ø° ÙØ°Ø§ Ø§ÙØ¥Ø¬Ø±Ø§Ø¡Ø"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ÙÙ ØªØ±ÙØ¯ Ù
ÙØ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> إذÙÙØ§ ÙØšØ« Ø§ÙØªØ·ØšÙÙØ§Øª ÙØ§ÙÙØµÙ٠إÙÙ Ù
ÙØ²Ø§Øª اÙÙØžØ§Ù
عÙÙ ÙØ§ØªÙÙØ"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Ø³ÙØªÙ
ÙÙÙ \"%1$s\" Ù
٠اÙÙØµÙ٠إÙÙ Ù٠اÙÙ
ØØªÙ٠اÙÙ
Ø¹Ø±ÙØ¶ Ø£Ù Ø§ÙØ°Ù ÙØªÙ
ت؎غÙÙ٠عÙÙ ÙØ§ØªÙÙØ ØšÙ
ا Ù٠ذÙ٠اÙÙ
ÙÙØ§Øª Ø§ÙØµÙØªÙØ© ÙØ§ÙØµÙØ± ÙÙ
عÙÙÙ
ات Ø§ÙØ¯Ùع ÙÙÙÙ
ات اÙÙ
Ø±ÙØ± ÙØ§Ùرسا؊Ù.<br/><br/>Ø³ÙØªÙ
ÙÙÙ \"%1$s\" Ù
٠ؚث Ø§ÙØªØ·ØšÙÙØ§Øª ÙØ§ÙÙØµÙ٠إÙÙ Ù
ÙØ²Ø§Øª اÙÙØžØ§Ù
Ø¥Ù٠أÙ٠تÙÙ٠إÙ
ÙØ§ÙÙØ© استخداÙ
ÙØ°Ø§ Ø§ÙØ¥Ø°Ù."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ÙØ·ÙØš \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" Ø§ÙØØµÙ٠عÙ٠إذ٠ÙÙØ§ØšØ©Ù ع٠\"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" ÙØšØ«Ù Ø§ÙØªØ·ØšÙÙØ§Øª ÙÙ
ÙØ²Ø§Øª اÙÙØžØ§Ù
Ø§ÙØ£Ø®Ø±Ù Ø¥ÙÙ Ø£Ø¬ÙØ²ØªÙ اÙÙ
Ø¬Ø§ÙØ±Ø©."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Ø¬ÙØ§Ø²"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ø³ÙØªÙ
ÙÙÙ ÙØ°Ø§ Ø§ÙØªØ·ØšÙÙ Ù
Ù Ù
زاÙ
ÙØ© اÙÙ
عÙÙÙ
Ø§ØªØ Ù
ث٠اسÙ
اÙÙ
ØªØµÙØ ØšÙÙ ÙØ§ØªÙÙ ÙØ§ÙØ¬ÙØ§Ø² اÙÙ
ØØ¯Ùد."</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 481ce24..3d1554b 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àŠ¡àŠ¿àŠàŠŸàŠàŠ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"àŠàŠ àŠàŠªà§àŠà§àŠ àŠàŠªà§àŠšàŠŸà§° <xliff:g id="DEVICE_NAME">%1$s</xliff:g>àŠ€ àŠàŠ àŠ
àŠšà§àŠ®àŠ€àŠ¿àŠžàŠ®à§àй àŠàŠà§àŠžà§àŠ àŠà§°àŠ¿àŠ¬àŠ²à§ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠ¯àŠŒàŠŸ àŠ¹’àŠ¬"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>àŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšà§° àŠªà§°àŠŸ àŠàŠ àŠ€àŠ¥à§àНàŠàŠ¿àŠšàŠ¿ àŠàŠà§àŠžà§àŠ àŠà§°àŠŸà§° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠ¯àŠŒàŠ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>àŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšà§° àŠàŠªà§ àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠ¿àŠ¬àŠ²à§ àŠŠàŠ¿àŠ¬àŠšà§?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$sàŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšàŠ€ àŠŠà§àжà§àŠ¯àŠ®àŠŸàŠš àŠ
àŠ¥àŠ¬àŠŸ àŠªà§àŠ²à§ àŠà§°àŠŸ àŠ
àŠ¡àŠ¿àŠ
’, àŠ«àŠ’ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠà§°à§ àŠ¬àŠŸà§°à§àŠ€àŠŸàŠà§ àŠ§à§°àŠ¿ àŠ¯àŠ¿àŠà§àŠšà§ àŠ¬àŠžà§àŠ€à§ àŠàŠà§àŠžà§àŠ àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°àŠ¿àŠ¬à¥€<br/><br/>%1$sàŠ àŠàŠªà§àŠšàŠ¿ àŠàŠ àŠ
àŠšà§àŠ®àŠ€àŠ¿à§° àŠàŠà§àŠžà§àŠ àŠàŠàŠ€à§°àŠŸàŠ àŠšàŠ¿àŠŠàŠ¿àŠ¯àŠŒàŠŸ àŠªà§°à§àŠ¯àŠšà§àŠ€ àŠàŠªà§àŠžàŠ®à§àй àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°àŠ¿àŠ¬à¥€"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àŠà§à§°àŠ-àŠ¡àŠ¿àŠàŠŸàŠàŠ àŠžà§à§±àŠŸàŠžàŠ®à§àй"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>àŠ àŠàŠªà§àŠšàŠŸà§° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>à§° àŠ¹à§ àŠàŠªà§àŠšàŠŸà§° àŠ¡àŠ¿àŠàŠŸàŠàŠàŠžàŠ®à§àŠ¹à§° àŠ®àŠŸàŠàŠ€ àŠàŠªà§ àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠ
àŠšà§à§°à§àЧ àŠàŠšàŠŸàŠàŠà§"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g>àŠ àŠàŠªà§àŠšàŠŸà§° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>à§° àŠ¹à§ àŠàŠªà§àŠšàŠŸà§° àŠ¡àŠ¿àŠàŠŸàŠàŠàŠžàŠ®à§àŠ¹à§° àŠ®àŠŸàŠàŠ€ àŠàŠªà§ àŠŠà§àŠà§à§±àŠŸàŠ¬àŠ²à§ àŠà§°à§ àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠ¿àŠ¬àŠ²à§ àŠ
àŠšà§à§°à§àЧ àŠàŠšàŠŸàŠàŠà§"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>àŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšà§° àŠªà§°àŠŸ àŠàŠ àŠ€àŠ¥à§àНàŠàŠ¿àŠšàŠ¿ àŠàŠà§àŠžà§àŠ àŠà§°àŠŸà§° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠ¯àŠŒàŠ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play àŠžà§à§±àŠŸ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g>àŠ àŠàŠªà§àŠšàŠŸà§° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>à§° àŠ¹à§ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšà§° àŠ«àŠ’, àŠ®àŠ¿àŠ¡àŠ¿àŠ¯àŠŒàŠŸ àŠà§°à§ àŠàŠŸàŠšàŠšà§ àŠàŠà§àŠžà§àŠ àŠà§°àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠ
àŠšà§à§°à§àЧ àŠàŠšàŠŸàŠàŠà§"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>àŠ àŠàŠ àŠàŠŸà§°à§àНàŠà§ àŠžàŠ®à§àŠªàŠŸàŠŠàŠš àŠà§°àŠ¿àŠ¬àŠ²à§ àŠŠàŠ¿àŠ¬àŠšà§?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>àŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšà§° àŠàŠªà§ àŠà§°à§ àŠàŠ¿àŠ·à§àŠà§àŠ®à§° àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠ¿àŠ¬àŠ²à§ àŠŠàŠ¿àŠ¬àŠšà§?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$sàŠ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠšàŠ€ àŠŠà§àжà§àŠ¯àŠ®àŠŸàŠš àŠ
àŠ¥àŠ¬àŠŸ àŠªà§àŠ²à§ àŠà§°àŠŸ àŠ
àŠ¡àŠ¿àŠ
’, àŠ«àŠ’ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠà§°à§ àŠ¬àŠŸà§°à§àŠ€àŠŸàŠà§ àŠ§à§°àŠ¿ àŠ¯àŠ¿àŠà§àŠšà§ àŠ¬àŠžà§àŠ€à§ àŠàŠà§àŠžà§àŠ àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°àŠ¿àŠ¬à¥€<br/><br/>%1$sàŠ àŠàŠªà§àŠšàŠ¿ àŠàŠ àŠ
àŠšà§àŠ®àŠ€àŠ¿à§° àŠàŠà§àŠžà§àŠ àŠàŠàŠ€à§°àŠŸàŠ àŠšàŠ¿àŠŠàŠ¿àŠ¯àŠŒàŠŸ àŠªà§°à§àŠ¯àŠšà§àŠ€ àŠàŠªà§àŠžàŠ®à§àй àŠà§°à§ àŠàŠ¿àŠ·à§àŠà§àŠ®à§° àŠžà§àŠ¬àŠ¿àŠ§àŠŸàŠžàŠ®à§àй àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°àŠ¿àŠ¬à¥€"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>àŠ àŠàŠªà§àŠšàŠŸà§° <xliff:g id="DEVICE_NAME">%2$s</xliff:g>à§° àŠ¹à§ àŠšàŠ¿àŠàŠà§±à§°à§àŠ€à§ àŠ¡àŠ¿àŠàŠŸàŠàŠàŠ€ àŠàŠªà§ àŠà§°à§ àŠàŠ¿àŠ·à§àŠà§àŠ®à§° àŠ
àŠšà§àН àŠžà§àŠ¬àŠ¿àŠ§àŠŸàŠžàŠ®à§àй àŠ·à§àŠà§à§°à§àŠ® àŠà§°àŠŸà§° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠ¬àŠ²à§ àŠ
àŠšà§à§°à§àЧ àŠàŠšàŠŸàŠàŠà§"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àŠ¡àŠ¿àŠàŠŸàŠàŠ"</string>
<string name="summary_generic" msgid="1761976003668044801">"àŠàŠ àŠàŠªà§àŠà§à§±à§ àŠàŠªà§àŠšàŠŸà§° àŠ«’àŠš àŠà§°à§ àŠ¬àŠŸàŠàŠšàŠ¿ àŠà§°àŠŸ àŠ¡àŠ¿àŠàŠŸàŠàŠàŠà§à§° àŠ®àŠŸàŠàŠ€ àŠàв àŠà§°à§àŠàŠ€àŠŸà§° àŠšàŠŸàŠ®à§° àŠŠà§°à§ àŠ€àŠ¥à§àН àŠàŠ¿àŠàŠ àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°àŠ¿àŠ¬"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 4e71b8c..6128c5c 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"cihazda"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Bu tÉtbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> bu icazÉlÉrÉ daxil ola bilÉcÉk"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tÉtbiqinÉ telefonunuzdan bu mÉlumata giriÅ icazÉsi verin"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tÉtbiqinÉ telefon tÉtbiqlÉrini yayımlamaq icazÉsi verilsin?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s audio, foto, parol vÉ mesajlar daxil olmaqla telefonda görünÉn vÉ ya oxudulan mÉzmuna giriÅ ÉldÉ edÉcÉk.<br/><br/>%1$s bu icazÉyÉ giriÅ silinÉnÉdÉk tÉtbiqlÉri yayımlayacaq."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmÉtlÉr"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> adından cihazlar arasında tÉtbiqlÉri yayımlamaq icazÉsi istÉyir"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> tÉtbiqlÉri göstÉrmÉk vÉ cihazlar arasında yayımlamaq üçün <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ÉvÉzinÉ icazÉ tÉlÉb edir"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tÉtbiqinÉ telefonunuzdan bu mÉlumata giriÅ icazÉsi verin"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmÉtlÉri"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> adından telefonun foto, media vÉ bildiriÅlÉrinÉ giriÅ icazÉsi istÉyir"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazına bu ÉmÉliyyatı yerinÉ yetirmÉk icazÉsi verilsin?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> tÉtbiqinÉ telefon tÉtbiqlÉrini vÉ sistem funksiyalarını yayımlamaq icazÉsi verilsin?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s audio, foto, ödÉniÅ mÉlumatı, parol vÉ mesajlar daxil olmaqla telefonda görünÉn vÉ ya oxudulan mÉzmuna giriÅ ÉldÉ edÉcÉk.<br/><br/>%1$s bu icazÉyÉ giriÅ silinÉnÉdÉk tÉtbiqlÉri vÉ sistem funksiyalarını yayımlayacaq."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından tÉtbiq vÉ digÉr sistem funksiyalarını yaxınlıqdakı cihazlara yayımlamaq icazÉsi sitÉyir"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="1761976003668044801">"TÉtbiq zÉng edÉnin adı kimi mÉlumatları telefon ilÉ seçilmiÅ cihaz arasında sinxronlaÅdıracaq"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 6504ab4..dde4906 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ureÄaj"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ovoj aplikaciji Äe biti dozvoljeno da pristupa ovim dozvolama na vašem ureÄaju (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Åœelite li da dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strimuje aplikacije na telefonu?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Äe imati pristup svemu što se vidi ili pušta na telefonu, ukljuÄujuÄi zvuk, slike, lozinke i poruke.<br/><br/>%1$s Äe moÄi da strimuje aplikacije dok ne uklonite pristup ovoj dozvoli."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više ureÄaja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za strimovanje aplikacija izmeÄu ureÄaja"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> traÅŸi dozvolu u ime ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> da prikazuje i strimuje aplikacije izmeÄu ureÄaja"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za pristup slikama, medijskom sadrÅŸaju i obaveštenjima sa telefona"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Åœelite li da dozvolite da <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> obavi ovu radnju?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Åœelite li da dozvolite da <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> strimuje aplikacije i funkcije sistema na telefonu?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s Äe imati pristup svemu što se vidi ili pušta na telefonu, ukljuÄujuÄi zvuk, slike, informacije o plaÄanju, lozinke i poruke.<br/><br/>%1$s Äe moÄi da strimuje aplikacije i funkcije sistema dok ne uklonite pristup ovoj dozvoli."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime ureÄaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije i druge sistemske funkcije na ureÄaje u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ureÄaj"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija Äe moÄi da sinhronizuje podatke, poput imena osobe koja upuÄuje poziv, izmeÄu telefona i odabranog ureÄaja"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index fcc587a..266e6be 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"пÑÑлаЎа"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐÑÑÐ°Ñ Ð¿ÑагÑаЌа бÑЎзе ЌеÑÑ ÐœÐ° ваÑай пÑÑлаЎзе \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" МаÑÑÑпМÑÑ ÐŽÐ°Ð·Ð²ÐŸÐ»Ñ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ÐазвПлÑÑе пÑагÑаЌе <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ЌеÑÑ ÐŽÐŸÑÑÑп Ўа гÑÑай ÑМÑаÑЌаÑÑÑ Ð· ваÑага ÑÑлеÑПМа"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ÐазвПлÑÑÑ Ð¿ÑагÑаЌе <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÑÑаМÑлÑÑаваÑÑ Ð¿ÑагÑÐ°ÐŒÑ Ð· ваÑага ÑÑлеÑПМа?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"ÐÑагÑаЌа \"%1$s\" бÑЎзе ЌеÑÑ ÐŽÐŸÑÑÑп Ўа ÑÑÑгП, ÑÑП аЎлÑÑÑÑПÑваеÑÑа Ма ÑкÑаМе ÑÑлеÑПМа ÑÑ Ð¿ÑайгÑаеÑÑа Ма ÑÐŒ, ÑклÑÑаÑÑÑ Ð°ÑÐŽÑÑ, ÑПÑа, паÑÐŸÐ»Ñ Ñ Ð¿Ð°Ð²ÐµÐŽÐ°ÐŒÐ»ÐµÐœÐœÑ.<br/><br/>ÐÑагÑаЌа \"%1$s\" зЌПжа ÑÑаМÑлÑÑаваÑÑ Ð¿ÑагÑаЌÑ, пакÑÐ»Ñ Ð²Ñ ÐœÐµ аЎклÑÑаÑе гÑÑÑ ÐŽÐ°Ð·Ð²ÐŸÐ»."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"СÑÑвÑÑÑ ÐŽÐ»Ñ ÐœÐµÐºÐ°Ð»ÑкÑÑ
пÑÑлаЎ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ÐÑагÑаЌа \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑÑвае ЎазвПл аЎ ÑÐŒÑ Ð²Ð°Ñай пÑÑÐ»Ð°ÐŽÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" Ма ÑÑаМÑлÑÑÑÑ Ð¿ÑагÑаЌ паЌÑж ваÑÑÐŒÑ Ð¿ÑÑлаЎаЌÑ"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ÐÑагÑаЌа \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑÑвае ЎазвПл аЎ ÑÐŒÐµÐœÑ Ð²Ð°Ñай пÑÑÐ»Ð°ÐŽÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" Ма паказ Ñ ÑÑаМÑлÑÑÑÑ Ð¿ÑагÑаЌ паЌÑж пÑÑлаЎаЌÑ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ÐазвПлÑÑе пÑагÑаЌе <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ЌеÑÑ ÐŽÐŸÑÑÑп Ўа гÑÑай ÑМÑаÑЌаÑÑÑ Ð· ваÑага ÑÑлеÑПМа"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"СÑÑвÑÑÑ Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ÐÑагÑаЌа \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑÑвае ЎазвПл аЎ ÑÐŒÑ Ð²Ð°Ñай пÑÑÐ»Ð°ÐŽÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" Ма ЎПÑÑÑп Ўа ÑПÑа, ЌеЎÑÑÑÐ°Ð¹Ð»Ð°Ñ Ñ Ð°Ð¿Ð°Ð²ÑÑÑÑММÑÑ ÐœÐ° ваÑÑÐŒ ÑÑлеÑПМе"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ÐазвПлÑÑÑ Ð¿ÑÑлаЎзе <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> вÑкаМаÑÑ Ð³ÑÑа ЎзеÑММе?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ÐазвПлÑÑÑ Ð¿ÑÑлаЎзе <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÑÑаМÑлÑÑаваÑÑ Ð¿ÑагÑÐ°ÐŒÑ Ñ ÑÑÑÑÑЌМÑÑ ÑÑМкÑÑÑ Ð· ваÑага ÑÑлеÑПМа?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"ÐÑÑлаЎа \"%1$s\" бÑЎзе ЌеÑÑ ÐŽÐŸÑÑÑп Ўа ÑÑÑгП, ÑÑП аЎлÑÑÑÑПÑваеÑÑа Ма ÑкÑаМе ÑÑлеÑПМа ÑÑ Ð¿ÑайгÑаеÑÑа Ма ÑÐŒ, ÑклÑÑаÑÑÑ Ð°ÑÐŽÑÑ, ÑПÑа, плаÑежМÑÑ ÑМÑаÑЌаÑÑÑ, паÑÐŸÐ»Ñ Ñ Ð¿Ð°Ð²ÐµÐŽÐ°ÐŒÐ»ÐµÐœÐœÑ.<br/><br/>ÐÑÑлаЎа \"%1$s\" зЌПжа ÑÑаМÑлÑÑаваÑÑ Ð¿ÑагÑÐ°ÐŒÑ Ñ ÑÑÑÑÑЌМÑÑ ÑÑМкÑÑÑ, пакÑÐ»Ñ Ð²Ñ ÐœÐµ аЎклÑÑаÑе гÑÑÑ ÐŽÐ°Ð·Ð²ÐŸÐ»."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ÐÑагÑаЌа \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑÑвае ЎазвПл аЎ ÑÐŒÑ Ð²Ð°Ñай пÑÑÐ»Ð°ÐŽÑ \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" Ма пеÑаЎаÑÑ Ð¿Ð»ÑÐœÐœÑ Ð·ÐŒÐµÑÑÑва пÑагÑаЌ Ñ ÑМÑÑÑ
ÑÑМкÑÑй ÑÑÑÑÑÐŒÑ ÐœÐ° пÑÑÐ»Ð°ÐŽÑ Ð¿Ð°Ð±Ð»ÑзÑ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"пÑÑлаЎа"</string>
<string name="summary_generic" msgid="1761976003668044801">"ÐÑÑа пÑагÑаЌа зЌПжа ÑÑМÑ
ÑаМÑзаваÑÑ ÑМÑаÑЌаÑÑÑ (МапÑÑклаЎ, ÑÐŒÑ ÑагП, Ñ
ÑП звПМÑÑÑ) паЌÑж ÑÑлеÑПМаЌ Ñ Ð²ÑбÑаМай пÑÑлаЎай"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 30447ce..771f4ec 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àŠ¡àŠ¿àŠàŠŸàŠàŠž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"àŠàŠ àŠ
à§àŠ¯àŠŸàŠª àŠàŠªàŠšàŠŸàŠ° <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-àŠ àŠàŠàŠžàŠ¬ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠš àŠ¥à§àŠà§ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àŠ
à§àŠ¯àŠŸàŠªàŠà§ àŠàŠ àŠ€àŠ¥à§àН àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠŸàŠ° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠš"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠšà§àа àŠ
à§àŠ¯àŠŸàŠª àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠŸàŠ° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠà§àЬà§àŠš?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s, àŠ
àŠ¡àŠ¿àŠ, àŠ«àŠà§, àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠàŠ¬àŠ àŠ®à§àŠžà§àŠ àŠžàŠ¹ àŠ«à§àŠšà§ àŠŠà§àŠàŠŸ àŠ¬àŠŸ àŠàŠŸàŠ²àŠŸàŠšà§ àŠ¯àŠŸàŠ¯àŠŒ àŠàŠ®àŠš àŠžàŠ¬ àŠàŠ¿àŠà§ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§à¥€<br/><br/>àŠàŠªàŠšàŠ¿ àŠàŠ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠšàŠŸ àŠžàŠ°àŠŸàŠšà§ àŠªàŠ°à§àŠ¯àŠšà§àŠ€ %1$s àŠ
à§àŠ¯àŠŸàŠª àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§à¥€"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àŠà§àŠ°àŠž-àŠ¡àŠ¿àŠàŠŸàŠàŠž àŠªàŠ°àŠ¿àŠ·à§àŠ¬àŠŸ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"àŠàŠªàŠšàŠŸàŠ° àŠ¡àŠ¿àŠàŠŸàŠàŠžàŠà§àŠ²àŠ¿àŠ° àŠ®àŠ§à§àŠ¯à§ àŠ
à§àŠ¯àŠŸàŠª àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠŸàŠ° àŠàŠšà§àН <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-àŠàа àŠ¹àŠ¯àŠŒà§ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠàŠŸàŠàŠà§"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"àŠàŠªàŠšàŠŸàŠ° àŠ¡àŠ¿àŠàŠŸàŠàŠžà§àа àŠ®àŠ§à§àŠ¯à§ àŠ
à§àŠ¯àŠŸàŠª, àŠ¡àŠ¿àŠžàŠªà§àŠ²à§ àŠàŠ¬àŠ àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠ€à§ àŠàŠªàŠšàŠŸàŠ° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-àŠàа àŠ¹àŠ¯àŠŒà§ <xliff:g id="APP_NAME">%1$s</xliff:g> àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠàŠŸàŠàŠà§"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠš àŠ¥à§àŠà§ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-àŠà§ àŠàŠ àŠ€àŠ¥à§àН àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠŸàŠ° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠàŠ¿àŠš"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play àŠªàŠ°àŠ¿àŠ·à§àŠ¬àŠŸ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠšà§àа àŠ«àŠà§, àŠ®àŠ¿àŠ¡àŠ¿àŠ¯àŠŒàŠŸ àŠàŠ¬àŠ àŠ€àŠ¥à§àН àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠŸàŠ° àŠàŠšà§àН <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-àŠàа àŠ¹àŠ¯àŠŒà§ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠàŠŸàŠàŠà§"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-àŠà§ àŠàŠ àŠàŠŸàŠàŠàŠ¿ àŠàŠ°àŠ€à§ àŠŠà§àЬà§àŠš?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠšà§àа àŠ
à§àŠ¯àŠŸàŠª àŠàŠ¬àŠ àŠžàŠ¿àŠžà§àŠà§àŠ® àŠ«àŠ¿àŠàŠŸàŠ° àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠŸàŠ° àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠà§àЬà§àŠš?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s, àŠ
àŠ¡àŠ¿àŠ, àŠ«àŠà§, àŠªà§àŠ®à§àŠšà§àŠà§àа àŠ€àŠ¥à§àН, àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠàŠ¬àŠ àŠ®à§àŠžà§àŠ àŠžàŠ¹ àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠšà§ àŠŠà§àŠàŠŸ àŠ¬àŠŸ àŠàŠŸàŠ²àŠŸàŠšà§ àŠ¯àŠŸàŠ¯àŠŒ àŠàŠ®àŠš àŠžàŠ¬ àŠàŠ¿àŠà§ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§à¥€<br/><br/>àŠàŠªàŠšàŠ¿ àŠàŠ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠšàŠŸ àŠžàŠ°àŠŸàŠšà§ àŠªàŠ°à§àŠ¯àŠšà§àŠ€ %1$s àŠ
à§àŠ¯àŠŸàŠª àŠàŠ¬àŠ àŠžàŠ¿àŠžà§àŠà§àŠ® àŠ«àŠ¿àŠàŠŸàŠ° àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§à¥€"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"àŠàжà§àŠªàŠŸàŠ¶à§àа àŠ¡àŠ¿àŠàŠŸàŠàŠžà§ àŠ
à§àŠ¯àŠŸàŠª àŠ àŠ
àŠšà§àŠ¯àŠŸàŠšà§àН àŠžàŠ¿àŠžà§àŠà§àŠ® àŠ«àŠ¿àŠàŠŸàŠ° àŠžà§àŠà§àŠ°àŠ¿àŠ® àŠàŠ°àŠŸàŠ° àŠàŠšà§àН àŠàŠªàŠšàŠŸàŠ° <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-àŠàа àŠ¹àŠ¯àŠŒà§ <xliff:g id="APP_NAME">%1$s</xliff:g> àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠà§àŠ¯àŠŒà§ àŠ
àŠšà§àаà§àЧ àŠàаàŠà§"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àŠ¡àŠ¿àŠàŠŸàŠàŠž"</string>
<string name="summary_generic" msgid="1761976003668044801">"àŠàŠ àŠ
à§àŠ¯àŠŸàŠª, àŠàŠªàŠšàŠŸàŠ° àŠ«à§àŠš àŠàŠ¬àŠ àŠ¬à§àŠà§ àŠšà§àŠàŠ¯àŠŒàŠŸ àŠ¡àŠ¿àŠàŠŸàŠàŠžà§àа àŠ®àŠ§à§àŠ¯à§ àŠ€àŠ¥à§àН àŠžàŠ¿àŠà§àŠ àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°àŠ¬à§, àŠ¯à§àŠ®àŠš àŠà§àŠšàŠ àŠàŠ²àŠŸàŠ°à§àа àŠšàŠŸàŠ®"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 87c5349..231d395 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ureÄaj"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Aplikaciji Äe biti dozvoljen pristup ovim odobrenjima na ureÄaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da prenosi aplikacije telefona?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Äe imati pristup svemu što je vidljivo ili se reproducira na telefonu, ukljuÄujuÄi zvuk, fotografije, lozinke i poruke.<br/><br/>%1$s Äe moÄi prenositi aplikacije dok ne uklonite pristup ovom odobrenju."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više ureÄaja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije izmeÄu vaših ureÄaja"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traÅŸi odobrenje u ime vašeg ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> da prikazuje i prenosi aplikacije izmeÄu vaših ureÄaja"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa ovim informacijama s vašeg telefona"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i obavještenjima na telefonu"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Dozvoliti ureÄaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da poduzme ovu radnju?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Dozvoliti ureÄaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da prenosi aplikacije telefona i funkcije sistema?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s Äe imati pristup svemu što je vidljivo ili se reproducira na telefonu, ukljuÄujuÄi zvuk, fotografije, podatke o plaÄanju, lozinke i poruke.<br/><br/>%1$s Äe moÄi prenositi aplikacije i funkcije sistema dok ne uklonite pristup ovom odobrenju."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime ureÄaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> traÅŸi odobrenje da prenosi aplikacije i druge funkcije sistema na ureÄajima u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ureÄaj"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija Äe moÄi sinhronizirati informacije, kao što je ime osobe koja upuÄuje poziv, izmeÄu vašeg telefona i odabranog ureÄaja"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 40c6aac..ae9e23f 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositiu"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Aquesta aplicació podrà accedir a aquests permisos del dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vols permetre que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> reprodueixi en continu les aplicacions del telèfon?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al telèfon, inclosos àudios, fotos, contrasenyes i missatges.<br/><br/>%1$s podrà reproduir en continu aplicacions fins que suprimeixis l\'accés a aquest permís."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) per reproduir en continu aplicacions entre els dispositius"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> per mostrar i reproduir en continu aplicacions entre els dispositius"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu dispositiu (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) per accedir a les fotos, el contingut multimèdia i les notificacions del telèfon"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vols permetre que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dugui a terme aquesta acció?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vols permetre que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> reprodueixi en continu les aplicacions del telèfon i les funcions del sistema?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al telèfon, inclosos àudios, fotos, informació de pagament, contrasenyes i missatges.<br/><br/>%1$s podrà reproduir en continu aplicacions i funcions del sistema fins que suprimeixis l\'accés a aquest permís."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sol·licita permís en nom del teu dispositiu (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) per reproduir en continu aplicacions i altres funcions del sistema en dispositius propers"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
<string name="summary_generic" msgid="1761976003668044801">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu triat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 7d7d74f..94510e3 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"zaÅízení"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Tato aplikace bude mít ve vašem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> povolený pÅístup k tÄmto oprávnÄním"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pÅístup k tÄmto informacím z vašeho telefonu"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Povolit zaÅízení <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovat aplikace telefonu?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"Aplikace %1$s bude mít pÅístup ke všemu, co zobrazíte nebo pÅehrajete na telefonu, vÄetnÄ zvuku, fotek, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace, dokud pÅístup k tomuto oprávnÄní neodeberete."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"SluÅŸby pro více zaÅízení"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> poÅŸaduje za vaše zaÅízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnÄní ke streamování aplikací mezi zaÅízeními"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> poÅŸaduje za vaše zaÅízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnÄní k zobrazení a streamování obsahu mezi zaÅízeními"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pÅístup k tÄmto informacím z vašeho telefonu"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"SluÅŸby Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> poÅŸaduje za vaše zaÅízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnÄní k pÅístupu k fotkám, médiím a oznámením v telefonu"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Povolit zaÅízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> podniknout tuto akci?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Povolit zaÅízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> streamovat aplikace a systémové funkce telefonu?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Aplikace %1$s bude mít pÅístup ke všemu, co zobrazíte nebo pÅehrajete na telefonu, vÄetnÄ zvuku, fotek, platebních údajů, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace a systémové funkce, dokud pÅístup k tomuto oprávnÄní neodeberete."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> ÅŸádá jménem vašeho zaÅízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnÄní streamovat aplikace a další systémové funkce do zaÅízení v okolí"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zaÅízení"</string>
<string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zaÅízením"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index c4fa73a..6b38bff 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"enhed"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Denne app får adgang til disse tilladelser på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at streame din telefons apps?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s har adgang til alt, der er synligt eller afspilles på telefonen, herunder lyd, billeder, adgangskoder og beskeder.<br/><br/>%1$s kan streame apps, indtil du fjerner adgangen til denne tilladelse."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at streame apps mellem dine enheder"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at vise og streame apps mellem dine enheder"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Tillad, at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får adgang til disse oplysninger fra din telefon"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at få adgang til din telefons billeder, medier og notifikationer"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du tillade, at <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> foretager denne handling?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vil du give <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> tilladelse til at streame din telefons apps og systemfunktioner?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s har adgang til alt, der er synligt eller afspilles på din telefon, herunder lyd, billeder, adgangskoder og beskeder.<br/><br/>%1$s kan streame apps og systemfunktioner, indtil du fjerner adgangen til denne tilladelse."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps og andre systemfunktioner til enheder i nærheden"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
<string name="summary_generic" msgid="1761976003668044801">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og den valgte enhed"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index d435829..65e923c 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Diese App darf dann auf diese Berechtigungen auf deinem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zugreifen:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, die Apps auf deinem Smartphone zu streamen?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s hat dann Zugriff auf alle Inhalte, die auf deinem Smartphone sichtbar sind oder abgespielt werden, einschließlich Audio, Fotos, Passwörter und Nachrichten.<br/><br/>%1$s kann so lange Apps streamen, bis du diese Berechtigung entfernst."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Anzeigen und Streamen von Apps zwischen deinen Geräten"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Darf das Gerät <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> diese Aktion ausführen?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> erlauben, die Apps und Systemfunktionen auf deinem Smartphone zu streamen?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s hat dann Zugriff auf alle Inhalte, die auf deinem Smartphone sichtbar sind oder abgespielt werden, einschließlich Audio, Fotos, Zahlungsinformationen, Passwörter und Nachrichten.<br/><br/>%1$s kann so lange Apps und Systemfunktionen streamen, bis du diese Berechtigung entfernst."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein Gerät (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) um die Berechtigung, Apps und andere Systemfunktionen auf Geräte in der Nähe zu streamen"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
<string name="summary_generic" msgid="1761976003668044801">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und dem ausgewählten Gerät synchronisieren"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 2fbe353..2d27790 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"συσκευή"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Αυτή η εφαρμογή θα μπορεί να Îχει πρÏσβαση σε αυτÎς τις άδειες στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρÎπεται στο <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η πρÏσβαση σε αυτÎς τις πληροφορίες απÏ το τηλÎφωνÏ σας."</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Να επιτρÎπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η μετάδοση σε ροή των εφαρμογÏν του τηλεφÏνου σας;"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"Το %1$s θα Îχει πρÏσβαση σε οτιδήποτε είναι ορατÏ Î® αναπαράγεται στο τηλÎφωνο, συμπεριλαμβανομÎνων ήχων, φωτογραφιÏν, κωδικÏν πρÏσβασης και μηνυμάτων.<br/><br/>Το %1$s θα μπορεί να μεταδÏσει εφαρμογÎς σε ροή μÎχρι να καταργήσετε την πρÏσβαση σε αυτή την άδεια."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλÏν συσκευÏν"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μÎρους της συσκευής σας <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> άδεια για ροή εφαρμογÏν μεταξÏ των συσκευÏν σας"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μÎρους της συσκευής <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> για προβολή και μετάδοση εφαρμογÏν σε ροή μεταξÏ των συσκευÏν σας"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ΕπιτρÎψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να Îχει πρÏσβαση σε αυτÎς τις πληροφορίες απÏ το τηλÎφωνÏ σας"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μÎρους της συσκευής σας <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> άδεια για πρÏσβαση στις φωτογραφίες, τα αρχεία μÎσων και τις ειδοποιήσεις του τηλεφÏνου σας"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Να επιτρÎπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> να εκτελεί αυτή την ενÎργεια;"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Να επιτρÎπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> η μετάδοση σε ροή των εφαρμογÏν και των λειτουργιÏν συστήματος του τηλεφÏνου σας;"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Το %1$s θα Îχει πρÏσβαση σε οτιδήποτε είναι ορατÏ Î® αναπαράγεται στο τηλÎφωνο, συμπεριλαμβανομÎνων ήχων, φωτογραφιÏν, στοιχείων πληρωμής, κωδικÏν πρÏσβασης και μηνυμάτων.<br/><br/>Το %1$s θα μπορεί να μεταδÏσει εφαρμογÎς και λειτουργίες συστήματος σε ροή μÎχρι να καταργήσετε την πρÏσβαση σε αυτή την άδεια."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μÎρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για ροή εφαρμογÏν και άλλων λειτουργιÏν του συστήματος σε συσκευÎς σε κοντινή απÏσταση"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
<string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξÏ του τηλεφÏνου και της επιλεγμÎνης συσκευής σας, Ïπως το Ïνομα ενÏς ατÏμου που σας καλεί."</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index ee8eca0..e23a48c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
<string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s will have access to anything that\'s visible or played on the phone, including audio, photos, passwords and messages.<br/><br/>%1$s will be able to stream apps until you remove access to this permission."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps and system features?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s will have access to anything that\'s visible or played on your phone, including audio, photos, payment info, passwords and messages.<br/><br/>%1$s will be able to stream apps and system features until you remove access to this permission."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index ee8eca0..e23a48c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
<string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s will have access to anything that\'s visible or played on the phone, including audio, photos, passwords and messages.<br/><br/>%1$s will be able to stream apps until you remove access to this permission."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps and system features?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s will have access to anything that\'s visible or played on your phone, including audio, photos, payment info, passwords and messages.<br/><br/>%1$s will be able to stream apps and system features until you remove access to this permission."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index ee8eca0..e23a48c 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"device"</string>
<string name="summary_glasses" msgid="2872254734959842579">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s will have access to anything that\'s visible or played on the phone, including audio, photos, passwords and messages.<br/><br/>%1$s will be able to stream apps until you remove access to this permission."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to display and stream apps between your devices"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to stream your phone\'s apps and system features?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s will have access to anything that\'s visible or played on your phone, including audio, photos, payment info, passwords and messages.<br/><br/>%1$s will be able to stream apps and system features until you remove access to this permission."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
<string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 51f1874..c0d1888 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Esta app podrá acceder a los siguientes permisos en tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> transmita apps del teléfono?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s tendrá acceso a todo el contenido visible o que se reproduzca en el teléfono, lo que incluye audio, fotos, contraseñas y mensajes.<br/><br/>%1$s podrá transmitir apps, a menos que se quite el acceso a este permiso."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para transmitir apps entre dispositivos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar y transmitir apps entre dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acceder a las fotos, el contenido multimedia y las notificaciones de tu teléfono"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permites que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"¿Quieres permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> transmita funciones del sistema y apps del teléfono?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s tendrá acceso a todo el contenido visible o que se reproduzca en tu teléfono, lo que incluye audio, fotos, información de pago, contraseñas y mensajes.<br/><br/>%1$s podrá transmitir apps y funciones del sistema, a menos que se quiete el acceso a este permiso."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir apps y otras funciones del sistema a dispositivos cercanos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y el dispositivo elegido"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 3e157f0..cdabc6c 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Esta aplicación podrá acceder a estos permisos de tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita las aplicaciones de tu dispositivo?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s tendrá acceso a todo lo que sea visible o se reproduzca en el teléfono, incluidos audio, fotos, contraseñas y mensajes.<br/><br/>%1$s podrá emitir aplicaciones hasta que quites el acceso a este permiso."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para emitir aplicaciones en otros dispositivos tuyos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar y emitir aplicaciones en otros dispositivos tuyos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acceder a las fotos, los archivos multimedia y las notificaciones de tu teléfono"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"¿Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> emita las aplicaciones y funciones del sistema de tu dispositivo?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s tendrá acceso a todo lo que sea visible o se reproduzca en el teléfono, incluidos audio, fotos, información para pagos, contraseñas y mensajes.<br/><br/>%1$s podrá emitir aplicaciones y funciones del sistema hasta que quites el acceso a este permiso."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir aplicaciones y otras funciones del sistema en dispositivos cercanos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 28e8b0d..b7a9ff6 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Sellele rakendusele antakse need load teie seadmes <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Kas lubate rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> oma telefoni rakendusi voogesitada?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s saab juurdepääsu kõigele, mis on telefonis nähtaval või esitatav, sh helile, fotodele, paroolidele ja sõnumitele.<br/><br/>%1$s saab rakendusi voogesitada kuni eemaldate juurdepääsu sellele loale."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi kuvada ja voogesitada"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Kas lubada seadmel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> teha seda toimingut?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Kas lubate rakendusel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> oma telefoni rakenduste ja süsteemifunktsioonidel voogesitada?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s saab juurdepääsu kõigele, mis on teie telefonis nähtav või esitatav, sh heli, fotod, makseteave, paroolid ja sõnumid.<br/><br/>%1$s saab voogesitada rakendusi ja süsteemifunktsioone, kuni eemaldate juurdepääsu sellele loale."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada rakendusi ja muid süsteemi funktsioone läheduses olevatesse seadmetesse"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
<string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 1884e04..d0dee9b 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"gailua"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Baimen hauek erabili ahalko ditu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>n aplikazioak:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari zure telefonoko aplikazioak zuzenean igortzeko baimena eman nahi diozu?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aplikazioak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailuarteko zerbitzuak"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikazioak gailuen artean bistaratzeko eta zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Eman telefonoko informazio hau erabiltzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak erabiltzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ekintza hau gauzatzeko baimena eman nahi diozu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari zure telefonoko aplikazioak eta sistemaren eginbideak zuzenean igortzeko baimena eman nahi diozu?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aplikazioak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak eta sistemaren eginbideak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikazioak eta sistemaren beste eginbide batzuk inguruko gailuetara igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
<string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 9c5807b..b3432ed 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"دستگاÙ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"اÛÙ ØšØ±ÙØ§Ù
Ù Ù
جاز Ù
ÛØŽÙد ؚ٠اÛ٠اجازÙÙØ§ در <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ØŽÙ
ا Ø¯Ø³ØªØ±Ø³Û ÙŸÛØ¯Ø§ Ú©ÙØ¯"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"اجاز٠داد٠ؚ٠<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ØšØ±Ø§Û Ø¯Ø³ØªØ±Ø³Û ØšÙ Ø§Ø·ÙØ§Ø¹Ø§Øª تÙÙÙ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ØšÙ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجاز٠Ù
ÛØ¯ÙÛØ¯ ØšØ±ÙØ§Ù
ÙÙØ§Û تÙÙÙØªØ§Ù را Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯Ø"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"â«%1$s ØšÙ ÙØ±ÚÛØ²Û ک٠در تÙÙÙ ÙÙ
Ø§ÛØ§Ù است ÛØ§ ٟخ؎ Ù
ÛØŽÙØ¯Ø Ø§Ø²Ø¬Ù
ÙÙ ØµØ¯Ø§ÙØ§Ø Ø¹Ú©Ø³ÙØ§Ø Ú¯Ø°Ø±ÙØ§ÚÙÙØ§Ø Ù ÙŸÛØ§Ù
ÙØ§ Ø¯Ø³ØªØ±Ø³Û Ø®ÙØ§Ùد دا؎ت.<br/><br/>تا زÙ
اÙÛ Ú©Ù Ø¯Ø³ØªØ±Ø³Û ØšÙ Ø§Û٠اجاز٠را ØØ°Ù ÙÚ©ÙÛØ¯Ø %1$s Ù
ÛØªÙØ§ÙØ¯ ØšØ±ÙØ§Ù
ÙÙØ§ را Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"سرÙÛØ³ÙØ§Û ØšÛÙØ¯Ø³ØªÚ¯Ø§ÙÛ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطر٠<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> اجاز٠Ù
ÛØ®ÙØ§ÙØ¯ ØšØ±ÙØ§Ù
ÙÙØ§ را ØšÛ٠دستگاÙÙØ§Û ØŽÙ
ا Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطر٠<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ØšØ±Ø§Û ÙÙ
Ø§ÛØŽ Ù Ø¬Ø§Ø±ÛØ³Ø§Ø²Û ØšØ±ÙØ§Ù
ÙÙØ§ ØšÛ٠دستگاÙÙØ§Û ØŽÙ
ا اجاز٠Ù
ÛØ®ÙØ§ÙØ¯"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ØšÙ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Ø§Ø¬Ø§Ø²Ù Ø¯Ø³ØªØ±Ø³Û ØšÙ Ø§ÛÙ Ø§Ø·ÙØ§Ø¹Ø§Øª در Ø¯Ø³ØªÚ¯Ø§ÙØªØ§Ù Ø¯Ø§Ø¯Ù ØŽÙØ¯"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"خدÙ
ات Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطر٠<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> اجاز٠Ù
ÛØ®ÙØ§ÙØ¯ ØšÙ Ø¹Ú©Ø³ÙØ§Ø رساÙÙÙØ§Ø Ù Ø§Ø¹ÙØ§ÙÙØ§Û تÙÙÙ ØŽÙ
ا Ø¯Ø³ØªØ±Ø³Û ÙŸÛØ¯Ø§ Ú©ÙØ¯"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ØšÙ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> Ø§Ø¬Ø§Ø²Ù Ø¯Ø§Ø¯Ù ØŽÙØ¯ اÛÙ Ø§ÙØ¯Ø§Ù
را Ø§ÙØ¬Ø§Ù
Ø¯ÙØ¯Ø"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ØšÙ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> اجاز٠Ù
ÛØ¯ÙÛØ¯ ØšØ±ÙØ§Ù
ÙÙØ§Û تÙÙÙØªØ§Ù Ù ÙÛÚÚ¯ÛÙØ§Û Ø³ÛØ³ØªÙ
را Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯Ø"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"â«%1$s ØšÙ ÙØ±ÚÛØ²Û ک٠در تÙÙÙ ÙÙ
Ø§ÛØ§Ù است ÛØ§ ٟخ؎ Ù
ÛØŽÙØ¯Ø Ø§Ø²Ø¬Ù
ÙÙ ØµØ¯Ø§ÙØ§Ø Ø¹Ú©Ø³ÙØ§Ø Ø§Ø·ÙØ§Ø¹Ø§Øª ÙŸØ±Ø¯Ø§Ø®ØªØ Ú¯Ø°Ø±ÙØ§ÚÙÙØ§Ø Ù ÙŸÛØ§Ù
ÙØ§ Ø¯Ø³ØªØ±Ø³Û Ø®ÙØ§Ùد دا؎ت.<br/><br/>تا زÙ
اÙÛ Ú©Ù Ø¯Ø³ØªØ±Ø³Û ØšÙ Ø§Û٠اجاز٠را ØØ°Ù ÙÚ©ÙÛØ¯Ø %1$s Ù
ÛØªÙØ§ÙØ¯ ØšØ±ÙØ§Ù
ÙÙØ§ Ù ÙÛÚÚ¯ÛÙØ§Û Ø³ÛØ³ØªÙ
را Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطر٠<xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجاز٠Ù
ÛØ®ÙØ§ÙØ¯ تا ØšØ±ÙØ§Ù
ÙÙØ§ ٠دÛگر ÙÛÚÚ¯ÛÙØ§Û Ø³ÛØ³ØªÙ
را در دستگاÙÙØ§Û Ø§Ø·Ø±Ø§Ù Ø¬Ø§Ø±ÛØ³Ø§Ø²Û Ú©ÙØ¯."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"دستگاÙ"</string>
<string name="summary_generic" msgid="1761976003668044801">"اÛÙ ØšØ±ÙØ§Ù
Ù Ù
جاز Ù
ÛØŽÙد Ø§Ø·ÙØ§Ø¹ØªÛ Ù
Ø«Ù ÙØ§Ù
ØŽØ®ØµÛ Ø±Ø§ ک٠تÙ
اس Ù
ÛÚ¯ÛØ±Ø¯ ØšÛ٠تÙÙÙ ØŽÙ
ا Ù Ø¯Ø³ØªÚ¯Ø§Ù Ø§ÙØªØ®Ø§ØšØŽØ¯Ù ÙÙ
گاÙ
Ø³Ø§Ø²Û Ú©ÙØ¯"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index ecde949..0671410 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"laite"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Tämä sovellus saa käyttää näitä lupia laitteella (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn näihin puhelimesi tietoihin"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Saako <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> striimata puhelimen sovelluksia?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s saa pääsyn kaikkeen puhelimessa näkyvään tai pelattavaan, mukaan lukien audioon, kuviin, salasanoihin ja viesteihin.<br/><br/>%1$s voi striimata sovelluksia, kunnes poistat luvan."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteidesi välillä"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) puolesta lupaa näyttää ja striimata sovelluksia laitteidesi välillä"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) puolesta lupaa päästä puhelimesi kuviin, mediaan ja ilmoituksiin"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Sallitko, että <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> voi suorittaa tämän toiminnon?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Saako <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> striimata puhelimen sovelluksia ja järjestelmäominaisuuksia?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s saa pääsyn kaikkeen puhelimessa näkyvään tai pelattavaan, mukaan lukien audioon, kuviin, maksutietoihin, salasanoihin ja viesteihin.<br/><br/>%1$s voi striimata sovelluksia ja järjestelmäominaisuuksia, kunnes poistat luvan."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia ja muita järjestelmän ominaisuuksia lähellä oleviin laitteisiin."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
<string name="summary_generic" msgid="1761976003668044801">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja valitun laitteen välillä"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 5debbf3..97abef7 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Cette application pourra accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à diffuser les applications de votre téléphone?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les mots de passe et les messages.<br/><br/>%1$s pourra diffuser des applications jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, d\'afficher et de diffuser des applications entre vos appareils"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre téléphone"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à diffuser les applications et les fonctionnalités du système de votre téléphone?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris l\'audio, les photos, les renseignements de paiement, les mots de passe et les messages.<br/><br/>%1$s pourra diffuser des applications jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, de diffuser des applications et d\'autres fonctionnalités du système sur des appareils à proximité"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="1761976003668044801">"Cette application pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 0403a4d..a33e0dc2 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Cette appli sera autorisée à accéder à ces autorisations sur votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à caster les applications de votre téléphone ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris les contenus audio, les photos, les mots de passe et les messages.<br/><br/>%1$s pourra caster des applications jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour caster des applis d\'un appareil à l\'autre"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour afficher et caster des applications d\'un appareil à l\'autre"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à caster les applications et les fonctionnalités système de votre téléphone ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris les contenus audio, les photos, les informations de paiement, les mots de passe et les messages.<br/><br/>%1$s pourra caster des applications et des fonctionnalités système jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des applis et d\'autres fonctionnalités système en streaming sur des appareils à proximité"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et l\'appareil choisi"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 5d9d7ee..da7d4a2 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Esta aplicación poderá acceder a estes permisos do dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita as aplicacións do teu teléfono?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s terá acceso a todo o que sexa visible ou se reproduza no teléfono, como audio, fotos, contrasinais e mensaxes.<br/><br/>%1$s poderá emitir aplicacións ata que quites o acceso a este permiso."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) para emitir contido de aplicacións entre os teus aparellos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) para mostrar e emitir aplicacións noutros dispositivos teus"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información do teu teléfono"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) para acceder ás fotos, ao contido multimedia e ás notificacións do teléfono"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Queres permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> leve a cabo esta acción?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Queres permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> emita as aplicacións e as funcións do sistema do teu teléfono?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s terá acceso a todo o que sexa visible ou se reproduza no teléfono, como audio, fotos, información de pago, contrasinais e mensaxes.<br/><br/>%1$s poderá emitir aplicacións e funcións do sistema ata que quites o acceso a este permiso."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir o contido das aplicacións e doutras funcións do sistema en dispositivos próximos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) entre o teléfono e o dispositivo escollido"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index e645f18..e34cf9a 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ડિવટàªàªž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ઠàªàªªàªšà« ઀મટરટ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> પર ઠપરવટચàªà«àª àªàªà«àªžà«àªž àªàª°àªµàªŸàªšà« મàªàªà«àª°à« મળશà«"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"઀મટરટ ફà«àªšàª®àªŸàªàª¥à« ઠમટહિ઀ૠàªàªà«àªžà«àªž àªàª°àªµàªŸ મટàªà«, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ચૠમàªàªà«àª°à« àªàªªà«"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"શà«àª <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ચૠ઀મટરટ ફà«àªšàªšà« àªàªªàªšà« ઞà«àªà«àª°à«àª® àªàª°àªµàªŸàªšà« મàªàªà«àª°à« àªàªªà«àª?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$sચૠપટઞૠàªàªµà« બધૠબટબ઀à«àªšà« àªàªà«àªžà«àªž રહà«àª¶à« àªà« ફà«àªš પર àªà«àª શàªàªŸàª€à« àªà« àªàª²àªŸàªµà« શàªàªŸàª€à« હà«àª¯, àªà«àª®àªŸàª àªàª¡àª¿àª¯à«, ફà«àªàªŸ, પટઞવરà«àª¡ àª
ચૠમà«àªžà«àª શટમà«àª² àªà«.<br/><br/>%1$s ઀à«àª¯àªŸàª ઞà«àª§à« àªàªªàªšà« ઞà«àªà«àª°à«àª® àªàª°à« શàªàª¶à«, àªà«àª¯àªŸàª ઞà«àª§à« ઀મૠઠપરવટચàªà«àªšà« àªàªà«àªžà«àªž àªàªŸàª¢à« ચહà«àª ચટàªà«."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àªà«àª°à«àªž-ડિવટàªàªž ઞà«àªµàªŸàª"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ઀મટરટ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> વ઀ૠ઀મટરટ ડિવટàªàªž વàªà«àªà« àªàªª ઞà«àªà«àª°à«àª® àªàª°àªµàªŸàªšà« પરવટચàªà«àªšà« વિચàªàª€à« àªàª°à« રહૠàªà«"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"઀મટરટ àªàª ડિવટàªàªž પરથૠબà«àªàªŸ ડિવટàªàªž પર àªàªªàªšà« ડિઞà«àªªà«àª²à« ઀à«àª®àª ઞà«àªà«àª°à«àª® àªàª°àªµàªŸ મટàªà«, <xliff:g id="APP_NAME">%1$s</xliff:g> ઀મટરટ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> વ઀ૠપરવટચàªà« મટàªà« રહૠàªà«"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"઀મટરટ ફà«àªšàª®àªŸàªàª¥à« ઠમટહિ઀ૠàªàªà«àªžà«àªž àªàª°àªµàªŸ મટàªà«, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ચૠમàªàªà«àª°à« àªàªªà«"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ઞà«àªµàªŸàª"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ઀મટરટ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> વ઀ૠ઀મટરટ ફà«àªšàªšàªŸ ફà«àªàªŸ, મà«àª¡àª¿àª¯àªŸ àª
ચૠચà«àªàª¿àª«àª¿àªà«àª¶àªš àªàªà«àªžà«àªž àªàª°àªµàªŸàªšà« પરવટચàªà«àªšà« વિચàªàª€à« àªàª°à« રહૠàªà«"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ચૠઠપàªàª²à«àª àªàª°àªµàªŸàªšà« મàªàªà«àª°à« àªàªªà«àª?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"શà«àª <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ચૠ઀મટરટ ફà«àªšàªšà« àªàªª àª
ચૠઞિઞà«àªàª®àªšà« ઞà«àªµàª¿àª§àªŸàªàªšà« ઞà«àªà«àª°à«àª® àªàª°àªµàªŸàªšà« મàªàªà«àª°à« àªàªªà«àª?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$sચૠપટઞૠàªàªµà« બધૠબટબ઀à«àªšà« àªàªà«àªžà«àªž રહà«àª¶à« àªà« ઀મટરટ ફà«àªš પર àªà«àª શàªàªŸàª€à« àªà« àªàª²àªŸàªµà« શàªàªŸàª€à« હà«àª¯, àªà«àª®àªŸàª àªàª¡àª¿àª¯à«, ફà«àªàªŸ, àªà«àªàªµàª£à«àªšà« મટહિ઀à«, પટઞવરà«àª¡ àª
ચૠમà«àªžà«àª શટમà«àª² àªà«.<br/><br/>%1$s ઀à«àª¯àªŸàª ઞà«àª§à« àªàªª àª
ચૠઞિઞà«àªàª®àªšà« ઞà«àªµàª¿àª§àªŸàªàªšà« ઞà«àªà«àª°à«àª® àªàª°à« શàªàª¶à«, àªà«àª¯àªŸàª ઞà«àª§à« ઀મૠઠપરવટચàªà«àªšà« àªàªà«àªžà«àªž àªàªŸàª¢à« ચહà«àª ચટàªà«."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ચàªà«àªàªšàªŸ ડિવટàªàªž પર àªàªª àª
ચૠઞિઞà«àªàª®àªšà« àª
ચà«àª¯ ઞà«àªµàª¿àª§àªŸàª ઞà«àªà«àª°à«àª® àªàª°àªµàªŸ ઀મટરટ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વ઀ૠપરવટચàªà«àªšà« વિચàªàª€à« àªàª°à« રહૠàªà«"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવટàªàªž"</string>
<string name="summary_generic" msgid="1761976003668044801">"ઠàªàªª ઀મટરટ ફà«àªš àª
ચૠપઞàªàªŠ àªàª°à«àª²àªŸ ડિવટàªàªž વàªà«àªà«, àªà«àª² àªàª°àªšàªŸàª° àªà«àª વà«àª¯àªà«àª€àª¿àªšà«àª ચટમ àªà«àªµà« મટહિ઀ૠઞિàªàª àªàª°à« શàªàª¶à«"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index f524b97..9b55669 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"à€¡à€¿à€µà€Ÿà€à€ž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à€¯à€¹ à€à€ªà¥à€²à€¿à€à¥à€¶à€š, à€à€ªà€à¥ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> à€ªà€° à€à€š à€
à€šà¥à€®à€€à€¿à€¯à¥à€ à€à¥ à€à€à¥à€žà¥à€ž à€à€° à€ªà€Ÿà€à€à€Ÿ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€à¥ à€
à€ªà€šà¥ à€«à€Œà¥à€š à€žà¥ à€¯à€¹ à€à€Ÿà€šà€à€Ÿà€°à¥ à€à€à¥à€žà¥à€ž à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€Šà¥à€"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€à¥ à€à€ªà€à¥ à€«à€Œà¥à€š à€à¥ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€žà¥à€à¥à€°à¥à€® à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€Šà¥à€šà¥ à€¹à¥?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s à€à¥ à€ªà€Ÿà€ž à€à€žà¥ à€à¥à€šà¥à€à¥à€à€ à€à€Ÿ à€à€à¥à€žà¥à€ž à€¹à¥à€à€Ÿ à€à¥ à€«à€Œà¥à€š à€ªà€° à€Šà€¿à€ à€°à€¹à€Ÿ à€¹à¥ à€¯à€Ÿ à€à€²à€Ÿà€¯à€Ÿ à€à€¯à€Ÿ à€¹à¥. à€à¥à€žà¥, à€à€¡à€¿à€¯à¥, à€«à€Œà¥à€à¥, à€ªà€Ÿà€žà€µà€°à¥à€¡, à€à€° à€®à¥à€žà¥à€.<br/><br/>%1$s à€€à€¬ à€€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€žà¥à€à¥à€°à¥à€® à€à€°à¥à€à€Ÿ, à€à€¬ à€€à€ à€à€ª à€à€ž à€
à€šà¥à€®à€€à€¿ à€à¥ à€¹à€à€Ÿ à€š à€Šà¥à€."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à€à¥à€°à¥à€ž-à€¡à€¿à€µà€Ÿà€à€ž à€žà¥ à€à¥à€¡à€Œà¥ à€žà¥à€µà€Ÿà€à€"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à€ªà€à¥ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€à€° à€žà¥, à€à€ªà€à¥ à€¡à€¿à€µà€Ÿà€à€žà¥à€ à€à¥ à€¬à¥à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€žà¥à€à¥à€°à¥à€® à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à€ à€°à€¹à€Ÿ à€¹à¥"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à€ªà€à¥ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€à€° à€žà¥, à€à€ªà€à¥ à€¡à€¿à€µà€Ÿà€à€žà¥à€ à€à¥ à€¬à¥à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€Šà€¿à€à€Ÿà€šà¥ à€à€° à€žà¥à€à¥à€°à¥à€® à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à€ à€°à€¹à€Ÿ à€¹à¥"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€à¥ à€
à€ªà€šà¥ à€«à€Œà¥à€š à€žà¥ à€¯à€¹ à€à€Ÿà€šà€à€Ÿà€°à¥ à€à€à¥à€žà¥à€ž à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€Šà¥à€"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à€ªà€à¥ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€à€° à€žà¥, à€à€ªà€šà¥ à€«à€Œà¥à€š à€®à¥à€ à€®à¥à€à¥à€Š à€«à€Œà¥à€à¥, à€®à¥à€¡à€¿à€¯à€Ÿ, à€à€° à€žà¥à€à€šà€Ÿà€à€ à€à¥ à€à€à¥à€žà¥à€ž à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à€ à€°à€¹à€Ÿ à€¹à¥"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"à€à¥à€¯à€Ÿ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€à¥ à€¯à€¹ à€à€Ÿà€°à¥à€°à€µà€Ÿà€ à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€Šà¥à€šà¥ à€¹à¥?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€à¥ à€à€ªà€à¥ à€«à€Œà¥à€š à€à¥ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à€° à€žà€¿à€žà¥à€à€® à€à¥ à€žà¥à€µà€¿à€§à€Ÿà€à€ à€žà¥à€à¥à€°à¥à€® à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€Šà¥à€šà¥ à€¹à¥?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s à€à¥ à€ªà€Ÿà€ž à€à€žà¥ à€à¥à€šà¥à€à¥à€à€ à€à€Ÿ à€à€à¥à€žà¥à€ž à€¹à¥à€à€Ÿ à€à¥ à€«à€Œà¥à€š à€ªà€° à€Šà€¿à€ à€°à€¹à€Ÿ à€¹à¥ à€¯à€Ÿ à€à€²à€Ÿà€¯à€Ÿ à€à€¯à€Ÿ à€¹à¥. à€à¥à€žà¥, à€à€¡à€¿à€¯à¥, à€«à€Œà¥à€à¥, à€ªà¥à€®à¥à€à€ à€žà¥ à€à¥à€¡à€Œà¥ à€à€Ÿà€šà€à€Ÿà€°à¥, à€ªà€Ÿà€žà€µà€°à¥à€¡, à€à€° à€®à¥à€žà¥à€.<br/><br/>%1$s à€€à€¬ à€€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à€° à€žà€¿à€žà¥à€à€® à€à¥ à€žà¥à€µà€¿à€§à€Ÿà€à€ à€à¥ à€žà¥à€à¥à€°à¥à€® à€à€°à¥à€à€Ÿ, à€à€¬ à€€à€ à€à€ª à€à€ž à€
à€šà¥à€®à€€à€¿ à€à¥ à€¹à€à€Ÿ à€š à€Šà¥à€."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à€ªà€à¥ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à€à¥ à€à€° à€žà¥, à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à€° à€Šà¥à€žà€°à¥ à€žà€¿à€žà¥à€à€® à€à¥ à€žà¥à€µà€¿à€§à€Ÿà€à€ à€à¥ à€à€ž-à€ªà€Ÿà€ž à€®à¥à€à¥à€Š à€¡à€¿à€µà€Ÿà€à€žà¥à€ à€ªà€° à€žà¥à€à¥à€°à¥à€® à€à€°à€šà¥ à€à¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à€ à€°à€¹à€Ÿ à€¹à¥"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"à€¡à€¿à€µà€Ÿà€à€ž"</string>
<string name="summary_generic" msgid="1761976003668044801">"à€¯à€¹ à€à€ªà¥à€²à€¿à€à¥à€¶à€š, à€à€ªà€à¥ à€«à€Œà¥à€š à€à€° à€à¥à€šà¥ à€¹à¥à€ à€¡à€¿à€µà€Ÿà€à€ž à€à¥ à€¬à¥à€ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà€¿à€à€ à€à€°à¥à€à€Ÿ. à€à¥à€žà¥, à€à¥à€² à€à€°à€šà¥ à€µà€Ÿà€²à¥ à€µà¥à€¯à€à¥à€€à€¿ à€à€Ÿ à€šà€Ÿà€®"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 5ed3eb2..b627998 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ureÄaj"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Aplikacija Äe moÄi pristupati ovim dopuštenjima na vašem ureÄaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"OmoguÄite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Åœelite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da streama aplikacije vašeg telefona?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"Aplikacija %1$s imat Äe pristup svemu što je vidljivo ili se reproducira na telefonu, ukljuÄujuÄi zvuk, fotografije, zaporke i poruke.<br/><br/>Aplikacija %1$s moÄi Äe streamati aplikacije dok ne uklonite pristup za to dopuštenje."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na razliÄitim ureÄajima"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za stream aplikacija s jednog ureÄaja na drugi"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za prikaz i streaming aplikacija s jednog ureÄaja na drugi"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"OmoguÄite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg ureÄaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> za pristup fotografijama, medijskim sadrÅŸajima i obavijestima na telefonu"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Åœelite li ureÄaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dopustiti da izvrši tu radnju?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Åœelite li dopustiti ureÄaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da streama aplikacije i znaÄajke sustava vašeg telefona?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Aplikacija %1$s imat Äe pristup svemu što je vidljivo ili se reproducira na telefonu, ukljuÄujuÄi zvuk, fotografije, podatke o plaÄanju, zaporke i poruke.<br/><br/>Aplikacija %1$s moÄi Äe streamati aplikacije i znaÄajke sustava dok ne uklonite pristup za to dopuštenje."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg ureÄaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za emitiranje aplikacija i drugih znaÄajki sustava na ureÄajima u blizini"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ureÄaj"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ta Äe aplikacija moÄi sinkronizirati podatke izmeÄu vašeg telefona i odabranog ureÄaja, primjerice ime pozivatelja"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 8082bb5..1c9c218 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"eszköz"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Az alkalmazás hozzáférhet majd ezekhez az engedélyekhez az Ön <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközén"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> számára a telefonja alkalmazásainak streamelését?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"A(z) %1$s hozzáférhet mindenhez, ami a telefonon látható vagy lejátszható, így az audiotartalomhoz, fényképekhez, jelszavakhoz és üzenetekhez is.<br/><br/>Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) %1$s képes lesz majd az alkalmazások streamelésére."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nevében az alkalmazások eszközök közötti streameléséhez"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nevében az alkalmazások eszközök közötti megjelenítéséhez és streameléséhez."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nevében a telefonon tárolt fotókhoz, médiatartalmakhoz és értesítésekhez való hozzáféréshez"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Engedélyezi a(z) <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> számára ennek a műveletnek a végrehajtását?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Engedélyezi a(z) <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> számára a telefonja alkalmazásainak és rendszerfunkcióinak streamelését?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"A(z) %1$s hozzáférhet mindenhez, ami a telefonon látható vagy lejátszható, így az audiotartalomhoz, fényképekhez, fizetési adatokhoz, jelszavakhoz és üzenetekhez is.<br/><br/>Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) %1$s képes lesz majd az alkalmazások és a rendszerfunkciók streamelésére."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások és más rendszerfunkciók közeli eszközökre történÅ streamelésére"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a kiválasztott eszköz között, mint például a hívó fél neve."</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index fc8adee..c4de3cd 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"՜աÖÖ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš կ՜տանա Õ°Õ¥Õ¿ÖÕµÕ¡Õ¬ Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš Õ±Õ¥Ö <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ÕžÖÕŽ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ô¹ÕžÖÕµÕ¬Õ¡Õ¿ÖÕ¥Ö <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ«Õ¶ Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬ Õ¡ÕµÕœ Õ¿Õ¥Õ²Õ¥Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜իÖ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ô¹ÕžÖÕµÕ¬Õ¡Õ¿ÖÕ¥ÕÕ¬ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ«Õ¶ հեՌաÖÕ±Õ¡Õ¯Õ¥Õ¬ Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜ի Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕš"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ«Õ¶ հա՜անելի Õ¯Õ¬Õ«Õ¶Õ« հեՌաÕ՞՜՞ÖÕŽ ÖÕžÖÖÕ¡Õ€ÖÕŸÕžÕ² Õ¯Õ¡ÕŽ Õ¶ÕŸÕ¡Õ£Õ¡ÖÕ¯ÕŸÕžÕ² Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶ÕšÕ Õ¶Õ¥ÖաՌյալ Õ¡ÕžÖÕ€Õ«ÕžÕ¶, Õ¬ÕžÖ՜անկաÖÕ¶Õ¥ÖÕš, գաղտնաբաՌեÖÕš Ö Õ°Õ¡Õ²ÕžÖÕ€Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕšÖ<br/><br/>%1$s Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ¯Õ¯Õ¡ÖÕžÕ²Õ¡Õ¶Õ¡ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥Ö Õ°Õ¥ÕŒÕ¡ÖÕ±Õ¡Õ¯Õ¥Õ¬, ÖÕ¡Õ¶Õ« Õ€Õ¥ÕŒ Õ¹Õ¥Ö Õ¹Õ¥Õ²Õ¡ÖÕ¯Õ¥Õ¬ Õ¡ÕµÕœ Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ÕšÖ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Õիջ՜աÖÖÕ¡ÕµÕ«Õ¶ ծաՌայ՞ÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ±Õ¥Ö <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ՜աÖÖÕ« Õ¡Õ¶ÕžÖÕ¶Õ«Ö Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ Õ§ ÕÕ¶Õ€ÖÕžÖÕŽÕ Õ±Õ¥Ö ÕœÕ¡ÖÖÕ¥ÖÕ« ÕŽÕ«Õ»Ö Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥Ö Õ°Õ¥ÕŒÕ¡ÖÕ±Õ¡Õ¯Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ±Õ¥Ö <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ՜աÖÖÕ« Õ¡Õ¶ÕžÖÕ¶Õ«Ö Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ Õ§ ÕÕ¶Õ€ÖÕžÖÕŽÕ Õ±Õ¥Ö ÕœÕ¡ÖÖÕ¥ÖÕ« ÕŽÕ«Õ»Ö Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥Ö Õ°Õ¥ÕŒÕ¡ÖÕ±Õ¡Õ¯Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ô¹ÕžÖÕµÕ¬Õ¡Õ¿ÖÕ¥Ö <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ«Õ¶ Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬ Õ¡ÕµÕœ Õ¿Õ¥Õ²Õ¥Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜իÖ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծաՌայ՞ÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ±Õ¥Ö <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ՜աÖÖÕ« Õ¡Õ¶ÕžÖÕ¶Õ«Ö Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ Õ§ ÕÕ¶Õ€ÖÕžÖÕŽÕ Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜ի Õ¬ÕžÖ՜անկաÖÕ¶Õ¥ÖÕš, ÕŽÕ¥Õ€Õ«Õ¡ÖÕ¡ÕµÕ¬Õ¥ÖÕ¶ ÕžÖ Õ®Õ¡Õ¶ÕžÖÖÕžÖÕŽÕ¶Õ¥ÖÕš Õ¿Õ¥ÕœÕ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ô¹ÕžÖÕµÕ¬Õ¡Õ¿ÖÕ¥ÕÕ¬ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ«Õ¶ Õ¯Õ¡Õ¿Õ¡ÖÕ¥Õ¬ Õ¡ÕµÕœ Õ£ÕžÖÕ®ÕžÕ²ÕžÖÕ©ÕµÕžÖÕ¶Õš"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Ô¹ÕžÖÕµÕ¬Õ¡Õ¿ÖÕ¥ÕÕ¬ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ՜աÖÖÕ«Õ¶ հեՌաÖÕ±Õ¡Õ¯Õ¥Õ¬ Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜ի Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕš Ö Õ°Õ¡ÕŽÕ¡Õ¯Õ¡ÖÕ£Õ« Õ£ÕžÖծաՌ՞ÖÕµÕ©Õ¶Õ¥ÖÕš"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ՜աÖÖÕ«Õ¶ հա՜անելի Õ¯Õ¬Õ«Õ¶Õ« Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜՞ÖÕŽ ÖÕžÖÖÕ¡Õ€ÖÕŸÕžÕ² Õ¯Õ¡ÕŽ Õ¶ÕŸÕ¡Õ£Õ¡ÖÕ¯ÕŸÕžÕ² Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶ÕšÕ Õ¶Õ¥ÖաՌյալ Õ¡ÕžÖÕ€Õ«ÕžÕ¶, Õ¬ÕžÖ՜անկաÖÕ¶Õ¥ÖÕš, ÕŸÕ³Õ¡ÖÕ¡ÕµÕ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš, գաղտնաբաՌեÖÕš Ö Õ°Õ¡Õ²ÕžÖÕ€Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕšÖ<br/><br/>%1$s ՜աÖÖÕš Õ¯Õ¯Õ¡ÖÕžÕ²Õ¡Õ¶Õ¡ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥Ö Ö Õ°Õ¡ÕŽÕ¡Õ¯Õ¡ÖÕ£Õ« Õ£ÕžÖծաՌ՞ÖÕµÕ©Õ¶Õ¥Ö Õ°Õ¥ÕŒÕ¡ÖÕ±Õ¡Õ¯Õ¥Õ¬, ÖÕ¡Õ¶Õ« Õ€Õ¥ÕŒ Õ¹Õ¥Ö Õ¹Õ¥Õ²Õ¡ÖÕ¯Õ¥Õ¬ Õ¡ÕµÕœ Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ÕšÖ"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ±Õ¥Ö <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ՜աÖÖÕ« Õ¡Õ¶ÕžÖÕ¶Õ«Ö Õ©ÕžÖÕµÕ¬Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ Õ§ ÕÕ¶Õ€ÖÕžÖÕŽÕ ÕŽÕžÕ¿Õ¡Õ¯Õ¡ ՜աÖÖÕ¥ÖÕ«Õ¶ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥Ö Ö Õ°Õ¡ÕŽÕ¡Õ¯Õ¡ÖÕ£Õ« Õ¡ÕµÕ¬ Õ£ÕžÖծաՌ՞ÖÕµÕ©Õ¶Õ¥Ö Õ°Õ¥ÕŒÕ¡ÖÕ±Õ¡Õ¯Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"՜աÖÖ"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ¯Õ¯Õ¡ÖÕžÕ²Õ¡Õ¶Õ¡ Õ°Õ¡ÕŽÕ¡ÕªÕ¡ÕŽÕ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Ö Õ°Õ¥ÕŒÕ¡Õ՞՜ի Ö ÕšÕ¶Õ¿ÖÕŸÕ¡Õ® ՜աÖÖÕ« Õ¿ÕŸÕµÕ¡Õ¬Õ¶Õ¥ÖÕš, Ö
Öâ€Õ ÕŠÕ¡Õ¶Õ£ÕžÕ²Õ« Õ¡Õ¶ÕžÖÕ¶Õš"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index c281455..b1c4f5b 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"perangkat"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Aplikasi ini akan diizinkan mengakses izin ini di <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> melakukan streaming aplikasi di ponsel Anda?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s akan memiliki akses ke konten apa pun yang ditampilkan atau dimainkan di ponsel, termasuk audio, foto, sandi, dan pesan.<br/><br/>%1$s akan dapat melakukan streaming aplikasi hingga Anda menghapus izin ini."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggantikan <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> meminta izin untuk menampilkan dan melakukan streaming aplikasi di antara perangkat Anda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses informasi ini dari ponsel Anda"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan tindakan ini?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan streaming aplikasi dan mengakses fitur sistem di ponsel Anda?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s akan memiliki akses ke konten apa pun yang ditampilkan atau dimainkan di ponsel Anda, termasuk audio, foto, info pembayaran, sandi, dan pesan.<br/><br/>%1$s akan dapat melakukan streaming aplikasi dan mengakses fitur sistem hingga Anda menghapus izin ini."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstreaming aplikasi dan fitur sistem lainnya ke perangkat di sekitar"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
<string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 42ca7da..befc55c 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"tæki"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Þetta forrit fær aðgang að eftirfarandi heimildum í <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að streyma forritum símans?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s fær aðgang að öllu sem er sýnilegt eða spilað í símanum, þ.m.t. hljóði, myndum, aðgangsorðum og skilaboðum.<br/><br/>%1$s getur streymt forritum þar til þú fjarlægir aðgang að þessari heimild."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til að streyma forritum á milli tækjanna þinna"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til að birta og streyma forritum á milli tækjanna þinna"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um aðgang að myndum, margmiðlunarefni og tilkynningum símans þíns fyrir hönd <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leyfa <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> að framkvæma þessa aðgerð?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Leyfa <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> að streyma forritum og kerfiseiginleikum símans?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s fær aðgang að öllu sem er sýnilegt eða spilað í símanum, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.<br/><br/>%1$s getur streymt forritum og kerfiseiginleikum þar til þú fjarlægir aðgang að þessari heimild."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum og öðrum kerfiseiginleikum í nálægum tækjum"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
<string name="summary_generic" msgid="1761976003668044801">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og valins tækis"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 06d58b6..40d3be5 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Questa app potrà accedere alle seguenti autorizzazioni su <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Consentire a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di riprodurre in streaming le app del tuo smartphone?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s avrà accesso a tutto ciò che è visibile o riprodotto sullo smartphone, inclusi audio, foto, password e messaggi.<br/><br/>%1$s sarà in grado di riprodurre in streaming le app finché non rimuoverai l\'accesso a questa autorizzazione."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> l\'autorizzazione a trasmettere app in streaming tra i dispositivi"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> l\'autorizzazione a visualizzare e riprodurre in streaming app tra i dispositivi"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a questa informazione dal tuo telefono"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche del telefono"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vuoi consentire a <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> di compiere questa azione?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Consentire a <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> di riprodurre in streaming app e funzionalità di sistema del tuo smartphone?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s avrà accesso a tutto ciò che è visibile o riprodotto sullo smartphone, inclusi audio, foto, dati di pagamento, password e messaggi.<br/><br/>%1$s sarà in grado di riprodurre in streaming app e funzionalità di sistema finché non rimuoverai l\'accesso a questa autorizzazione."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione a trasmettere in streaming app e altre funzionalità di sistema ai dispositivi nelle vicinanze"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 49d1f9e..f1eb5347 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"××ש×ך"</string>
<string name="summary_glasses" msgid="2872254734959842579">"×××€××ק׊×× ××× ×ª××× ××שת ××ךש××ת ×××× ×<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ש××"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"××ª× ××ש×ך ×××€××ק׊×× <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ××שת ×××××¢ ××× ×××××€×× ×©××"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"××שך ×××€××ק׊××ת <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ×ש×ך ×ת ×××€××ק׊××ת ×©× ××××€××?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"×-%1$s ת××× ×××©× ××× ×× ×©×š×××× ×× ××€×¢×××× ××××€××, ×××× ×××××, ת××× ×ת, ס×ס×××ת ×××××¢×ת.<br/><br/>×-%1$s ת××× ×׀שך×ת ×ש×ך ××€××ק׊××ת ×¢× ×©××××©× ××ךש×× ××× ×ª×סך."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ש×ך×ת×× ××ס׀ך ××ש×ך××"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"×××€××ק׊×× <xliff:g id="APP_NAME">%1$s</xliff:g> ××קשת ×ךש×× ×¢××ך ×××ש×ך <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ××× ×ש×ך ××€××ק׊××ת ××× ×××ש×ך×× ×©××"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"×××€××ק׊×× <xliff:g id="APP_NAME">%1$s</xliff:g> ××קשת ×ךש×× ×××ש×ך <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ××× ××׊×× ××ש×ך ××€××ק׊××ת ××× ×××ש×ך×× ×©××"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"××ª× ××ש×ך ×××€××ק׊×× <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ××שת ×××××¢ ××× ×××××€×× ×©××"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"×××€××ק׊×× <xliff:g id="APP_NAME">%1$s</xliff:g> ××קשת ×ךש×× ×¢××ך ×××ש×ך <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ××× ××שת ×ת××× ×ת, ××××× ×××תך××ת ××××€×× ×©××"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"×תת ×ךש×× ×××ש×ך <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ××׊ע ×ת ××€×¢××× ×××?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"××שך ×××€××ק׊××ת <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ×ש×ך ×ת ×××€××ק׊××ת ××ת ת××× ×ת ××עך×ת ×©× ××××€××?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"×-%1$s ת××× ×××©× ××× ×× ×©×š×××× ×× ××€×¢×××× ××××€××, ×××× ×××××, ת××× ×ת, ׀ך×× ×ª×©×××, ס×ס×××ת ×××××¢×ת.<br/><br/>×-%1$s ת××× ×׀שך×ת ×ש×ך ××€××ק׊××ת ×ת××× ×ת ×עך×ת ×¢× ×©××××©× ××ךש×× ××× ×ª×סך."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"×××€××ק׊×× <xliff:g id="APP_NAME">%1$s</xliff:g> ××קשת ×ךש×× ×¢××ך <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ××× ×××¢××ך ××€××ק׊××ת ×ת××× ×ת ×עך×ת ××ך×ת ×ס×ך×××× × ×××ש×ך×× ×קך×ת ××§××"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"××ש×ך"</string>
<string name="summary_generic" msgid="1761976003668044801">"×××€××ק׊×× ××× ×ª××× ××¡× ××š× ××××¢, ××× ××©× ×©× ××ש×× ×©×תקשך, ×××××€×× ×©×× ×××ש×ך ש××ךת"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 3ad80ba..ced2802 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ááá¬á§ááááááá"</string>
<string name="summary_glasses" msgid="2872254734959842579">"áá¡ ááá ášáá«áááá¡ áá ááááá áááááá á¬áááááá¡ áá¥áááá¡ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ášá"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"áááá ááá ááá, á áá <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ááá¡ á°á¥ááááá¡ áá ááá€áá áááªáááá á¬ááááá áá¥áááá á¢áááá€áááááá"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"áá¡á£á á <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-á¡ ááá¡áªáá á¢áááá€áááá¡ áááááá¡ á¡á¢á ááááááá¡ á¡áášá£ááááá?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s-á¡ áá¥áááá á¬ááááá á§ááááá€áá áá, á á᪠á©ááá¡ áá á£áá ááá¡ á¢áááá€áááá, ááá ášáá áá¡, áá£ááááá, á€áá¢ááááá, ááá ááááá¡á áá ášáá¢á§áááááááááá.<br/><br/>%1$s ášáá«áááá¡ áááááá¡ ááášááááá¡ ááááá, á¡áááá áá¥ááá áá áááá£á¥áááá á¬áááááá¡ áá ááááá ááááá."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ááá¬á§ááááááááášáá áá¡á á¡áá ááá¡ááá"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááá®ááá¡ á£á€ááááá¡ áá¥áááá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-áá¡ á¡áá®áááá, á áá ááá¬á§ááááááááá¡ ášáá áá¡ á¡á¢á áááááá ášáá«ááá¡"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááá®ááá¡ ááááá áááá¡ áá¥áááá (<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>) á¡áá®áááá, á ááá á¬áá áááá©áááá¡ áá áááá®ááááá¡ áááááá¡ ááášáááá áá¥áááá¡ ááá¬á§ááááááááá¡ ášáá áá¡"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"áááá ááá ááá, á áá <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ááá¡ á°á¥ááááá¡ áá ááá€áá áááªáááá á¬ááááá áá¥áááá á¢áááá€áááááá"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááá®ááá¡ á£á€ááááá¡ áá¥áááá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-áá¡ á¡áá®áááá, á áá á¬ááááá á°á¥ááááá¡ áá¥áááá á¢áááá€áááá¡ á€áá¢ááááá, áááááá¡á áá ášáá¢á§áááááááááá"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"áá¡á£á á áááá ááá¡áªáá <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g>-á¡</strong> áá ááá¥ááááááá¡ ášáá¡áá¡á á£áááááá?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"áá¡á£á á <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-á¡ ááá¡áªáá áá¥áááá á¢áááá€áááá¡ áááááá¡á áá á¡áá¡á¢áááá¡ á€á£áá¥áªááááá¡ á¡á¢á ááááááá¡ á¡áášá£ááááá?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s-á¡ áá¥áááá á¬ááááá á§ááááá€áá áá, á á᪠á©ááá¡ áá á£áá ááá¡ á¢áááá€áááá, ááá ášáá áá¡, áá£ááááá, á€áá¢ááááá, ááááá®ááá¡ ááá€áá áááªáááá, ááá ááááá¡á áá ášáá¢á§áááááááááá.<br/><br/>%1$s ášáá«áááá¡ áááááá¡á áá á¡áá¡á¢áááá¡ á€á£áá¥áªááááá¡ ááášááááá¡ ááááá, á¡áááá áá¥ááá áá áááá£á¥áááá á¬áááááá¡ áá ááááá ááááá."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááá®ááá¡ áá¥áááá <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-áá¡ á¡áá®áááá áááááá¡ áá á¡áá¡á¢áááá¡ á¡á®áá á€á£áá¥áªááááá¡ áá®ááááá®áá ááá¬á§áááááááááá á¡á¢á ááááááá¡ ááááá áááá¡"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ááá¬á§ááááááá"</string>
<string name="summary_generic" msgid="1761976003668044801">"áá¡ ááá ášáá«áááá¡ ááá€áá áááªááá¡ á¡ááá¥á áááááááá¡ áá¥áááá¡ á¢áááá€ááá¡á áá áá¥ááá áááá áá á©áá£á ááá¬á§áááááááá¡ ášáá áá¡, ááááááááá, áá ááááááááá¡ á¡áá®áááá¡, á ááááá᪠ááá ááááá"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 4e4986e..b981bf4 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÒÒ±ÑÑлÒÑ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ðұл ÒПлЎаМба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ÒÒ±ÑÑлÒÑÑÑМЎа ПÑÑ ÑÒ±ÒÑаÑÑаÑÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÐ° алаЎÑ."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÒПлЎаМбаÑÑМа ÑелеÑПМÑÒ£ÑзЎаÒÑ ÐŸÑÑ Ð°ÒпаÑаÑÑÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒа ÑÒ±ÒÑÐ°Ñ Ð±ÐµÑÑÒ£Ñз."</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÒПлЎаМбаÑÑМа ÑелеÑПМЎаÒÑ ÒПлЎаМбалаÑÐŽÑ ÑÑаМÑлÑÑОÑлаÑÒа ÑÒ±ÒÑÐ°Ñ Ð±ÐµÑÑлÑÑМ бе?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ÑелеÑПМЎа көÑÑМеÑÑМ Ме ПйМаÑÑлаÑÑМ кез келгеМ кПМÑеМÑÑÑ (аÑЎОПÑайлЎаÑÐŽÑ, ÑПÑПÑÑÑеÑÑеÑÐŽÑ, ÒÒ±Ð¿ÐžÑ ÑÓ©Ð·ÐŽÐµÑ ÐŒÐµÐœ Ñ
абаÑлаÑÐŽÑ ÒПÑа алÒаМЎа) пайЎалаМа алаЎÑ.<br/><br/>ӚзÑÒ£Ñз ПÑÑ ÑÒ±ÒÑаÑÑÑ Ó©ÑÑÑЌеÑеңÑз, %1$s ÒПлЎаМбалаÑÐŽÑ ÑÑаМÑлÑÑОÑлай алаЎÑ."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ÐÑалÑÒ ÒÒ±ÑÑлÒÑ ÒÑзЌеÑÑеÑÑ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÒПлЎаМбаÑÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> аÑÑМаМ ÒÒ±ÑÑлÒÑÐ»Ð°Ñ Ð°ÑаÑÑМЎа ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°Ð»Ð°Ñ ÑÑаМÑлÑÑОÑÐ»Ð°Ñ Ò¯ÑÑМ ÑÒ±ÒÑÐ°Ñ ÑÒ±ÑайЎÑ."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÒПлЎаМбаÑÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> аÑÑМаМ ÒÒ±ÑÑлÒÑÐ»Ð°Ñ Ð°ÑаÑÑМЎа ÒПлЎаМбалаÑÐŽÑ ÐºÓ©ÑÑеÑÑге жÓМе ÑÑаМÑлÑÑОÑлаÑÒа ÑÒ±ÒÑÐ°Ñ ÑÒ±ÑайЎÑ."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÒПлЎаМбаÑÑМа ÑелеÑПМÑÒ£ÑзЎаÒÑ ÐŸÑÑ Ð°ÒпаÑаÑÑÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒа ÑÒ±ÒÑÐ°Ñ Ð±ÐµÑÑÒ£Ñз."</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ÒÑзЌеÑÑеÑÑ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÒПлЎаМбаÑÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> аÑÑМаМ ÑелеÑПМЎаÒÑ ÑПÑПÑÑÑеÑÑеÑÐŽÑ, ЌеЎОаÑÐ°Ð¹Ð»ÐŽÐ°Ñ ÐŒÐµÐœ Ñ
абаÑлаМЎÑÑÑлаÑÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑ Ò¯ÑÑМ ÑÒ±ÒÑÐ°Ñ ÑÒ±ÑайЎÑ."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÒÒ±ÑÑлÒÑÑÑМа бұл ÓÑекеÑÑÑ ÐŸÑÑМЎаÑÒа ÑÒ±ÒÑÐ°Ñ Ð±ÐµÑÑ ÐºÐµÑек пе?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÒÒ±ÑÑлÒÑÑÑМа ÑелеÑПМЎаÒÑ ÒПлЎаМбалаÑÐŽÑ Ð¶ÓМе жүйе ÑÑМкÑОÑлаÑÑМ ÑÑаМÑлÑÑОÑлаÑÒа ÑÒ±ÒÑÐ°Ñ Ð±ÐµÑÑлÑÑМ бе?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ÑелеÑПМЎа көÑÑМеÑÑМ Ме ПйМаÑÑлаÑÑМ кез келгеМ кПМÑеМÑÑÑ (аÑЎОПÑайлЎаÑÐŽÑ, ÑПÑПÑÑÑеÑÑеÑÐŽÑ, ÑөлеЌ ÑÑÑÐ°Ð»Ñ Ð°ÒпаÑаÑÑÑ, ÒÒ±Ð¿ÐžÑ ÑÓ©Ð·ÐŽÐµÑ ÐŒÐµÐœ Ñ
абаÑлаÑÐŽÑ ÒПÑа алÒаМЎа) пайЎалаМа алаЎÑ.<br/><br/>ӚзÑÒ£Ñз ПÑÑ ÑÒ±ÒÑаÑÑÑ Ó©ÑÑÑЌеÑеңÑз, %1$s ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°Ð»Ð°Ñ ÐŒÐµÐœ жүйе ÑÑМкÑОÑлаÑÑМ ÑÑаМÑлÑÑОÑлай алаЎÑ."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÒПлЎаМбаÑÑ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> аÑÑМаМ ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°Ð»Ð°Ñ ÐŒÐµÐœ баÑÒа Ўа жүйе ÑÑМкÑОÑлаÑÑМ ЌаңайЎаÒÑ ÒÒ±ÑÑлÒÑлаÑÒа ÑÑаМÑлÑÑОÑÐ»Ð°Ñ ÑÒ±ÒÑаÑÑМ ÑÒ±Ñап ÑÒ±Ñ."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÒÒ±ÑÑлÒÑ"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ðұл ÒПлЎаМба ÑелеÑПМ ЌеМ ÑаңЎалÒаМ ÒÒ±ÑÑлÒÑ Ð°ÑаÑÑМЎа ЎеÑекÑÑ (ÐŒÑÑалÑ, ÒПңÑÑÐ°Ñ ÑалÑÑÑМÑÒ£ аÑÑМ) ÑОМÑ
ÑПМЎай алаЎÑ."</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 4646e11..41cdf95 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"á§ááááá"</string>
<string name="summary_glasses" msgid="2872254734959842579">"áááááá·áážáááâáá¹áááááŒááá¶áá¢áá»áááá¶áá±ááâá
áŒáááááŸáááá¶áááá¶áá¢áá»áááá¶ááá¶áááááâáá
á០<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ááááá¢ááá"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"á¢áá»áááá¶áá±áá <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> á
áŒáááááŸáááááá¶áááááážááŒáááááááááá¢ááá"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"á¢áá»áááá¶áá±áá <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> áááá¶ááááááá·áážááŸááŒáááááááááá¢áááá¬?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s áá¹ááá¶ááá·áááá·á
áŒáááááŸá¢ááážááááá¢á¶á
ááŸáááŸá á¬ááááŒááá¶áá
á¶áááá
ááŸááŒááááá ááœááá¶ááááá¡áá ááŒááá áá¶áááááááá¶áá áá·ááá¶áá<br/><br/>%1$s áá¹áá¢á¶á
áááá¶ááááááá·ááž áá áŒááá¶ááááá¢ááááááá·áááá·á
áŒáááááŸáá¶áá¢áá»áááá¶ááááá
ááá"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"áááá¶áááááááááá¶ááá§ááááá"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> áááá»áááááŸáá»ááá¶áá¢áá»áááá¶áááááœáá±áá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááááá¢ááá ááŸáááážáááá
á¶áááááááá·áážááá¶áá§áááááááááá¢ááá"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> áááá»áááááŸáá»ááá¶áá¢áá»áááá¶áááááœáá±áá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááááá¢ááá ááŸáááážáááá á¶á áá·ááááá¶ááááááá·áážááá¶áá§ááááááá¶áá¶ááááá¢ááá"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"á¢áá»áááá¶áá±áá <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> á
áŒáááŸááááááá¶áááááážááŒáááááááááá¢ááá"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"áááá¶áááá Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> áááá»áááááŸáá»ááá¶áá¢áá»áááá¶áááááœáá±áá <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááááá¢ááá ááŸáááážá
áŒáááááŸááŒááá áááá áá·ááá¶áááŒááááá¹áááááááŒáááááá¢ááá"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"á¢áá»áááá¶áá±áá <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ááááŸááááááá¶ááááá¬?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"á¢áá»áááá¶áá±áá <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> áááá¶ááá»ááá¶ááááááááá áá·ááááááá·áážááŸááŒáááááááááá¢áááá¬?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s áá¹ááá¶ááá·áááá·á
áŒáááááŸá¢ááážááááá¢á¶á
ááŸáááŸá á¬ááááŒááá¶áá
á¶áááá
ááŸááŒáááááááááá¢ááá ááœááá¶ááááá¡áá ááŒááá áááááá¶ááááá¶áááŒáá¶áááááá¶áá áá¶áááááááá¶áá áá·ááá¶áá<br/><br/>%1$s áá¹áá¢á¶á
áááá¶ááááááá·ááž áá·ááá»ááá¶ááááááááá áá áŒááá¶ááááá¢ááááááá·áááá·á
áŒáááááŸáá¶áá¢áá»áááá¶ááááá
ááá"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> áááá»áááááŸáá»áâáá¶áá¢áá»áááá¶áááááœáá±áá <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ááááá¢ááá ááŸáááážá
á¶áááááá¶ááááááá·ááž áá·ááá»ááá¶áááááááááááááááááâáá
áá¶ááâá§ááááááá
áá·á"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"á§ááááá"</string>
<string name="summary_generic" msgid="1761976003668044801">"áááááá·áážááááá¹áá¢á¶á
âááááŸáááá¶ááááááááááá¶á ááŒá
áá¶áááááááá»ááááááá á
ááŒááááááá¶ááŸáâ ááá¶áá§áááááááááá¶áááááŸáááŸá áá·áááŒáááááááááá¢ááá"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 4f2bdd2..7aace82 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ಞಟಧಚ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ಚಿಮà³à²® <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಚಲà³à²²à²¿ ಠà²
ಚà³à²®à²€à²¿à²à²³à²šà³à²šà³ à²à³à²¯à²à³à²žà³à²žà³ ಮಟಡಲೠಠà²à³à²¯à²ªà³à²à³ à²
ಚà³à²®à²€à²¿à²žà²²à²Ÿà²à³à²€à³à²€à²Šà³"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ಚಿಮà³à²® ಫà³à²šà³ ಮà³à²²à² ಠಮಟಹಿಀಿಯಚà³à²šà³ à²à³à²¯à²à³à²žà³à²žà³ ಮಟಡಲೠ<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à²à³ à²
ಚà³à²®à²€à²¿à²žà²¿"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ಚಿಮà³à²® ಫà³à²šà³à²šà²²à³à²²à²¿à²š à²à³à²¯à²ªà³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠ<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à²à³ à²
ಚà³à²®à²€à²¿à²žà²¬à³à²à³?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"à²à²¡à²¿à²¯à³, ಫà³à²à³à²à²³à³, ಪಟಞà³à²µà²°à³à²¡à³à²à²³à³ ಮಀà³à²€à³ ಞà²à²Šà³à²¶à²à²³à³ ಞà³à²°à²¿à²Šà²à²€à³ ಚಿಮà³à²® ಫà³à²šà³à²šà²²à³à²²à²¿ à²à³à²à²°à²¿à²žà³à²µ à²
ಥವಟ ಪà³à²²à³ à²à²à³à²µ ಯಟವà³à²Šà³ à²à²à²à³à²à²à³à²à³ %1$s à²à³à²¯à²à³à²žà³à²žà³ ಹà³à²à²Šà²¿à²°à³à²€à³à²€à²Šà³.<br/><br/>ಚà³à²µà³ ಠà²
ಚà³à²®à²€à²¿à²à³ à²à²°à³à²µ à²à³à²¯à²à³à²žà³à²žà³ à²
ಚà³à²šà³ ಀà³à²à³à²Šà³à²¹à²Ÿà²à³à²µà²µà²°à³à²à³ %1$s à²à³ à²à³à²¯à²ªà³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠಞಟಧà³à²¯à²µà²Ÿà²à³à²€à³à²€à²Šà³."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à²à³à²°à²Ÿà²žà³-ಡಿವà³à²žà³ ಞà³à²µà³à²à²³à³"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ಚಿಮà³à²® ಞಟಧಚà²à²³ ಚಡà³à²µà³ à²à³à²¯à²ªà³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠಚಿಮà³à²® <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ಚ ಪರವಟà²à²¿ <xliff:g id="APP_NAME">%1$s</xliff:g> à²
ಚà³à²®à²€à²¿à²¯à²šà³à²šà³ ವಿಚà²à²€à²¿à²žà²¿à²à³à²³à³à²³à³à²€à³à²€à²¿à²Šà³"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ಚಿಮà³à²® ಞಟಧಚà²à²³ ಚಡà³à²µà³ à²à³à²¯à²ªà³à²à²³à²šà³à²šà³ ಪà³à²°à²Šà²°à³à²¶à²¿à²žà²²à³ ಮಀà³à²€à³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠಚಿಮà³à²® <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ಪರವಟà²à²¿ <xliff:g id="APP_NAME">%1$s</xliff:g> à²
ಚà³à²®à²€à²¿à²¯à²šà³à²šà³ ವಿಚà²à²€à²¿à²žà³à²€à³à²€à²¿à²Šà³"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ಚಿಮà³à²® ಫà³à²šà³ ಮà³à²²à² ಠಮಟಹಿಀಿಯಚà³à²šà³ ಪà³à²°à²µà³à²¶à²¿à²žà²²à³ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à²à³ à²
ಚà³à²®à²€à²¿à²žà²¿"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಞà³à²µà³à²à²³à³"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ಚಿಮà³à²® ಫà³à²šà³à²š ಫà³à²à³à²à²³à³, ಮà³à²¡à²¿à²¯à²Ÿ ಮಀà³à²€à³ à²
ಧಿಞà³à²à²šà³à²à²³à²šà³à²šà³ à²à³à²¯à²à³à²žà³à²žà³ ಮಟಡಲೠಚಿಮà³à²® <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ಚ ಪರವಟà²à²¿ <xliff:g id="APP_NAME">%1$s</xliff:g> à²
ಚà³à²®à²€à²¿à²¯à²šà³à²šà³ ವಿಚà²à²€à²¿à²žà²¿à²à³à²³à³à²³à³à²€à³à²€à²¿à²Šà³"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ಠà²à³à²¯à²à³à²·à²šà³ à²
ಚà³à²šà³ ಀà³à²à³à²Šà³à²à³à²³à³à²³à²²à³ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à²
ಚà³à²®à²€à²¿à²žà²¬à³à²à³?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ಚಿಮà³à²® ಫà³à²šà³à²šà²²à³à²²à²¿à²š à²à³à²¯à²ªà³à²à²³à³ ಮಀà³à²€à³ ಞಿಞà³à²à²®à³ ಫà³à²à²°à³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠ<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à²à³ à²
ಚà³à²®à²€à²¿à²žà²¬à³à²à³?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"à²à²¡à²¿à²¯à³, ಫà³à²à³à²à²³à³, ಪಟವಀಿ ಮಟಹಿಀಿ, ಪಟಞà³à²µà²°à³à²¡à³à²à²³à³ ಮಀà³à²€à³ ಞà²à²Šà³à²¶à²à²³à³ ಞà³à²°à²¿à²Šà²à²€à³ ಚಿಮà³à²® ಫà³à²šà³à²šà²²à³à²²à²¿ à²à³à²à²°à²¿à²žà³à²µ à²
ಥವಟ ಪà³à²²à³ à²à²à³à²µ ಯಟವà³à²Šà³ à²à²à²à³à²à²à³à²à³.<br/><br/>ಚà³à²µà³ ಠà²
ಚà³à²®à²€à²¿à²à³ à²à²°à³à²µ à²à³à²¯à²à³à²žà³à²žà³ à²
ಚà³à²šà³ ಀà³à²à³à²Šà³à²¹à²Ÿà²à³à²µà²µà²°à³à²à³ %1$s à²à³ à²à³à²¯à²ªà³à²à²³à³ ಮಀà³à²€à³ ಞಿಞà³à²à²®à³ ಫà³à²à²°à³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠಞಟಧà³à²¯à²µà²Ÿà²à³à²€à³à²€à²Šà³."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ಞಮà³à²ªà²Šà²²à³à²²à²¿à²°à³à²µ ಞಟಧಚà²à²³à²¿à²à³ à²à³à²¯à²ªà³à²à²³à³ ಮಀà³à²€à³ à²à²€à²° ಞಿಞà³à²à² ಫà³à²à²°à³à²à²³à²šà³à²šà³ ಞà³à²à³à²°à³à²®à³ ಮಟಡಲೠಚಿಮà³à²® <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ರ ಪರವಟà²à²¿ <xliff:g id="APP_NAME">%1$s</xliff:g> à²
ಚà³à²®à²€à²¿à²¯à²šà³à²šà³ ವಿಚà²à²€à²¿à²žà³à²€à³à²€à²¿à²Šà³"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಞಟಧಚ"</string>
<string name="summary_generic" msgid="1761976003668044801">"ಮà³à²¬à³à²²à³ ಫà³à²šà³ ಮಀà³à²€à³ à²à²¯à³à²à³à²®à²Ÿà²¡à²¿à²Š ಞಟಧಚಊ ಚಡà³à²µà³, à²à²°à³ ಮಟಡà³à²µà²µà²° ಹà³à²žà²°à²¿à²šà²à²€à²¹ ಮಟಹಿಀಿಯಚà³à²šà³ ಞಿà²à²à³ ಮಟಡಲೠಠà²à³à²¯à²ªà³à²à³ ಞಟಧà³à²¯à²µà²Ÿà²à³à²€à³à²€à²Šà³"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 9aa49d5..86679ac 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"êž°êž°"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ì±ìŽ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ìì ìŽë¬í ê¶íì ì¡ìžì€í ì ìê² ë©ëë€."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ìŽ íŽëì íì ìŽ ì 볎ì ì¡ìžì€íëë¡ íì©í©ëë€."</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ìì íŽëì íì ì±ì ì€ížëЬë°íëë¡ íì©íìê² ìµëê¹?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$sìì ì€ëì€, ì¬ì§, ë¹ë°ë²íž, ë©ìì§ ë± íŽëì íì íìëê±°ë íŽëì íìì ì¬ìëë 몚ë í목ì ì¡ìžì€í ì ììµëë€.<br/><br/>ìŽ ê¶íì ëí ì¡ìžì€ë¥Œ ìì í ëê¹ì§ %1$sìì ì±ì ì€ížëЬë°í ì ììµëë€."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"êµì°š êž°êž° ìë¹ì€"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>ìì <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ëì êž°êž° ê°ì ì±ì ì€ížëЬë°í ì ìë ê¶íì ìì²íê³ ììµëë€."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g>ìì <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ëì êž°êž° ê° ì±ì íìíê³ ì€ížëЬë°í ê¶íì ìì²íê³ ììµëë€."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ìŽ íŽëì íìì ìŽ ì 볎ì ì¡ìžì€íëë¡ íì©"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ìë¹ì€"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g>ìì <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ëì íŽëì íì ì¬ì§, 믞ëìŽ, ì늌ì ì¡ìžì€í ì ìë ê¶íì ìì²íê³ ììµëë€."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> êž°êž°ê° ìŽ ìì
ì ìííëë¡ íì©íìê² ìµëê¹?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ìì íŽëì íì ì± ë° ìì€í
êž°ë¥ì ì€ížëЬë°íëë¡ íì©íìê² ìµëê¹?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$sìì ì€ëì€, ì¬ì§, ê²°ì ì 볎, ë¹ë°ë²íž, ë©ìì§ ë± íŽëì íì íìëê±°ë íŽëì íìì ì¬ìëë 몚ë í목ì ì¡ìžì€í ì ììµëë€.<br/><br/>ìŽ ê¶íì ëí ì¡ìžì€ë¥Œ ìì í ëê¹ì§ %1$sìì ì± ë° ìì€í
êž°ë¥ì ì€ížëЬë°í ì ììµëë€."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>ìì <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ëì ê·Œì² êž°êž°ë¡ ì± ë° êž°í ìì€í
êž°ë¥ì ì€ížëЬë°í ê¶íì ìì²íê³ ììµëë€."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"êž°êž°"</string>
<string name="summary_generic" msgid="1761976003668044801">"ìŽ ì±ìì íŽëì íì ì íí êž°êž° ê°ì ì 볎(ì: ë°ì ì ìŽëŠ)륌 ëêž°íí ì ìê² ë©ëë€."</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index bb1e1aa..1f623e1 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÑүзЌөк"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐÑл кПлЎПМЌПгП <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ÑүзЌөгүңүзЎө ÑөЌөМкүлөÑÐŽÒ¯ аÑкаÑÑÑга ÑÑÑкÑÐ°Ñ Ð±ÐµÑОлеÑ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кПлЎПМЌПÑÑМа ÑелеÑПМÑÒ£ÑÐ·ÐŽÐ°Ð³Ñ ÑÑÑл ЌаалÑЌаÑÑÑ ÐºÓ©Ñүүгө ÑÑÑкÑÐ°Ñ Ð±ÐµÑОңОз"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кПлЎПМЌПÑÑМа ÑелеÑПМÑÒ£ÑÐ·ÐŽÐ°Ð³Ñ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸÐ»ÐŸÑÐŽÑ Ð°Ð»Ñп ПйМПÑÑÑга ÑÑÑкÑÐ°Ñ Ð±ÐµÑеÑОзбО?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ÑелеÑПМЎП көÑүМгөМ же ПйМПÑÑлгаМ баÑÐŽÑк МеÑÑелеÑге, аМÑМ ОÑОМЎе аÑЎОП, ÑÒ¯ÑÓ©ÑÑÓ©Ñ, ÑÑÑÑÓ©Ð·ÐŽÓ©Ñ Ð¶Ð°ÐœÐ° бОлЎОÑүүлөÑгө кОÑе алаÑ. ÐÑл ÑÑÑкÑаÑÑÑ Ð°Ð»Ñп ÑалЌайÑМÑа, <br/><br/>%1$s кПлЎПМЌПлПÑÐŽÑ Ð°Ð»Ñп ПйМПÑП алаÑ."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ТүзЌөкÑÓ©Ñ Ð°ÑалÑк кÑзЌаÑÑаÑ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ÑүзЌөгүңүзЎүМ аÑÑМаМ ÑүзЌөкÑÓ©ÑүңүзЎүМ ПÑÑПÑÑМЎа кПлЎПМЌПлПÑÐŽÑ Ð°Ð»Ñп ПйМПÑÑÑга ÑÑÑкÑÐ°Ñ ÑÑÑап жаÑаÑ"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> кПлЎПМЌПÑÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ÑүзЌөгүңүзЎүМ аÑÑМаМ ÑүзЌөкÑÓ©ÑЎүМ ПÑÑПÑÑМЎа кПлЎПМЌПлПÑÐŽÑ ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯ жаМа алÑп ПйМПÑÑÑ Ò¯ÑүМ ÑÑÑкÑÐ°Ñ ÑÑÑап жаÑаÑ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кПлЎПМЌПÑÑМа ÑелеÑПМÑÒ£ÑÐ·ÐŽÐ°Ð³Ñ ÑÑÑл ЌаалÑЌаÑÑÑ ÐºÓ©Ñүүгө ÑÑÑкÑÐ°Ñ Ð±ÐµÑОңОз"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play кÑзЌаÑÑаÑÑ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> кПлЎПМЌПÑÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ÑүзЌөгүңүзЎүМ аÑÑМаМ ÑелеÑÐŸÐœÐŽÐŸÐ³Ñ ÑÒ¯ÑÓ©ÑÑÓ©ÑÐŽÒ¯, ЌеЎОа ÑайлЎаÑÐŽÑ Ð¶Ð°ÐœÐ° бОлЎОÑЌелеÑЎО кПлЎПМÑÑга ÑÑÑкÑÐ°Ñ ÑÑÑап жаÑаÑ"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÑүзЌөгүМө бÑл аÑакеÑÑО аÑкаÑÑÑга ÑÑÑкÑÐ°Ñ Ð±ÐµÑеÑОзбО?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> кПлЎПМЌПÑÑМа ÑелеÑПМÑÒ£ÑÐ·ÐŽÐ°Ð³Ñ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸÐ»ÐŸÑÐŽÑ Ð¶Ð°ÐœÐ° ÑÑÑÑЌЎÑМ ÑÑМкÑОÑлаÑÑМ алÑп ПйМПÑÑÑга ÑÑÑкÑÐ°Ñ Ð±ÐµÑеÑОзбО?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ÑелеÑПМÑÒ£ÑзЎа көÑүМгөМ же ПйМПÑÑлгаМ баÑÐŽÑк МеÑÑелеÑге, аМÑМ ОÑОМЎе аÑЎОП, ÑÒ¯ÑÓ©ÑÑÓ©Ñ, ÑөлөЌ ЌаалÑЌаÑÑ, ÑÑÑÑÓ©Ð·ÐŽÓ©Ñ Ð¶Ð°ÐœÐ° бОлЎОÑүүлөÑгө кОÑе алаÑ. ÐÑл ÑÑÑкÑаÑÑÑ Ð°Ð»Ñп ÑалЌайÑМÑа, <br/><br/>%1$s кПлЎПМЌПлПÑÐŽÑ Ð¶Ð°ÐœÐ° ÑÑÑÑÐŒ ÑÑМкÑОÑлаÑÑМ алÑп ПйМПÑП алаÑ."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ÑүзЌөгүңүзЎүМ аÑÑМаМ жакÑМ жеÑЎегО ÑүзЌөкÑÓ©ÑÐŽÓ© кПлЎПМЌПлПÑÐŽÑ Ð¶Ð°ÐœÐ° ÑОÑÑеЌаМÑМ баÑка ÑÑМкÑОÑлаÑÑМ алÑп ПйМПÑÑÑга ÑÑÑкÑÐ°Ñ ÑÑÑап жаÑаÑ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÑүзЌөк"</string>
<string name="summary_generic" msgid="1761976003668044801">"ÐÑл кПлЎПМЌП ЌаалÑЌаÑÑÑ ÑайкеÑÑОÑе алаÑ, ЌОÑалÑ, ÑалÑп жаÑкаМ кОÑОМОМ аÑÑМ ÑелеÑПМ жаМа ÑаМЎалгаМ ÑүзЌөк ЌеМеМ ÑайкеÑÑОÑеÑ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 9a45460..4a97f0d 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àºàºžàºàº°àºàºàº"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à»àºàº±àºàºàºµà»àºàº°à»àºà»àº®àº±àºàºªàºŽàºà»àºàº»à»àº²à»àºàºŽàºàºàº²àºàºàº°àºàºžàºàº²àºà»àº«àºŒàº»à»àº²àºàºµà»àº¢àº¹à» <xliff:g id="DEVICE_NAME">%1$s</xliff:g> àºàºàºàºà»àº²àº"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"àºàº°àºàºžàºàº²àº <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à»àº«à»à»àºàº»à»àº²à»àºàºŽàºàºà»à»àº¡àº¹àºàºàºµà»àºàº²àºà»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àºà»àºà»"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"àºàº°àºàºžàºàº²àºà»àº«à» <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ສະâàºâຣີມà»àºàº±àºàºàºàºà»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àºàºà»?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s àºàº°àº¡àºµàºªàºŽàºà»àºàº»à»àº²à»àºàºŽàºàºàºžàºàº¢à»àº²àºàºàºµà»à»àº«àº±àºà»àºà» ຫຌື ຫຌຎà»àºàº¢àº¹à»à»àºàº¥àº°àºªàº±àº, ຮວມàºàº±àºàºªàºœàº, ຮູàºàºàº²àº, ລະຫັàºàºà»àº²àº à»àº¥àº° àºà»à»àºàº§àº²àº¡.<br/><br/>%1$s àºàº°àºªàº²àº¡àº²àºàºªàº°âàºâຣີມà»àºàº±àºà»àºà»àºàº»àºàºàº§à»àº²àºà»àº²àºàºàº°àº¥àº¶àºàºªàºŽàºà»àºàº»à»àº²à»àºàºŽàºàºàº²àºàºàº°àºàºžàºàº²àºàºàºµà»àºàºàº."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àºà»àº¥àºŽàºàº²àºàºà»àº²àº¡àºàºžàºàº°àºàºàº"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> àºàº³àº¥àº±àºàº®à»àºàºàºà»àºàº²àºàºàº°àºàºžàºàº²àºà»àºàºàº²àº¡àºàºàº <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à»àºàº·à»àºàºªàº°àºàº£àºµàº¡à»àºàº±àºàº¥àº°àº«àº§à»àº²àºàºàºžàºàº°àºàºàºàºà»àº²àºà»àºàºàºàºà»àº²àº"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> àºà»àº²àº¥àº±àºàº®à»àºàºàºà»àºàº²àºàºàº°àºàºžàºàº²àºà»àºàºàº²àº¡àºàºàº <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àºàºàºàºà»àº²àºà»àºàº·à»àºàºªàº°à»àºàº à»àº¥àº° àºà»àº²àºàºàºàºà»àºàº±àºàº¥àº°àº«àº§à»àº²àºàºàºžàºàº°àºàºàºàºàºàºàºà»àº²àº"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"àºàº°àºàºžàºàº²àº <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à»àº«à»à»àºàº»à»àº²à»àºàºŽàºàºà»à»àº¡àº¹àºàºàºµà»àºàº²àºà»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àºà»àºà»"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"àºà»àº¥àºŽàºàº²àº Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> àºàº³àº¥àº±àºàº®à»àºàºàºà»àºàº²àºàºàº°àºàºžàºàº²àºà»àºàºàº²àº¡àºàºàº <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à»àºàº·à»àºà»àºàº»à»àº²à»àºàºŽàºàº®àº¹àºàºàº²àº, ສື໠à»àº¥àº° àºàº²àºà»àºà»àºà»àºàº·àºàºà»àºà»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àº"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"àºàº°àºàºžàºàº²àº <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à»àºàº·à»àºàºàº³à»àºàºµàºàºàº³àºªàº±à»àºàºàºµà»àºà»?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"àºàº°àºàºžàºàº²àºà»àº«à» <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ສະâàºâຣີມà»àºàº±àºàºàºàºà»àºàº¥àº°àºªàº±àº à»àº¥àº° àºàºžàºàºªàº»àº¡àºàº±àºàº¥àº°àºàº»àºàºàºàºàºà»àº²àºàºà»?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s àºàº°àº¡àºµàºªàºŽàºà»àºàº»à»àº²à»àºàºŽàºàºàºžàºàº¢à»àº²àºàºàºµà»à»àºàºŽà»àºà»àº«àº±àº ຫຌື ຫຌຎà»àºàº¢àº¹à»à»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àº, ຮວມàºàº±àºàºªàºœàº, ຮູàºàºàº²àº, àºà»à»àº¡àº¹àºàºàº²àºàºà»àº²àºà»àºàºŽàº, ລະຫັàºàºà»àº²àº à»àº¥àº° àºà»à»àºàº§àº²àº¡.<br/><br/>%1$s àºàº°àºªàº²àº¡àº²àºàºªàº°âàºâຣີມà»àºàº±àº à»àº¥àº° àºàºžàºàºªàº»àº¡àºàº±àºàºàºàºàº¥àº°àºàº»àºàºàº»àºàºàº§à»àº²àºà»àº²àºàºàº°àº¥àº¶àºàºªàºŽàºà»àºàº»à»àº²à»àºàºŽàºàºàº²àºàºàº°àºàºžàºàº²àºàºàºµà»àºàºàº."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> àºà»àº²àº¥àº±àºàº®à»àºàºàºà»àºàº²àºàºàº°àºàºžàºàº²àºà»àºàºàº²àº¡ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> àºàºàºàºà»àº²àºà»àºàº·à»àºàºªàº°àºàº£àºµàº¡à»àºàº±àº à»àº¥àº° àºàºžàºàºªàº»àº¡àºàº±àºàº¥àº°àºàº»àºàºàº·à»àºà»à»àºàº«àº²àºàºžàºàº°àºàºàºàºàºµà»àº¢àº¹à»à»àºà»àºàºœàº"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àºàºžàºàº°àºàºàº"</string>
<string name="summary_generic" msgid="1761976003668044801">"à»àºàº±àºàºàºµà»àºàº°àºªàº²àº¡àº²àºàºàºŽà»àºàºà»à»àº¡àº¹àº à»àºàº±à»àº: àºàº·à»àºàºàºàºàº»àºàºàºµà»à»àºà»àºàº»à»àº², ລະຫວà»àº²àºà»àºàº¥àº°àºªàº±àºàºàºàºàºà»àº²àº à»àº¥àº° àºàºžàºàº°àºàºàºàºàºµà»à»àº¥àº·àºàºà»àº§à»à»àºà»"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 58a9db9..e931353 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"įrenginio"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Šiai programai bus leidÅŸiama pasiekti toliau nurodytus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> leidimus."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šiÄ
informacijÄ
iš jÅ«sų telefono"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Leisti programai <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> srautu perduoti telefono programas?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"„%1$s“ galÄs pasiekti visÄ
telefone matomÄ
ar leidÅŸiamÄ
turinį, įskaitant garso įrašus, nuotraukas, slaptaÅŸodÅŸius ir pranešimus.<br/><br/>„%1$s“ galÄs perduoti srautu programas, kol pašalinsite prieigÄ
prie šio leidimo."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jÅ«sų „<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>“ vardu, kad galÄtų srautu perduoti programas iš vieno įrenginio į kitÄ
"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jÅ«sų „<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>“ vardu, kad galÄtų rodyti ir srautu perduoti programas iš vieno įrenginio į kitÄ
"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šiÄ
informacijÄ
iš jÅ«sų telefono"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jÅ«sų „<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>“ vardu, kad galÄtų pasiekti telefono nuotraukas, medijÄ
ir pranešimus"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leisti <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> atlikti šÄ¯ veiksmÄ
?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Leisti programai <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> srautu perduoti telefono programas ir sistemos funkcijas?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"„%1$s“ galÄs pasiekti visÄ
telefone matomÄ
ar leidÅŸiamÄ
turinį, įskaitant garso įrašus, nuotraukas, , mokÄjimo informacijÄ
, slaptaÅŸodÅŸius ir pranešimus.<br/><br/>„%1$s“ galÄs perduoti srautu programas ir sistemos funkcijas, kol pašalinsite prieigÄ
prie šio leidimo."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jÅ«sų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galÄtų srautu perduoti programas ir kitas sistemos funkcijas įrenginiams netoliese"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ši programa galÄs sinchronizuoti tam tikrÄ
informacijÄ
, pvz., skambinanÄio asmens vardÄ
, su jūsų telefonu ir pasirinktu įrenginiu"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 36908e4..20282b3 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ierīce"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Šai lietotnei tiks sniegta piekÄŒuve norÄdÄ«tajÄm atÄŒaujÄm jÅ«su ierÄ«cÄ (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"AtÄŒaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekČūt šai informÄcijai no jÅ«su tÄlruÅa"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vai atÄŒaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> straumÄt jÅ«su tÄlruÅa lietotnes?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s varÄs piekČūt visam saturam, kas ir redzams vai tiek atskaÅots jÅ«su tÄlrunÄ«, tostarp audio, fotoattÄliem, parolÄm un ziÅojumiem.<br/><br/>%1$s varÄs straumÄt lietotnes, lÄ«dz noÅemsiet tÄs piekÄŒuvi šai atÄŒaujai."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"VairÄku ierÄ«Äu pakalpojumi"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atÄŒauju straumÄt lietotnes starp jÅ«su ierÄ«cÄm šÄ«s ierÄ«ces vÄrdÄ: <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atÄŒauju rÄdÄ«t un straumÄt lietotnes starp jÅ«su ierÄ«cÄm šÄ«s ierÄ«ces vÄrdÄ: <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"AtÄŒaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekČūt šai informÄcijai no jÅ«su tÄlruÅa"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atÄŒauju piekČūt jÅ«su tÄlruÅa fotoattÄliem, multivides saturam un paziÅojumiem šÄ«s ierÄ«ces vÄrdÄ: <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vai atÄŒaut ierÄ«cei <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> veikt šo darbÄ«bu?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vai atÄŒaut ierÄ«cei <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> straumÄt jÅ«su tÄlruÅa lietotnes un sistÄmas funkcijas?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s varÄs piekČūt visam saturam, kas ir redzams vai tiek atskaÅots jÅ«su tÄlrunÄ«, tostarp audio, fotoattÄliem, maksÄjumu informÄcijai, parolÄm un ziÅojumiem.<br/><br/>%1$s varÄs straumÄt lietotnes un sistÄmas funkcijas, lÄ«dz noÅemsiet tÄs piekÄŒuvi šai atÄŒaujai."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atÄŒauju tuvumÄ esošÄs ierÄ«cÄs straumÄt lietotnes un citas sistÄmas funkcijas šÄ«s ierÄ«ces vÄrdÄ: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
<string name="summary_generic" msgid="1761976003668044801">"ŠÄ« lietotne varÄs sinhronizÄt informÄciju (piemÄram, zvanÄ«tÄja vÄrdu) starp jÅ«su tÄlruni un izvÄlÄto ierÄ«ci"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index b361ae2..2d7c2d3 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÑÑеЎ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐплОкаÑОÑава Ñе ЌПже Ўа пÑОÑÑапÑва ЎП ПвОе ЎПзвПлО Ма <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ÐвПзЌПжеÑе <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Ўа пÑОÑÑапÑва ЎП ПвОе пПЎаÑПÑО Ма ÑелеÑПМПÑ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ðа Ñе ЎПзвПлО <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Ўа гО ÑÑÑОЌÑва аплОкаÑООÑе ПЎ ваÑÐžÐŸÑ ÑелеÑПМ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Ñе ОЌа пÑОÑÑап ЎП Ñè ÑÑП е вОЎлОвП ОлО ÑепÑПЎÑÑОÑаМП Ма ÑелеÑПМПÑ, вклÑÑÑваÑÑО гО О аÑЎОПÑП, ÑПÑПгÑаÑООÑе, лПзОМкОÑе О пПÑакОÑе.<br/><br/>%1$s Ñе ЌПже Ўа ÑÑÑОЌÑва аплОкаÑОО ЎПЎека Ме Ñа пПвлеÑеÑе ЎПзвПлава."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ÐПвеÑеМаЌеМÑкО ÑÑлÑгО"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> баÑа ЎПзвПла вП ОЌе Ма ваÑÐžÐŸÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за Ўа ÑÑÑОЌÑва аплОкаÑОО пПЌеÑÑ Ð²Ð°ÑОÑе ÑÑеЎО"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> баÑа ЎПзвПла вП ОЌе Ма ваÑÐžÐŸÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за Ўа пÑОкажÑва О ÑÑÑОЌÑва аплОкаÑОО ЌеÑÑ Ð²Ð°ÑОÑе ÑÑеЎО"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ÐПзвПлеÑе <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Ўа пÑОÑÑапÑва ЎП ПвОе пПЎаÑПÑО Ма ÑелеÑПМПÑ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"УÑлÑгО Ма Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> баÑа ЎПзвПла вП ОЌе Ма ваÑÐžÐŸÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за Ўа пÑОÑÑапÑва ЎП ÑПÑПгÑаÑООÑе, аÑЎОПвОзÑелМОÑе ÑПЎÑжОМО О ОзвеÑÑÑваÑаÑа Ма ÑелеÑПМПÑ"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ðе ЎПзвПлОÑе <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> Ўа гП пÑезеЌе Пва ЎеÑÑÑвП?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Ðа Ñе ЎПзвПлО <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> Ўа гО ÑÑÑОЌÑва аплОкаÑООÑе О ÑОÑÑеЌÑкОÑе ÑÑМкÑОО ПЎ ваÑÐžÐŸÑ ÑелеÑПМ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s Ñе ОЌа пÑОÑÑап ЎП Ñè ÑÑП е вОЎлОвП ОлО ÑепÑПЎÑÑОÑаМП Ма ÑелеÑПМПÑ, вклÑÑÑваÑÑО гО О аÑЎОПÑП, ÑПÑПгÑаÑООÑе, пПЎаÑПÑОÑе за плаÑаÑе, лПзОМкОÑе О пПÑакОÑе.<br/><br/>%1$s Ñе ЌПже Ўа ÑÑÑОЌÑва аплОкаÑОО О ÑОÑÑеЌÑкО ÑÑМкÑОО ЎПЎека Ме Ñа пПвлеÑеÑе ЎПзвПлава."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> баÑа ЎПзвПла вП ОЌе Ма ваÑÐžÐŸÑ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за Ўа ÑÑÑОЌÑва аплОкаÑОО О ÐŽÑÑгО ÑОÑÑеЌÑкО ÑÑМкÑОО Ма ÑÑеЎОÑе вП блОзОМа"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÑÑеЎ"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ðваа аплОкаÑОÑа Ñе ЌПже Ўа гО ÑОМÑ
ÑПМОзОÑа пПЎаÑПÑОÑе какП ÑÑП Ñе ОЌОÑаÑа Ма ÑавÑваÑОÑе пПЌеÑÑ Ð²Ð°ÑÐžÐŸÑ ÑелеÑПМ О ОзбÑÐ°ÐœÐžÐŸÑ ÑÑеЎ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 485dc98..b1934af 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àŽàŽªàŽàŽ°àŽ£àŽ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àµœ àŽàŽšàŽ¿àŽªàµàŽªàŽ±àŽ¯àµàŽšàµàŽš àŽ
àŽšàµàŽ®àŽ€àŽ¿àŽàµŸ àŽàŽàµàŽžàŽžàµ àŽàµàޝàµàŽ¯àŽŸàµ» àŽ àŽàŽªàµàŽªàŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàµàŽ"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àµœ àŽšàŽ¿àŽšàµàŽšàµ àŽ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽàŽàµàŽžàŽžàµ àŽàµàޝàµàŽ¯àŽŸàµ» <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àŽàŽªàµàŽªàŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàµàŽ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àŽ²àµ àŽàŽªàµàŽªàµàŽàµŸ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàµ» <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàŽ£àµ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"àŽàŽ¡àŽ¿àŽ¯àµ, àŽ«àµàŽàµàŽàµàŽàµŸ, àŽªàŽŸàŽžàµà޵àµàŽ¡àµàŽàµŸ, àŽžàŽšàµàŽŠàµà޶àŽàµàŽàµŸ àŽàŽšàµàŽšàŽ¿àŽµ àŽàµŸàŽªàµàŽªàµàŽàµ àŽ«àµàŽ£àŽ¿àµœ àŽŠàµà޶àµàŽ¯àŽ®àŽŸàŽàµàŽšàµàŽšàŽ€àµ àŽªàµàŽ²àµ àŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àµ àŽàޝ àŽà޲àµàŽ²àŽŸàŽ€àµàŽ€àŽ¿àŽ²àµàŽàµàŽàµàŽ %1$s-àŽšàµ àŽàŽàµàŽžàŽžàµ àŽàŽ£àµàŽàŽŸàŽ¯àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽ.<br/><br/>àŽšàŽ¿àŽàµàŽàµŸ àŽ àŽ
àŽšàµàŽ®àŽ€àŽ¿àŽ¯àŽ¿àŽ²àµàŽàµàŽàµà޳àµà޳ àŽàŽàµàŽžàŽžàµ àŽšàµàŽàµàŽàŽ àŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àµ àŽµàŽ°àµ %1$s-àŽšàµ àŽàŽªàµàŽªàµàŽàµŸ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàŽšàŽŸàŽàµàŽ."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àŽàµàްàµàŽžàµ-àŽàŽªàŽàŽ°àŽ£ àŽžàµàŽµàŽšàŽàµàŽàµŸ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽàŽªàŽàŽ°àŽ£àŽàµàŽàŽ³àŽ¿àµœ àŽàŽšàµàŽšàŽ¿àµœ àŽšàŽ¿àŽšàµàŽšàµ àŽ
àŽàµàŽ€àµàŽ€àŽ€àŽ¿àŽ²àµàŽàµàŽàµ àŽàŽªàµàŽªàµàŽàµŸ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàµ» <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àŽàŽšàµàŽš àŽàŽªàŽàŽ°àŽ£àŽ€àµàŽ€àŽ¿àŽšàµ àŽµàµàŽ£àµàŽàŽ¿ <xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àµ àŽ
àŽšàµàŽ®àŽ€àŽ¿ àŽ
àŽàµàŽ¯àµŒàŽ€àµàŽ¥àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽàŽªàŽàŽ°àŽ£àŽàµàŽàµŸàŽàµàŽàŽ¿àŽàŽ¯àŽ¿àµœ àŽàŽªàµàŽªàµàŽàµŸ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàŽšàµàŽ àŽªàµàŽ°àŽŠàµŒàŽ¶àŽ¿àŽªàµàŽªàŽ¿àŽàµàŽàŽŸàŽšàµàŽ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àŽàŽšàµàŽš àŽàŽªàŽàŽ°àŽ£àŽ€àµàŽ€àŽ¿àŽšàµ àŽµàµàŽ£àµàŽàŽ¿ <xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àµ àŽ
àŽšàµàŽ®àŽ€àŽ¿ àŽ
àŽàµàŽ¯àµŒàŽ€àµàŽ¥àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àµœ àŽšàŽ¿àŽšàµàŽšàµ àŽ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽàŽàµàŽžàŽžàµ àŽàµàޝàµàŽ¯àŽŸàµ» <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àŽàŽªàµàŽªàŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàµàŽ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play àŽžàµàŽµàŽšàŽàµàŽàµŸ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àŽ²àµ àŽ«àµàŽàµàŽàµàŽàµŸ, àŽ®àµàŽ¡àŽ¿àŽ¯, àŽ
àŽ±àŽ¿àŽ¯àŽ¿àŽªàµàŽªàµàŽàµŸ àŽàŽšàµàŽšàŽ¿àŽµ àŽàŽàµàŽžàŽžàµ àŽàµàޝàµàŽ¯àŽŸàµ» <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àŽàŽšàµàŽš àŽàŽªàŽàŽ°àŽ£àŽ€àµàŽ€àŽ¿àŽšàµ àŽµàµàŽ£àµàŽàŽ¿ <xliff:g id="APP_NAME">%1$s</xliff:g> àŽ
àŽšàµàŽ®àŽ€àŽ¿ àŽ
àŽàµàŽ¯àµŒàŽ€àµàŽ¥àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"àŽ àŽªàµàŽ°àŽµàµŒàŽ€àµàŽ€àŽšàŽ àŽšàŽàŽ€àµàŽ€àŽŸàµ» <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàŽ£àµ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àŽ²àµ àŽàŽªàµàŽªàµàŽà޳àµàŽ àŽžàŽ¿àŽžàµàޱàµàŽ±àŽ àŽ«àµàŽàµàŽàޱàµàŽà޳àµàޝàµàŽ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàµ», <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽ
àŽšàµàŽµàŽŠàŽ¿àŽàµàŽàŽ£àµ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"àŽàŽ¡àŽ¿àŽ¯àµ, àŽ«àµàŽàµàŽàµàŽàµŸ, àŽªàµàޝàµàŽ®àµàŽšàµàŽ±àµ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ, àŽªàŽŸàŽžàµà޵àµàŽ¡àµàŽàµŸ, àŽžàŽšàµàŽŠàµà޶àŽàµàŽàµŸ àŽàŽšàµàŽšàŽ¿àŽµ àŽàµŸàŽªàµàŽªàµàŽàµ àŽ«àµàŽ£àŽ¿àµœ àŽŠàµà޶àµàŽ¯àŽ®àŽŸàŽàµàŽšàµàŽšàŽ€àµ àŽªàµàŽ²àµ àŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àµ àŽàޝ àŽà޲àµàŽ²àŽŸàŽ€àµàŽ€àŽ¿àŽ²àµàŽàµàŽàµàŽ %1$s-àŽšàµ àŽàŽàµàŽžàŽžàµ àŽàŽ£àµàŽàŽŸàŽ¯àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽ.<br/><br/>àŽšàŽ¿àŽàµàŽàµŸ àŽ àŽ
àŽšàµàŽ®àŽ€àŽ¿àŽ¯àŽ¿àŽ²àµàŽàµàŽàµà޳àµà޳ àŽàŽàµàŽžàŽžàµ àŽšàµàŽàµàŽàŽ àŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àµ àŽµàŽ°àµ %1$s-àŽšàµ àŽàŽªàµàŽªàµàŽà޳àµàŽ àŽžàŽ¿àŽžàµàޱàµàŽ±àŽ àŽ«àµàŽàµàŽàޱàµàŽà޳àµàŽ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàŽšàŽŸàŽàµàŽ."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"àŽžàŽ®àµàŽªàŽ®àµà޳àµà޳ àŽàŽªàŽàŽ°àŽ£àŽàµàŽàŽ³àŽ¿àµœ àŽàŽªàµàŽªàµàŽà޳àµàŽ àŽ®àŽ±àµàŽ±àµ àŽžàŽ¿àŽžàµàޱàµàŽ±àŽ àŽ«àµàŽàµàŽàޱàµàŽà޳àµàŽ àŽžàµàŽàµàްàµàŽ àŽàµàޝàµàŽ¯àŽŸàµ» àŽšàŽ¿àŽàµàŽà޳àµàŽàµ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽµàµàŽ£àµàŽàŽ¿ <xliff:g id="APP_NAME">%1$s</xliff:g> àŽ
àŽšàµàŽ®àŽ€àŽ¿ àŽ
àŽàµàŽ¯àµŒàŽ€àµàŽ¥àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àŽàŽªàŽàŽ°àŽ£àŽ"</string>
<string name="summary_generic" msgid="1761976003668044801">"àŽµàŽ¿àŽ³àŽ¿àŽàµàŽàµàŽšàµàŽšàŽ¯àŽŸàŽ³àµàŽàµ àŽªàµàŽ°àµ àŽªàµà޲àµà޳àµà޳ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ«àµàŽ£àŽ¿àŽšàµàŽ àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽ€àµàŽ€ àŽàŽªàŽàŽ°àŽ£àŽ€àµàŽ€àŽ¿àŽšàµàŽ àŽàŽàŽ¯àŽ¿àµœ àŽžàŽ®àŽšàµàŽµàŽ¯àŽ¿àŽªàµàŽªàŽ¿àŽàµàŽàµàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽ àŽàŽªàµàŽªàŽ¿àŽšàµ àŽàŽŽàŽ¿àŽ¯àµàŽ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 13d52d6b..fe6e4cc 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÑÓ©Ñ
Ó©Ó©ÑөЌж"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐÐœÑ Ð°Ð¿Ð¿ ÑÐ°ÐœÑ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-М ÑЎгÑÑÑ Ð·Ó©Ð²ÑÓ©Ó©ÑөлЎ Ñ
аМЎаÑ
ÑÑÑ
ÑÑй байÑ
бПлМП"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ÐŽ ÑÐ°ÐœÑ ÑÑаÑÐœÐ°Ð°Ñ ÑÐœÑ ÐŒÑÐŽÑÑлÑлЎ Ñ
аМЎаÑ
Ñг зөвÑÓ©Ó©ÑМө Ò¯Ò¯"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ð¢Ð°ÐœÑ ÑÑаÑÐœÑ Ð°Ð¿Ð¿ÑÑÐŽÑг ЎаЌжÑÑлаÑ
Ñг <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ÐŽ</strong> зөвÑÓ©Ó©ÑÓ©Ñ
Ò¯Ò¯?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s аÑЎОП, зÑÑаг, МÑÑÑ Ò¯Ð³ бПлПМ ЌеÑÑежүүЎОйг ПÑÑÑлааЎ ÑÑÑаМ ÐŽÑÑÑ Ñ
аÑагЎÑаМ ÑÑвÑÑ
ÑПглÑÑлÑаМ алОваа зүйлЎ Ñ
аМЎаÑ
ÑÑÑ
ÑÑй бПлМП.<br/><br/>%1$s ÑаМÑг ÑÐœÑ Ð·Ó©Ð²ÑÓ©Ó©ÑлОйг Ñ
аÑаÑ
Ñ
Ò¯ÑÑÑл аппÑÑÐŽÑг ЎаЌжÑÑлаÑ
бПлПЌжÑПй байÑ
бПлМП."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"ТөÑ
Ó©Ó©ÑөЌж Ñ
ППÑПМЎÑМ үйлÑОлгÑÑ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Ð¢Ð°ÐœÑ ÑÓ©Ñ
Ó©Ó©ÑөЌжүүЎ Ñ
ППÑПМЎ апп ЎаЌжÑÑлаÑ
ÑМ ÑÑлЎ <xliff:g id="APP_NAME">%1$s</xliff:g> ÑÐ°ÐœÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-М Ó©ÐŒÐœÓ©Ó©Ñ Ð·Ó©Ð²ÑÓ©Ó©Ñөл Ñ
Ò¯ÑÑж байМа"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÑÐ°ÐœÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-М Ó©ÐŒÐœÓ©Ó©Ñ ÑÐ°ÐœÑ ÑÓ©Ñ
Ó©Ó©ÑөЌжүүЎОйМ Ñ
ППÑПМЎ аппÑÑÐŽ үзүүлж, ЎаЌжÑÑлаÑ
зөвÑÓ©Ó©ÑлОйг Ñ
Ò¯ÑÑж байМа"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ÐŽ ÑÐ°ÐœÑ ÑÑаÑÐœÐ°Ð°Ñ ÑÐœÑ ÐŒÑÐŽÑÑлÑлЎ Ñ
аМЎаÑ
Ñг зөвÑÓ©Ó©ÑМө Ò¯Ò¯"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлÑОлгÑÑ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Ð¢Ð°ÐœÑ ÑÑаÑÐœÑ Ð·ÑÑаг, ЌеЎОа бПлПМ ÐŒÑÐŽÑгЎÑлЎ Ñ
аМЎаÑ
ÑМ ÑÑлЎ <xliff:g id="APP_NAME">%1$s</xliff:g> ÑÐ°ÐœÑ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-М Ó©ÐŒÐœÓ©Ó©Ñ Ð·Ó©Ð²ÑÓ©Ó©Ñөл Ñ
Ò¯ÑÑж байМа"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-ÐŽ ÑÐœÑ Ò¯Ð¹Ð»ÐŽÐ»ÐžÐ¹Ð³ Ñ
ОйÑ
Ойг зөвÑÓ©Ó©ÑÓ©Ñ
Ò¯Ò¯?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Ð¢Ð°ÐœÑ ÑÑаÑÐœÑ Ð°Ð¿Ð¿ бПлПМ ÑОÑÑеЌОйМ ПМÑлПгÑÑÐŽÑг ЎаЌжÑÑлаÑ
Ñг <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ÐŽ</strong> зөвÑÓ©Ó©ÑÓ©Ñ
Ò¯Ò¯?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s аÑЎОП, зÑÑаг, ÑөлбөÑОйМ ÐŒÑÐŽÑÑлÑл, МÑÑÑ Ò¯Ð³ бПлПМ ЌеÑÑежүүЎОйг ПÑÑÑлааЎ ÑÑÑаМ ÐŽÑÑÑ Ñ
аÑагЎÑаМ ÑÑвÑÑ
ÑПглÑÑлÑаМ алОваа зүйлЎ Ñ
аМЎаÑ
ÑÑÑ
ÑÑй бПлМП.<br/><br/>%1$s ÑаМÑг ÑÐœÑ Ð·Ó©Ð²ÑÓ©Ó©ÑлОйг Ñ
аÑаÑ
Ñ
Ò¯ÑÑÑл апп бПлПМ ÑОÑÑеЌОйМ ПМÑлПгÑÑÐŽÑг ЎаЌжÑÑлаÑ
бПлПЌжÑПй байÑ
бПлМП."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÑÐ°ÐœÑ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-М Ó©ÐŒÐœÓ©Ó©Ñ Ð°Ð¿Ð¿ÑÑÐŽ бПлПМ ÑОÑÑеЌОйМ бÑÑаЎ ПМÑлПгОйг ПйÑПлÑППÑ
ÑÓ©Ñ
Ó©Ó©ÑөЌжүүЎ ÑÒ¯Ò¯ ЎаЌжÑÑлаÑ
зөвÑÓ©Ó©Ñөл Ñ
Ò¯ÑÑж байМа"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÑÓ©Ñ
Ó©Ó©ÑөЌж"</string>
<string name="summary_generic" msgid="1761976003668044801">"ÐÐœÑ Ð°Ð¿Ð¿ залгаж бÑй Ñ
үМОй МÑÑ Ð·ÑÑÑг ÐŒÑÐŽÑÑллОйг ÑÐ°ÐœÑ ÑÑÐ°Ñ Ð±ÐŸÐ»ÐŸÐœ ÑПМгПÑПМ ÑÓ©Ñ
Ó©Ó©ÑөЌжОйМ Ñ
ППÑПМЎ ÑОМк Ñ
ОйÑ
бПлПЌжÑПй бПлМП"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 7f77303..52a7a55 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -26,14 +26,13 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à€¯à€Ÿ à€
à¥
à€ªà€²à€Ÿ à€€à¥à€®à€à¥à€¯à€Ÿ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> à€µà€° à€¯à€Ÿ à€ªà€°à€µà€Ÿà€šà€à¥à€¯à€Ÿ à€
à¥
à€à¥à€žà¥à€ž à€à€°à€£à¥à€¯à€Ÿà€à¥ à€
à€šà¥à€®à€€à¥ à€
à€žà¥à€²"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿ à€¹à¥ à€®à€Ÿà€¹à€¿à€€à¥ à€€à¥à€®à€à¥à€¯à€Ÿ à€«à¥à€šà€µà€°à¥à€š à€
à¥
à€à¥à€žà¥à€ž à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿ à€€à¥à€®à€à¥à€¯à€Ÿ à€«à¥à€šà€à¥ à€
à¥
à€ªà¥à€ž à€žà¥à€à¥à€°à¥à€® à€à€°à€£à¥à€¯à€Ÿà€à¥ à€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for summary_app_streaming (295548145144086753) -->
<skip />
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à€à¥à€°à¥à€ž-à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž à€žà¥à€µà€Ÿ"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"à€€à¥à€®à€à¥à€¯à€Ÿ à€¡à€¿à€µà¥à€¹à€Ÿà€à€žà€Šà€°à€®à¥à€¯à€Ÿà€š à¥²à€ªà¥à€ž à€žà¥à€à¥à€°à¥à€® à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠ<xliff:g id="APP_NAME">%1$s</xliff:g> à€¹à¥ à€€à¥à€®à€à¥à€¯à€Ÿ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥à€¯à€Ÿ à€µà€€à¥à€šà¥ à€ªà€°à€µà€Ÿà€šà€à¥à€à¥ à€µà€¿à€šà€à€€à¥ à€à€°à€€ à€à€¹à¥"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"à€€à¥à€®à€à¥à€¯à€Ÿ à€¡à€¿à€µà¥à€¹à€Ÿà€à€žà€Šà€°à€®à¥à€¯à€Ÿà€š à¥²à€ªà¥à€ž à€Šà€Ÿà€à€µà€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à€£à€¿ à€žà¥à€à¥à€°à¥à€® à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠ<xliff:g id="APP_NAME">%1$s</xliff:g> à€¹à¥ à€€à¥à€®à€à¥à€¯à€Ÿ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥à€¯à€Ÿ à€µà€€à¥à€šà¥ à€ªà€°à€µà€Ÿà€šà€à¥à€à¥ à€µà€¿à€šà€à€€à¥ à€à€°à€€ à€à€¹à¥"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿ à€¹à¥ à€®à€Ÿà€¹à€¿à€€à¥ à€€à¥à€®à€à¥à€¯à€Ÿ à€«à¥à€šà€µà€°à¥à€š à€
à¥
à€à¥à€žà¥à€ž à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿ"</string>
@@ -41,8 +40,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play à€žà¥à€µà€Ÿ"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"à€€à¥à€®à€à¥à€¯à€Ÿ à€«à¥à€šà€®à€§à¥à€² à€«à¥à€à¥, à€®à¥à€¡à€¿à€¯à€Ÿ à€à€£à€¿ à€žà¥à€à€šà€Ÿ ॲà€à¥à€žà¥à€ž à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠ<xliff:g id="APP_NAME">%1$s</xliff:g> à€¹à¥ à€€à¥à€®à€à¥à€¯à€Ÿ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥à€¯à€Ÿ à€µà€€à¥à€šà¥ à€ªà€°à€µà€Ÿà€šà€à¥à€à¥ à€µà€¿à€šà€à€€à¥ à€à€°à€€ à€à€¹à¥"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€²à€Ÿ à€¹à¥ à€à¥à€€à¥ à€à€°à€£à¥à€¯à€Ÿà€à¥ à€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€²à€Ÿ à€€à¥à€®à€à¥à€¯à€Ÿ à€«à¥à€šà€à¥ à€
à¥
à€ªà¥à€ž à€à€£à€¿ à€žà€¿à€žà¥à€à¥à€®à€à¥ à€µà¥à€¶à€¿à€·à¥à€à¥à€¯à¥ à€žà¥à€à¥à€°à¥à€® à€à€°à€£à¥à€¯à€Ÿà€à¥ à€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
<skip />
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€¹à¥ à€à€µà€³à€ªà€Ÿà€žà€à¥à€¯à€Ÿ à€¡à€¿à€µà¥à€¹à€Ÿà€à€žà€µà€° à€
à¥
à€ªà¥à€ž à€à€£à€¿ à€à€€à€° à€žà€¿à€žà¥à€à¥à€® à€µà¥à€¶à€¿à€·à¥à€à¥à€¯à¥ à€žà¥à€à¥à€°à¥à€® à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ à¥ à€€à¥à€®à€à¥à€¯à€Ÿ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à€à¥à€¯à€Ÿ à€µà€€à¥à€šà¥ à€ªà€°à€µà€Ÿà€šà€à¥à€à¥ à€µà€¿à€šà€à€€à¥ à€à€°à€Ÿ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 66f8caf4..21132a9 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"peranti"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Apl ini akan dibenarkan untuk mengakses kebenaran yang berikut pada <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses maklumat ini daripada telefon anda"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk menstrim apl telefon anda?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada telefon termasuk audio, foto, kata laluan dan mesej.<br/><br/>%1$s akan dapat menstrim apl sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> anda untuk memaparkan dan menstrim apl antara peranti anda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses maklumat ini daripada telefon anda"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan telefon anda"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Benarkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> mengambil tindakan ini?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Benarkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> untuk menstrim apl dan ciri sistem telefon anda?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s akan mendapat akses kepada semua perkara yang dipaparkan atau dimainkan pada telefon anda termasuk audio, foto, maklumat pembayaran, kata laluan dan mesej.<br/><br/>%1$s akan dapat menstrim apl dan ciri sistem sehingga anda mengalih keluar akses kepada kebenaran ini."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk menstrim apl dan ciri sistem yang lain pada peranti berdekatan"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
<string name="summary_generic" msgid="1761976003668044801">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan peranti yang dipilih"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 2192efa..12242b9 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"á
ááº"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ááá·áº <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ááœáẠáááºážááœáá·áºááŒá¯áá»ááºáá»á¬ážááá°ááẠá€á¡ááºááºááá¯ááœáá·áºááŒá¯áááº"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ááᯠááá·áºáá¯ááºážá០á€á¡áá»ááºá¡ááẠáá¯á¶ážááœáá·áºááŒá¯áááº"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ááᯠááá·áºáá¯ááºážá á¡ááºááºáá»á¬áž ááá¯ááºááá¯ááºááœáá·áºááœáá·áºááŒá¯ááá¬ážá"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ááẠá¡áá¶á áá¬ááºáá¯á¶á á
áá¬ážááŸááºá áááºáá±á·áá»áº á¡áá«á¡ááẠáá¯ááºážááœáẠááŒááºááá¯ááºáá±á¬ (ááá¯á·) ááœáá·áºáá¬ážáá±á¬ á¡áá¬á¡á¬ážáá¯á¶ážááᯠáá¯á¶ážááœáá·áºááŸááá«áááºá<br/><br/>á€ááœáá·áºááŒá¯áá»ááºáá¯á¶ážááœáá·áºááᯠáááºááááºááŸá¬ážááá»ááºáž %1$s ááẠá¡ááºááºáá»á¬ážááᯠááá¯ááºááá¯ááºááœáá·áºááá¯ááºáá«áááºá"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"á
ááºáá»á¬ážááŒá¬ážáá¯á¶áž áááºáá±á¬ááºááŸá¯áá»á¬áž"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááẠáááºáá
ááºáá»á¬ážá¡ááŒá¬áž á¡ááºááºáá»á¬ážááá¯ááºááá¯ááºááœáŸáá·áºááẠ<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááá¯ááºá
á¬áž ááœáá·áºááŒá¯áá»ááºáá±á¬ááºážáá±áááº"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááẠááá·áºá
ááºáá»á¬ážá¡ááŒá¬áž á¡ááºááºáá»á¬áž ááŒááŒá®áž ááá¯ááºááá¯ááºááœáá·áºááẠ<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááá¯ááºá
á¬áž ááœáá·áºááŒá¯áá»ááºáá±á¬ááºážáá±áááº"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> á¡á¬áž ááá·áºáá¯ááºážá០á€á¡áá»ááºá¡ááẠáá¯á¶ážááœáá·áºááŒá¯ááŒááºáž"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play áááºáá±á¬ááºááŸá¯áá»á¬áž"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááẠááá·áºáá¯ááºážá áá¬ááºáá¯á¶á áá®áá®áá¬ááŸáá·áº á¡ááŒá±á¬ááºážááŒá¬ážáá»ááºáá»á¬ážáá¯á¶ážááẠ<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ááá¯ááºá
á¬áž ááœáá·áºááŒá¯áá»ááºáá±á¬ááºážáá±áááº"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ááᯠá€ááá¯á·áá¯ááºáá±á¬ááºááœáá·áºááŒá¯ááá¬ážá"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ááᯠááá·áºáá¯ááºážá á¡ááºááºááŸáá·áº á
áá
áºá¡ááºá¹áá«áááºáá»á¬áž ááá¯ááºááá¯ááºááœáá·áºááœáá·áºááŒá¯ááá¬ážá"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ááẠá¡áá¶á áá¬ááºáá¯á¶á ááœá±áá»á±á¡áá»ááºá¡áááºá á
áá¬ážááŸááºááŸáá·áº áááºáá±á·áá»áºáá»á¬áž á¡áá«á¡ááẠáá¯ááºážááœáẠááŒááºááá¯ááºáá±á¬ (ááá¯á·) ááœáá·áºáá¬ážáá±á¬ á¡áá¬á¡á¬ážáá¯á¶ážááᯠáá¯á¶ážááœáá·áºááŸááá«áááºá<br/><br/>á€ááœáá·áºááŒá¯áá»ááºáá¯á¶ážááœáá·áºááᯠáááºááááºááŸá¬ážááá»ááºáž %1$s ááẠá¡ááºááºááŸáá·áº á
áá
áºá¡ááºá¹áá«áááºáá»á¬ážááᯠááá¯ááºááá¯ááºááœáá·áºááá¯ááºáá«áááºá"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ááẠá¡áá®ážáá
áºááá¯ááºááŸá á¡ááºááºáá»á¬ážááŸáá·áº á¡ááŒá¬ážá
áá
áºá¡ááºá¹áá«áááºáá»á¬ážááᯠááá¯ááºááá¯ááºááœáá·áºááẠááá·áº <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ááá¯ááºá
á¬áž ááœáá·áºááŒá¯áá»ááºáá±á¬ááºážáá±áááº"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"á
ááº"</string>
<string name="summary_generic" msgid="1761976003668044801">"á€á¡ááºááºááẠááá·áºáá¯ááºážááŸáá·áº ááœá±ážáá¬ážáá±á¬á
ááºá¡ááŒá¬áž áá±á«áºááá¯áá°áá¡áááºáá²á·ááá¯á· á¡áá»ááºá¡áááºááᯠá
áá·áºááºáá¯ááºááá¯ááºáá«áááº"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 2ad0f32..d817df2 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Denne appen får disse tillatelsene på <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vil du tillate at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strømmer appene på telefonen?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s får tilgang til alt som er synlig eller spilles av på telefonen, inkludert lyd, bilder, passord og meldinger.<br/><br/>%1$s kan strømme apper til du fjerner denne tillatelsen."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper mellom enhetene dine, på vegne av <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å vise og strømme apper mellom enhetene dine, på vegne av <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å få tilgang til bilder, medier og varsler på telefonen din, på vegne av <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du la <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> gjøre dette?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vil du tillate at <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> strømmer appene og systemfunksjonene på telefonen."</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s får tilgang til alt som er synlig eller spilles av på telefonen, inkludert lyd, bilder, betalingsopplysninger, passord og meldinger.<br/><br/>%1$s kan strømme apper og systemfunksjoner til du fjerner denne tillatelsen."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til å strømme apper og andre systemfunksjoner til enheter i nærheten"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="1761976003668044801">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og den valgte enheten"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 0d5cad8..fc28789 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"à€¡à€¿à€à€Ÿà€à€ž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à€€à€ªà€Ÿà€à€à€à¥ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> à€®à€Ÿ à€¯à¥ à€à€ªà€²à€Ÿà€ à€šà€¿à€®à¥à€š à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€à€šà¥ à€:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿà€ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€à€à€à¥ à€¯à¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€¹à¥à€°à¥à€šà¥ à€€à€¥à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€¹à¥à€žà¥"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿà€ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€à€à€à€Ÿ à€à€ªà€¹à€°à¥ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€š à€Šà€¿à€šà¥ à€¹à¥?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s à€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€Šà¥à€à€¿à€šà¥ à€µà€Ÿ à€ªà¥à€²à¥ à€à€°à€¿à€šà¥ à€
à€¡à€¿à€¯à¥, à€«à¥à€à¥, à€ªà€Ÿà€žà€µà€°à¥à€¡ à€° à€®à¥à€¯à€Ÿà€žà¥à€à€²à€à€Ÿà€¯à€€à€à€Ÿ à€žà€¬à¥ à€à¥à€°à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€š à€žà€à¥à€šà¥ à€à¥€<br/><br/>à€€à€ªà€Ÿà€à€à€²à¥ à€¯à¥ à€
à€šà¥à€®à€€à€¿ à€°à€Šà¥à€Š à€šà€à€°à¥à€žà€®à¥à€® %1$s à€²à¥ à€à€ªà€¹à€°à¥ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€š à€ªà€Ÿà€à€°à€Ÿà€à¥à€šà¥ à€à¥€"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à€à¥à€°à€ž-à€¡à€¿à€à€Ÿà€à€ž à€žà¥à€µà€Ÿà€¹à€°à¥"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€€à€ªà€Ÿà€à€à€à¥ à€¡à€¿à€à€Ÿà€à€ž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€€à€°à¥à€«à€¬à€Ÿà€ à€€à€ªà€Ÿà€à€à€à€Ÿ à€à¥à€šà¥ à€à€à€à€Ÿ à€¡à€¿à€à€Ÿà€à€žà€¬à€Ÿà€ à€
à€°à¥à€à¥ à€¡à€¿à€à€Ÿà€à€žà€®à€Ÿ à€à€ª à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à¥à€Šà¥ à€"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€€à€ªà€Ÿà€à€à€à¥ à€¡à€¿à€à€Ÿà€à€ž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€€à€°à¥à€«à€¬à€Ÿà€ à€€à€ªà€Ÿà€à€à€à€Ÿ à€à¥à€šà¥ à€à€à€à€Ÿ à€¡à€¿à€à€Ÿà€à€žà€¬à€Ÿà€ à€
à€°à¥à€à¥ à€¡à€¿à€à€Ÿà€à€žà€®à€Ÿ à€à€ª à€Šà¥à€à€Ÿà€à€šà¥ à€€à€¥à€Ÿ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à¥à€Šà¥ à€"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à€²à€Ÿà€ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€à€à€à¥ à€¯à¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€¹à¥à€°à¥à€šà¥ à€€à€¥à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥à€¹à¥à€žà¥"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€€à€ªà€Ÿà€à€à€à¥ à€¡à€¿à€à€Ÿà€à€ž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à€à¥ à€€à€°à¥à€«à€¬à€Ÿà€ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€à€à€à€Ÿ à€«à¥à€à¥, à€®à€¿à€¡à€¿à€¯à€Ÿ à€° à€žà¥à€à€šà€Ÿà€¹à€°à¥ à€¹à¥à€°à¥à€šà¥ à€€à€¥à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à¥à€Šà¥ à€"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€²à€Ÿà€ à€¯à¥ à€à€Ÿà€°à¥à€¯ à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€Šà€¿à€šà¥ à€¹à¥?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à€²à€Ÿà€ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€à€à€à€Ÿ à€à€ª à€€à€¥à€Ÿ à€žà€¿à€žà¥à€à€®à€à€Ÿ à€žà¥à€µà€¿à€§à€Ÿà€¹à€°à¥ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€š à€Šà€¿à€šà¥ à€¹à¥?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s à€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€šà€®à€Ÿ à€Šà¥à€à€¿à€šà¥ à€µà€Ÿ à€ªà¥à€²à¥ à€à€°à€¿à€šà¥ à€
à€¡à€¿à€¯à¥, à€«à¥à€à¥, à€à¥à€à¥à€€à€Ÿà€šà¥à€žà€®à¥à€¬à€šà¥à€§à¥ à€à€Ÿà€šà€à€Ÿà€°à¥, à€ªà€Ÿà€žà€µà€°à¥à€¡ à€° à€®à¥à€¯à€Ÿà€žà¥à€à€²à€à€Ÿà€¯à€€à€à€Ÿ à€žà€¬à¥ à€à¥à€°à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€š à€žà€à¥à€šà¥ à€à¥€<br/><br/>à€€à€ªà€Ÿà€à€à€²à¥ à€¯à¥ à€
à€šà¥à€®à€€à€¿ à€°à€Šà¥à€Š à€šà€à€°à¥à€žà€®à¥à€® %1$s à€²à¥ à€à€ª à€€à€¥à€Ÿ à€žà€¿à€žà¥à€à€®à€à€Ÿ à€žà¥à€µà€¿à€§à€Ÿà€¹à€°à¥ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€š à€ªà€Ÿà€à€°à€Ÿà€à¥à€šà¥ à€à¥€"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€€à€ªà€Ÿà€à€à€à¥ à€¡à€¿à€à€Ÿà€à€ž <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à€à¥ à€€à€°à¥à€«à€¬à€Ÿà€ à€šà€à€¿à€à¥à€à€Ÿ à€¡à€¿à€à€Ÿà€à€žà€¹à€°à¥à€®à€Ÿ à€à€ª à€° à€žà€¿à€žà¥à€à€®à€à€Ÿ à€
à€šà¥à€¯ à€žà¥à€µà€¿à€§à€Ÿà€¹à€°à¥ à€žà¥à€à¥à€°à€¿à€® à€à€°à¥à€šà¥ à€
à€šà¥à€®à€€à€¿ à€®à€Ÿà€à¥à€Šà¥ à€"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"à€¯à€šà¥à€€à¥à€°"</string>
<string name="summary_generic" msgid="1761976003668044801">"à€¯à¥ à€à€ªà€²à¥ à€€à€ªà€Ÿà€à€à€à¥ à€«à¥à€š à€° à€€à€ªà€Ÿà€à€à€²à¥ à€à€šà¥à€ à€à€°à¥à€šà¥ à€¡à€¿à€à€Ÿà€à€žà€à€Ÿ à€¬à€¿à€à€®à€Ÿ à€à€² à€à€°à¥à€šà¥ à€µà¥à€¯à€à¥à€€à€¿à€à¥ à€šà€Ÿà€® à€à€žà¥à€€à€Ÿ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà€¿à€à€ à€à€°à¥à€š à€žà€à¥à€šà¥ à€à¥€"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index b2c2818..4b17c7d 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"apparaat"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Deze app krijgt toegang tot deze rechten op je <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan de apps van je telefoon te streamen?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s heeft toegang tot alles wat zichtbaar is of wordt afgespeeld op de telefoon, waaronder audio, foto\'s, wachtwoorden en berichten.<br/><br/>%1$s kan apps streamen totdat je dit recht verwijdert."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toestemming om apps te streamen tussen je apparaten"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toestemming om apps tussen je apparaten weer te geven en te streamen"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> toegang tot de foto\'s, media en meldingen van je telefoon"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Toestaan dat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> deze actie uitvoert?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> toestaan de apps en systeemfuncties van je telefoon te streamen?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s heeft toegang tot alles wat zichtbaar is of wordt afgespeeld op je telefoon, waaronder audio, foto\'s, betalingsgegevens, wachtwoorden en berichten.<br/><br/>%1$s kan apps en systeemfuncties streamen totdat je dit recht verwijdert."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens je <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en andere systeemfuncties naar apparaten in de buurt te streamen"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
<string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index d5e9d85..c134cf1 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ଡିà¬à¬Ÿà¬à¬ž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à¬à¬ªà¬£à¬àଠ<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ରà à¬à¬¹à¬¿ à¬
ଚàମ଀ିà¬àଡଌିà¬à à¬à¬àଞàଞ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ à¬à¬¹à¬¿ à¬à¬ªà¬à à¬
ଚàମ଀ି ଊିà¬à¬¯à¬¿à¬¬"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"à¬à¬ªà¬£à¬àଠଫàଚରà à¬à¬¹à¬¿ ଞàà¬à¬šà¬Ÿà¬à à¬à¬àଞàଞ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>à¬à à¬
ଚàମ଀ି ଊିà¬
ଚà଀à"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"à¬à¬ªà¬£à¬àଠଫàଚର à¬à¬ªàଞà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>à¬à à¬
ଚàମ଀ି ଊàବà?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"à¬
ଡିà¬, ଫà¬à, ପଟଞà±à¬Ÿà¬°àଡ à¬à¬¬à¬ ମàଞàଠଞମà଀ ଫàଚରà ଊàà¬à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ à¬à¬¿à¬®àବଟ ପàଲà ହàà¬à¬¥à¬¿à¬¬à¬Ÿ ଞବàà¬à¬¿à¬à¬¿à¬à %1$sର à¬à¬àଞàଞ ରହିବी<br/><br/>à¬à¬ªà¬£ à¬à¬¹à¬¿ à¬
ଚàମ଀ିà¬à à¬à¬àଞàଞ à¬à¬Ÿà¬¢à¬Œà¬¿ ଚଊàବଟ ପରàଯààଚà଀ %1$s à¬à¬ªàଞà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ ଞà¬àଷମ ହàବी"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à¬àରଞ-ଡିà¬à¬Ÿà¬à¬ž ଞàବଟà¬àଡଌିà¬"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"à¬à¬ªà¬£à¬àଠଡିà¬à¬Ÿà¬à¬žà¬àଡଌିଠମଧààରà à¬à¬ªàଞà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <xliff:g id="APP_NAME">%1$s</xliff:g> à¬à¬ªà¬£à¬àà¬à¬° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ଀ରଫରà à¬
ଚàମ଀ି ପଟà¬à¬ à¬
ଚàରàଧ à¬à¬°àà¬à¬¿"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"à¬à¬ªà¬£à¬àଠଡିà¬à¬Ÿà¬à¬žà¬àଡଌିଠମଧààରà à¬à¬ªàଞà¬à ଡିଞପàଲà à¬à¬¬à¬ ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <xliff:g id="APP_NAME">%1$s</xliff:g> à¬à¬ªà¬£à¬àà¬à¬° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ଀ରଫରà à¬
ଚàମ଀ି ପଟà¬à¬ à¬
ଚàରàଧ à¬à¬°àà¬à¬¿"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"à¬à¬ªà¬£à¬àଠଫàଚରà à¬à¬¹à¬¿ ଞàà¬à¬šà¬Ÿà¬à à¬à¬àଞàଞ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>à¬à à¬
ଚàମ଀ି ଊିà¬
ଚà଀à"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ଞàବଟà¬àଡଌିà¬"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"à¬à¬ªà¬£à¬àଠଫàଚର ଫà¬à, ମିଡିଠà¬à¬¬à¬ ବିà¬àà¬à¬ªà଀ିà¬àଡଌିà¬à à¬à¬àଞàଞ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <xliff:g id="APP_NAME">%1$s</xliff:g> à¬à¬ªà¬£à¬àà¬à¬° <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ଀ରଫରà à¬
ଚàମ଀ି ପଟà¬à¬ à¬
ଚàରàଧ à¬à¬°àà¬à¬¿"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"à¬à¬¹à¬¿ ପଊà¬àଷàପ ଚàବଟ ପଟà¬à¬ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>à¬à à¬
ଚàମ଀ି ଊàବà?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"à¬à¬ªà¬£à¬àଠଫàଚର à¬à¬ªàଞ à¬à¬¬à¬ ଞିଷàà¬à¬® ଫିà¬à¬°à¬àଡଌିà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>à¬à à¬
ଚàମ଀ି ଊàବà?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"à¬
ଡିà¬, ଫà¬à, ପàମàଣàଠଞàà¬à¬šà¬Ÿ, ପଟଞà±à¬Ÿà¬°àଡ à¬à¬¬à¬ ମàଞàଠଞମà଀ à¬à¬ªà¬£à¬àଠଫàଚରà ଊàà¬à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ à¬à¬¿à¬®àବଟ ପàଲà ହàà¬à¬¥à¬¿à¬¬à¬Ÿ ଞବàà¬à¬¿à¬à¬¿à¬à %1$sର à¬à¬àଞàଞ ରହିବी<br/><br/>à¬à¬ªà¬£ à¬à¬¹à¬¿ à¬
ଚàମ଀ିà¬à à¬à¬àଞàଞ à¬à¬Ÿà¬¢à¬Œà¬¿ ଚଊàବଟ ପରàଯààଚà଀ %1$s à¬à¬ªàଞ à¬à¬¬à¬ ଞିଷàà¬à¬® ଫିà¬à¬°à¬àଡଌିà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ ଞà¬àଷମ ହàବी"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"à¬à¬à¬ªà¬Ÿà¬à¬° ଡିà¬à¬Ÿà¬à¬žà¬àଡଌିà¬à¬°à à¬à¬ªàଞ à¬à¬¬à¬ à¬
ଚàà ଞିଷàà¬à¬® ଫିà¬à¬°à¬àଡଌିà¬à ଷàà¬àରିମ à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ <xliff:g id="APP_NAME">%1$s</xliff:g> à¬à¬ªà¬£à¬àଠ<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ଀ରଫରà à¬
ଚàମ଀ି ପଟà¬à¬ à¬
ଚàରàଧ à¬à¬°àà¬à¬¿"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ଡିà¬à¬Ÿà¬à¬žà"</string>
<string name="summary_generic" msgid="1761976003668044801">"à¬à¬ªà¬£à¬àଠଫàଚ à¬à¬¬à¬ ବà¬à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ ଡିà¬à¬Ÿà¬à¬ž ମଧààରà, à¬à¬² à¬à¬°àଥିବଟ ଯà à¬àଣଞି ବààà¬à଀ିà¬àଠଚଟମ ପରି ଞàà¬à¬šà¬Ÿ ଞିà¬àଠà¬à¬°à¬¿à¬¬à¬Ÿà¬à à¬à¬¹à¬¿ à¬à¬ª ଞà¬àଷମ ହàବ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index 8a89f06..8394a82 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àš¡à©àšµàšŸàšàšž"</string>
<string name="summary_glasses" msgid="2872254734959842579">"àšàšž àšàšª àššà©à©° àš€à©àš¹àšŸàš¡à© <xliff:g id="DEVICE_NAME">%1$s</xliff:g> \'àš€à© àšàššà©àš¹àšŸàš àšàšàšŸàšàšŒàš€àšŸàš àš€à©±àš àšªàš¹à©à©°àš àšàš°àšš àšŠà© àšàšàš¿àš àš¹à©àšµà©àšà©"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àššà©à©° àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àš€à©àš àšàšž àšàšŸàš£àšàšŸàš°à© àš€à©±àš àšªàš¹à©à©°àš àšàš°àšš àšŠà© àšàšàš¿àš àšŠàš¿àš"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"àšà© <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àššà©à©° àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àšŠà©àšàš àšàšªàšŸàš àššà©à©° àšžàšà©àš°à©àš® àšàš°àšš àšŠà© àšàšàš¿àš àšŠà©àš£à© àš¹à©?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s àšà©àš² àšàš¡à©àš, àš«àšŒà©àšà©àšàš, àšªàšŸàšžàšµàš°àš¡àšŸàš àš
àš€à© àšžà©àššà©àš¹àš¿àšàš àšžàš®à©àš€, àš«àšŒà©àšš \'àš€à© àšŠàš¿àšàšŸàš àšŠà©àš£ àšµàšŸàš²à© àšàšŸàš àšàš²àšŸàš àšàšŸàš£ àšµàšŸàš²à© àšàš¿àšžà© àšµà© àšà©àšàšŒ àš€à©±àš àšªàš¹à©à©°àš àš¹à©àšµà©àšà©à¥€<br/><br/>%1$s àšàšªàšŸàš àššà©à©° àšàšŠà©àš àš€à©±àš àšžàšà©àš°à©àš® àšàš° àšžàšà©àšà©, àšàšŠà©àš àš€à©±àš àš€à©àšžà©àš àšàšž àšàšàšŸàšàšŒàš€ àš€à©±àš àšªàš¹à©à©°àš àššàš¹à©àš àš¹àšàšŸ àšŠàš¿à©°àšŠà©à¥€"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àšà©àš°àšŸàšž-àš¡à©àšµàšŸàšàšž àšžà©àšµàšŸàšµàšŸàš"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> àš€à©àš¹àšŸàš¡à© <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àšŠà© àš€àš°àš«àšŒà©àš àš€à©àš¹àšŸàš¡à© àš¡à©àšµàšŸàšàšžàšŸàš àšµàš¿àšàšàšŸàš° àšàšªàšŸàš àššà©à©° àšžàšà©àš°à©àš® àšàš°àšš àšŠà© àšàšàšŸàšàšŒàš€ àš®à©°àš àš°àš¹à© àš¹à©"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> àš€à©àš¹àšŸàš¡à© <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àšŠà© àš€àš°àš«àšŒà©àš àš€à©àš¹àšŸàš¡à© àš¡à©àšµàšŸàšàšžàšŸàš àšµàš¿àšàšàšŸàš° àšàšªàšŸàš àššà©à©° àšŠàš¿àšàšŸàšàš£ àš
àš€à© àšžàšà©àš°à©àš® àšàš°àšš àšŠà© àšàšàšŸàšàšŒàš€ àš®à©°àš àš°àš¹à© àš¹à©"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àššà©à©° àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àš€à©àš àšàšž àšàšŸàš£àšàšŸàš°à© àš€à©±àš àšªàš¹à©à©°àš àšàš°àšš àšŠà© àšàšàš¿àš àšŠàš¿àš"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play àšžà©àšµàšŸàšµàšŸàš"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> àš€à©àš¹àšŸàš¡à© <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> àšŠà© àš€àš°àš«àšŒà©àš àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àšŠà©àšàš àš«àšŒà©àšà©àšàš, àš®à©àš¡à©àš àš
àš€à© àšžà©àšàššàšŸàšµàšŸàš àš€à©±àš àšªàš¹à©à©°àš àšàš°àšš àšŠà© àšàšàšŸàšàšŒàš€ àš®à©°àš àš°àš¹à© àš¹à©"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"àšà© <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àššà©à©° àšàš¹ àšàšŸàš°àšµàšŸàš àšàš°àšš àšŠà© àšàšàš¿àš àšŠà©àš£à© àš¹à©?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"àšà© <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àššà©à©° àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àšŠà©àšàš àšàšªàšŸàš àššà©à©° àšžàšà©àš°à©àš® àšàš°àšš àš
àš€à© àšžàš¿àšžàšàš® àšµàš¿àšžàšŒà©àšžàšŒàš€àšŸàšµàšŸàš àšŠà© àšµàš°àš€à©àš àšàš°àšš àšŠà© àšàšàš¿àš àšŠà©àš£à© àš¹à©?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s àšà©àš² àšàš¡à©àš, àš«àšŒà©àšà©àšàš, àšà©àšàš€àšŸàšš àšàšŸàš£àšàšŸàš°à©, àšªàšŸàšžàšµàš°àš¡àšŸàš àš
àš€à© àšžà©àššà©àš¹àš¿àšàš àšžàš®à©àš€, àš«àšŒà©àšš \'àš€à© àšŠàš¿àšàšŸàš àšŠà©àš£ àšµàšŸàš²à© àšàšŸàš àšàš²àšŸàš àšàšŸàš£ àšµàšŸàš²à© àšàš¿àšžà© àšµà© àšà©àšàšŒ àš€à©±àš àšªàš¹à©à©°àš àš¹à©àšµà©àšà©à¥€<br/><br/>%1$s àšàšªàšŸàš àššà©à©° àšàšŠà©àš àš€à©±àš àšžàšà©àš°à©àš® àš
àš€à© àšžàš¿àšžàšàš® àšµàš¿àšžàšŒà©àšžàšŒàš€àšŸàšµàšŸàš àšŠà© àšµàš°àš€à©àš àšàš° àšžàšà©àšà©, àšàšŠà©àš àš€à©±àš àš€à©àšžà©àš àšàšž àšàšàšŸàšàšŒàš€ àš€à©±àš àšªàš¹à©à©°àš àššàš¹à©àš àš¹àšàšŸ àšŠàš¿à©°àšŠà©à¥€"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> àš€à©àš¹àšŸàš¡à© <xliff:g id="DEVICE_NAME">%2$s</xliff:g> àšŠà© àš€àš°àš«àšŒà©àš àššàšàšŒàšŠà©àšà© àš¡à©àšµàšŸàšàšžàšŸàš \'àš€à© àšàšªàšŸàš àš
àš€à© àš¹à©àš° àšžàš¿àšžàšàš® àšžà©°àš¬à©°àš§à© àšµàš¿àšžàšŒà©àšžàšŒàš€àšŸàšµàšŸàš àššà©à©° àšžàšà©àš°à©àš® àšàš°àšš àšŠà© àšàšàšŸàšàšŒàš€ àš®à©°àš àš°àš¹à© àš¹à©"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àš¡à©àšµàšŸàšàšž"</string>
<string name="summary_generic" msgid="1761976003668044801">"àšàš¹ àšàšª àš€à©àš¹àšŸàš¡à© àš«àšŒà©àšš àš
àš€à© àšà©àš£à© àšàš àš¡à©àšµàšŸàšàšž àšµàš¿àšàšàšŸàš° àšàšŸàš²àš° àšŠà© àššàšŸàš® àšµàš°àšà© àšàšŸàš£àšàšŸàš°à© àššà©à©° àšžàš¿à©°àš àšàš° àšžàšà©àšà©"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 41029b1..289d6e0 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming dos apps do smartphone?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps até que você remova o acesso a essa permissão."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming dos apps e recursos do sistema do smartphone?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps e recursos do sistema até que você remova o acesso a essa permissão."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 60a625c..9d94de7 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Esta app vai poder aceder a estas autorizações no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream das apps do telemóvel?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, palavras-passe e mensagens.<br/><br/>%1$s vai poder fazer stream de apps até remover o acesso a esta autorização."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para apresentar e fazer stream de apps entre os seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permita que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para aceder às fotos, ao conteúdo multimédia e às notificações do seu telemóvel"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça esta ação?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça stream das apps e das funcionalidades do sistema do telemóvel?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.<br/><br/>%1$s vai poder fazer stream de apps e funcionalidades do sistema até remover o acesso a esta autorização."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e outras funcionalidades do sistema para dispositivos próximos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 41029b1..289d6e0 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="2872254734959842579">"O app poderá acessar estas permissões no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming dos apps do smartphone?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps até que você remova o acesso a essa permissão."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming dos apps e recursos do sistema do smartphone?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps e recursos do sistema até que você remova o acesso a essa permissão."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 70fc090..99067df 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"dispozitiv"</string>
<string name="summary_glasses" msgid="2872254734959842579">"AplicaÈia va putea sÄ acceseze urmÄtoarele permisiuni pe <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Permite ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> sÄ acceseze aceste informaÈii de pe telefon"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"PermiÈi ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> sÄ poatÄ reda în stream aplicaÈiile de pe telefonul tÄu?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s va avea acces la tot ce este vizibil sau redat pe telefon, inclusiv conÈinutul audio, fotografii, parole Èi mesaje.<br/><br/>%1$s va putea reda în stream aplicaÈii pânÄ când elimini accesul la aceastÄ permisiune."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicitÄ permisiunea pentru <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> de a reda în stream aplicaÈii între dispozitivele tale"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicitÄ permisiunea pentru <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> de a afiÈa Èi a reda în stream aplicaÈii între dispozitive"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permite ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> sÄ acceseze aceste informaÈii de pe telefon"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicitÄ permisiunea pentru <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> de a accesa fotografiile, conÈinutul media Èi notificÄrile de pe telefon"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"PermiÈi ca <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> sÄ realizeze aceastÄ acÈiune?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"PermiÈi ca <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> sÄ poatÄ reda în stream aplicaÈiile Èi funcÈiile de sistem de pe telefonul tÄu?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s va avea acces la tot ce este vizibil sau redat pe telefon, inclusiv conÈinutul audio, fotografii, informaÈii de platÄ, parole Èi mesaje.<br/><br/>%1$s va putea reda în stream aplicaÈii Èi funcÈii de sistem pânÄ când elimini accesul la aceastÄ permisiune."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicitÄ permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream conÈinut din aplicaÈii Èi alte funcÈii de sistem pe dispozitivele din apropiere"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
<string name="summary_generic" msgid="1761976003668044801">"AplicaÈia va putea sÄ sincronizeze informaÈii, cum ar fi numele unui apelant, între telefonul tÄu Èi dispozitivul ales"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 2072f90..ce65c70 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÑÑÑÑПйÑÑве"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐÑП пÑОлПжеМОе пПлÑÑÐžÑ ÑказаММÑе ÑазÑеÑÐµÐœÐžÑ ÐœÐ° <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"РазÑеÑОÑе пÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> пПлÑÑаÑÑ ÑÑÑ ÐžÐœÑПÑЌаÑÐžÑ Ñ Ð²Ð°ÑегП ÑелеÑПМа"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"РазÑеÑОÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ Ñ Ð²Ð°ÑегП ÑелеÑПМа?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"ÐÑОлПжеМОе \"%1$s\" пПлÑÑÐžÑ ÐŽÐŸÑÑÑп кП вÑеЌÑ, ÑÑП пПказÑваеÑÑÑ ÐžÐ»Ðž вПÑпÑПОзвПЎОÑÑÑ ÐœÐ° ÑелеÑПМе, вклÑÑÐ°Ñ Ð°ÑЎОПÑайлÑ, ÑПÑПгÑаÑОО, паÑПлО О ÑППбÑеМОÑ.<br/><br/>ÐÑОлПжеМОе \"%1$s\" ÑÐŒÐŸÐ¶ÐµÑ ÑÑаМÑлОÑПваÑÑ Ð¿ÑОлПжеМОÑ, пПка Ð²Ñ ÐœÐµ ПÑзПвеÑе ÑÑП ÑазÑеÑеМОе."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"СеÑвОÑÑ ÑÑÑОЌОМга пÑОлПжеМОй"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ÐÑОлПжеМОе \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑаÑÐžÐ²Ð°ÐµÑ ÑазÑеÑеМОе ÐŸÑ ÐžÐŒÐµÐœÐž ваÑегП ÑÑÑÑПйÑÑва <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, ÑÑÐŸÐ±Ñ ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ ÐŒÐµÐ¶ÐŽÑ ÑÑÑÑПйÑÑваЌО."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ÐÑОлПжеМОе \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑаÑÐžÐ²Ð°ÐµÑ ÑазÑеÑеМОе ÐŸÑ ÐžÐŒÐµÐœÐž ваÑегП ÑÑÑÑПйÑÑва <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, ÑÑÐŸÐ±Ñ ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ ÐŒÐµÐ¶ÐŽÑ ÑÑÑÑПйÑÑваЌО."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"РазÑеÑОÑе пÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> пПлÑÑаÑÑ ÑÑÑ ÐžÐœÑПÑЌаÑÐžÑ Ñ Ð²Ð°ÑегП ÑелеÑПМа"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"СеÑвОÑÑ Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ÐÑОлПжеМОе \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запÑаÑÐžÐ²Ð°ÐµÑ ÑазÑеÑеМОе ÐŸÑ ÐžÐŒÐµÐœÐž ваÑегП ÑÑÑÑПйÑÑва <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑОÑÑ ÐŽÐŸÑÑÑп к ÑПÑПгÑаÑОÑÐŒ, ЌеЎОакПМÑеМÑÑ Ðž ÑвеЎПЌлеМОÑÐŒ Ма ÑелеÑПМе."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"РазÑеÑОÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> вÑпПлМÑÑÑ ÑÑП ЎейÑÑвОе?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"РазÑеÑОÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ Ðž ÑОÑÑеЌМÑе ÑÑМкÑОО Ñ Ð²Ð°ÑегП ÑелеÑПМа?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"ÐÑОлПжеМОе \"%1$s\" пПлÑÑÐžÑ ÐŽÐŸÑÑÑп кП вÑеЌÑ, ÑÑП пПказÑваеÑÑÑ ÐžÐ»Ðž вПÑпÑПОзвПЎОÑÑÑ ÐœÐ° ваÑеЌ ÑелеÑПМе, вклÑÑÐ°Ñ Ð°ÑЎОПÑайлÑ, ÑПÑПгÑаÑОО, плаÑежМÑе ЎаММÑе, паÑПлО О ÑППбÑеМОÑ.<br/><br/>ÐÑОлПжеМОе \"%1$s\" ÑÐŒÐŸÐ¶ÐµÑ ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ Ðž ÑОÑÑеЌМÑе ÑÑМкÑОО, пПка Ð²Ñ ÐœÐµ ПÑзПвеÑе ÑÑП ÑазÑеÑеМОе."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ÐÑОлПжеМОе \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ÐŸÑ ÐžÐŒÐµÐœÐž ваÑегП ÑÑÑÑПйÑÑва \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запÑаÑÐžÐ²Ð°ÐµÑ ÑазÑеÑеМОе ÑÑаМÑлОÑПваÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ Ðž ÑОÑÑеЌМÑе ÑÑМкÑОО Ма ÑÑÑÑПйÑÑва пПблОзПÑÑО."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÑÑÑÑПйÑÑвП"</string>
<string name="summary_generic" msgid="1761976003668044801">"ÐÑОлПжеМОе ÑÐŒÐŸÐ¶ÐµÑ ÑОМÑ
ÑПМОзОÑПваÑÑ ÐžÐœÑПÑЌаÑÐžÑ ÐŒÐµÐ¶ÐŽÑ ÑелеÑПМПЌ О вÑбÑаММÑÐŒ ÑÑÑÑПйÑÑвПЌ, МапÑÐžÐŒÐµÑ ÐŽÐ°ÐœÐœÑе Оз жÑÑМала звПМкПв."</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 6d25260..c1d79e5 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"à¶à¶Žà·à¶à¶à¶º"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à¶žà·à¶ž යà·à¶¯à·à¶žà¶§ à¶à¶¶à· <xliff:g id="DEVICE_NAME">%1$s</xliff:g> à¶žà¶ à¶žà·à¶ž à¶
à·à·à¶» à·à·à¶ à¶Žà·à¶»à·à·à· à·à·à¶žà¶§ à¶à¶© දà·à¶±à· à¶œà·à¶¶à·"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à·à¶§ à¶à¶¶à¶à· දà·à¶»à¶à¶®à¶±à¶ºà·à¶±à· à¶žà·à¶ž à¶à·à¶»à¶à·à¶»à·à·à¶œà¶§ à¶Žà·à¶»à·à·à· à·à·à¶žà¶§ à¶à¶© දà·à¶±à·à¶±"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"à¶à¶¶à· දà·à¶»à¶à¶®à¶±à¶ºà· යà·à¶¯à·à¶žà· à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à·à· à¶à¶© දà·à¶±à·à¶± ද?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"à·à·à¶»à·à·à¶º, à¶¡à·à¶ºà·à¶»à·à¶Ž, à¶žà·à¶»à¶Žà¶¯ à·à· à¶Žà¶«à·à·à·à¶© à¶à¶à·à·
෠දà·à¶»à¶à¶®à¶±à¶º ඞචදà·à¶à·à¶º à·à·à¶à· à·à· à·à·à¶¯à¶±à¶º à¶à¶» à¶à¶à· à¶à¶±à·à¶ž දà·à¶ºà¶à¶§ %1$s à·à¶§ à¶Žà·à¶»à·à·à·à¶º à¶à·à¶¶à·à¶±à· à¶à¶. à¶à¶¶ à¶žà·à¶ž à¶
à·à·à¶»à¶º à·à·à¶ à¶Žà·à¶»à·à·à·à¶º à¶à·à¶à· à¶à¶»à¶± à¶à·à¶à· <br/><br/>%1$s à·à¶§ යà·à¶¯à·à¶žà· à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ à·à·à¶à· à·à·à¶±à· à¶à¶."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"à·à¶»à·à·-à¶à¶Žà·à¶à¶ à·à·à·à·"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> à¶à¶¶à· <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à·à·à¶±à·à·à·à¶±à· à¶à¶¶à· à¶à¶Žà·à¶à¶ à¶
à¶à¶» යà·à¶¯à·à¶žà· à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ à¶
à·à·à¶»à¶º à¶à¶œà·à¶œà¶žà·à¶±à· à·à·à¶§à·à¶ºà·"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"à¶à¶¶à· <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à·à·à¶±à·à·à·à¶±à· <xliff:g id="APP_NAME">%1$s</xliff:g> à¶à¶¶à· à¶à¶Žà·à¶à¶ à¶
à¶à¶» යà·à¶¯à·à¶žà· à·à¶à¶¯à¶»à·à·à¶±à¶º à¶à·à¶»à·à¶žà¶§ à·à· à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ à¶
à·à·à¶» à¶à¶œà·à¶œà¶ºà·"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à·à¶§ à¶à¶¶à¶à· දà·à¶»à¶à¶®à¶±à¶ºà·à¶±à· à¶žà·à¶ž à¶à·à¶»à¶à·à¶»à·à·à¶œà¶§ à¶Žà·à¶»à·à·à· à·à·à¶žà¶§ à¶à¶© දà·à¶±à·à¶±"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play à·à·à·à·"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> à¶à¶¶à· <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à·à·à¶±à·à·à·à¶±à· à¶à¶¶à· දà·à¶»à¶à¶®à¶±à¶ºà· à¶¡à·à¶ºà·à¶»à·à¶Ž, à¶žà·à¶°à·à¶º, à·à· දà·à¶±à·à¶žà·à¶¯à·à¶žà· à·à·à¶ à¶Žà·à¶»à·à·à· à·à·à¶žà¶§ à¶
à·à·à¶»à¶º à¶à¶œà·à¶œà¶žà·à¶±à· à·à·à¶§à·à¶ºà·"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"à¶žà·à¶ž à¶à·à¶»à·à¶ºà·à· à¶à·à¶»à·à¶žà¶§ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à·à¶§ à¶à¶© දà·à¶±à·à¶± ද?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"à¶à¶¶à· දà·à¶»à¶à¶®à¶±à¶ºà· යà·à¶¯à·à¶žà· à·à· ඎදà·à¶°à¶à· à·à·à·à·à·à·à¶à¶ à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à·à¶§ à¶à¶© දà·à¶±à·à¶± ද?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"à·à·à¶»à·à·à¶º, à¶¡à·à¶ºà·à¶»à·à¶Ž, à¶à·à·à·à¶žà· à¶à¶à·, à¶žà·à¶»à¶Žà¶¯ à·à· à¶Žà¶«à·à·à·à¶© à¶à¶à·à·
෠දà·à¶»à¶à¶®à¶±à¶º ඞචදà·à¶à·à¶º à·à·à¶à· à·à· à·à·à¶¯à¶±à¶º à¶à¶» à¶à¶à· à¶à¶±à·à¶ž දà·à¶ºà¶à¶§ %1$s à·à¶§ à¶Žà·à¶»à·à·à·à¶º à¶à·à¶¶à·à¶±à· à¶à¶. à¶à¶¶ à¶žà·à¶ž à¶
à·à·à¶»à¶º à·à·à¶ à¶Žà·à¶»à·à·à·à¶º à¶à·à¶à· à¶à¶»à¶± à¶à·à¶à· <br/><br/>%1$s à·à¶§ යà·à¶¯à·à¶žà· à·à· ඎදà·à¶°à¶à· à·à·à·à·à·à·à¶à¶ à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ à·à·à¶à· à·à·à¶±à· à¶à¶."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> à¶à¶¶à· <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à·à·à¶±à·à·à·à¶±à· යà·à¶¯à·à¶žà· à·à· à¶
à¶±à·à¶à·à¶à· ඎදà·à¶°à¶à· à·à·à·à·à·à·à¶à¶ à¶
à·à¶§ à¶à¶Žà·à¶à¶ à·à·à¶ à¶Žà·à¶»à·à·à· à¶à·à¶»à·à¶žà¶§ à¶
à·à·à¶» à¶à¶œà·à¶œà¶ºà·"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"à¶à¶Žà·à¶à¶à¶º"</string>
<string name="summary_generic" msgid="1761976003668044801">"à¶žà·à¶ž යà·à¶¯à·à¶žà¶§ à¶à¶¶à· දà·à¶»à¶à¶®à¶±à¶º à·à· à¶à·à¶»à· à¶à¶à· à¶à¶Žà·à¶à¶à¶º à¶
à¶à¶», à¶
à¶žà¶à¶± à¶à·à¶±à·à¶à·à¶à· නඞ à·à·à¶±à·, à¶à¶à· à·à¶žà¶žà·à·à·à¶»à·à¶ à¶à·à¶»à·à¶žà¶§ à·à·à¶à· à·à¶±à· à¶à¶"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index b165331..bbee596 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"zariadenie"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Táto aplikácia bude maÅ¥ prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"PovoÄŸte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Chcete povoliÅ¥ aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovaÅ¥ aplikácie vo svojom telefóne?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s bude maÅ¥ prístup k všetkému obsahu viditeÄŸnému alebo prehrávanému v telefóne vrátane zvuku, fotiek, hesiel a správ.<br/><br/>%1$s bude môcÅ¥ streamovaÅ¥ aplikácie, kým prístup k tomuto povoleniu neodstránite."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"SluÅŸby pre viacero zariadení"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyÅŸaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie streamovaÅ¥ aplikácie medzi vašimi zariadeniami."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyÅŸaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie zobrazovaÅ¥ a streamovaÅ¥ aplikácie medzi zariadeniami"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"PovoÄŸte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"SluÅŸby Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyÅŸaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Chcete povoliÅ¥ zariadeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> vykonaÅ¥ túto akciu?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Chcete povoliÅ¥ aplikácii <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> streamovaÅ¥ aplikácie a systémové funkcie vo svojom telefóne?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s bude maÅ¥ prístup k všetkému obsahu viditeÄŸnému alebo prehrávanému v telefóne vrátane zvuku, fotiek, platobných údajov, hesiel a správ.<br/><br/>%1$s bude môcÅ¥ streamovaÅ¥ aplikácie, kým prístup k tomuto povoleniu neodstránite."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyÅŸaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovaÅ¥ aplikácie a Äalšie systémové funkcie do zariadení v okolí"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
<string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcÅ¥ synchronizovaÅ¥ informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 6972fb4..346fbae 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"naprava"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ta aplikacija bo lahko dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«."</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ali aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite, da pretoÄno predvaja aplikacije telefona?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"Aplikacija %1$s bo imela dostop do vsega, kar je prikazano ali se predvaja v telefonu, vkljuÄno z zvokom, fotografijami, gesli in sporoÄili.<br/><br/>Aplikacija %1$s bo lahko pretoÄno predvajala aplikacije, dokler ne odstranite dostopa do tega dovoljenja."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretoÄno predvajanje aplikacij v vaših napravah."</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za prikaz in pretoÄno predvajanje aplikacij v vaših napravah."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v telefonu."</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ali napravi <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dovolite izvedbo tega dejanja?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Ali napravi <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dovolite, da pretoÄno predvaja aplikacije in sistemske funkcije telefona?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Naprava %1$s bo imela dostop do vsega, kar je prikazano ali se predvaja v telefonu, vkljuÄno z zvokom, fotografijami, podatki za plaÄilo, gesli in sporoÄili.<br/><br/>Naprava %1$s bo lahko pretoÄno predvajala aplikacije in sistemske funkcije, dokler ne odstranite dostopa do tega dovoljenja."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretoÄno predvajanje aplikacij in drugih sistemskih funkcij v napravah v bliÅŸini."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in izbrani napravi."</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 635e5c8..76f623a 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"pajisje"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Këtij aplikacioni do t\'i lejohet qasja te këto leje në <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet e telefonit tënd?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose luhet në telefon, duke përfshirë audion, fotografitë, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund të transmetojë aplikacionet derisa ta heqësh qasjen për këtë leje."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të shfaqur dhe transmetuar aplikacionet mes pajisjeve të tua"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të ndërmarrë këtë veprim?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet dhe veçoritë e sistemit të telefonit tënd?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose luhet në telefon, duke përfshirë audion, fotografitë, informacionet për pagesën, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund të transmetojë aplikacionet dhe veçoritë e sistemit derisa ta heqësh qasjen për këtë leje."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) tënde për të transmetuar aplikacione dhe veçori të tjera të sistemit te pajisjet në afërsi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index af9e194..22eafa5 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"ÑÑеÑаÑ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"ÐÐ²ÐŸÑ Ð°Ð¿Ð»ÐžÐºÐ°ÑОÑО Ñе бОÑО ЎПзвПÑеМП Ўа пÑОÑÑÑпа ПвОЌ ЎПзвПлаЌа Ма ваÑеЌ ÑÑеÑаÑÑ (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ÐПзвПлОÑе Ўа <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> пÑОÑÑÑпа ПвОЌ ОМÑПÑЌаÑОÑаЌа Ñа ÑелеÑПМа"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ÐелОÑе лО Ўа ЎПзвПлОÑе Ўа <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÑÑÑОЌÑÑе аплОкаÑОÑе Ма ÑелеÑПМÑ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Ñе ОЌаÑО пÑОÑÑÑп ÑÐ²ÐµÐŒÑ ÑÑП Ñе вОЎО ОлО пÑÑÑа Ма ÑелеÑПМÑ, ÑкÑÑÑÑÑÑÑО звÑк, ÑлОке, лПзОМке О пПÑÑке.<br/><br/>%1$s Ñе ЌПÑО Ўа ÑÑÑОЌÑÑе аплОкаÑОÑе ЎПк Ме ÑклПМОÑе пÑОÑÑÑп ÐŸÐ²ÐŸÑ ÐŽÐŸÐ·Ð²ÐŸÐ»Ðž."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"УÑлÑге Ма вОÑе ÑÑеÑаÑа"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> заÑ
Ñева ÐŽÐŸÐ·Ð²ÐŸÐ»Ñ Ñ ÐžÐŒÐµ ÑÑеÑаÑа <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за ÑÑÑОЌПваÑе аплОкаÑОÑа ОзЌеÑÑ ÑÑеÑаÑа"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÑÑажО ÐŽÐŸÐ·Ð²ÐŸÐ»Ñ Ñ ÐžÐŒÐµ ÑÑеÑаÑа <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Ўа пÑОказÑÑе О ÑÑÑОЌÑÑе аплОкаÑОÑе ОзЌеÑÑ ÑÑеÑаÑа"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ÐПзвПлОÑе Ўа <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> пÑОÑÑÑпа ПвОЌ ОМÑПÑЌаÑОÑаЌа Ñа ÑелеÑПМа"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play ÑÑлÑге"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> заÑ
Ñева ÐŽÐŸÐ·Ð²ÐŸÐ»Ñ Ñ ÐžÐŒÐµ ÑÑеÑаÑа <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> за пÑОÑÑÑп ÑлОкаЌа, ЌеЎОÑÑкПЌ ÑаЎÑжаÑÑ Ðž ПбавеÑÑеÑОЌа Ñа ÑелеÑПМа"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ÐелОÑе лО Ўа ЎПзвПлОÑе Ўа <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ПбавО ÐŸÐ²Ñ ÑаЎÑÑ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ÐелОÑе лО Ўа ЎПзвПлОÑе Ўа <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÑÑÑОЌÑÑе аплОкаÑОÑе О ÑÑМкÑОÑе ÑОÑÑеЌа Ма ÑелеÑПМÑ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s Ñе ОЌаÑО пÑОÑÑÑп ÑÐ²ÐµÐŒÑ ÑÑП Ñе вОЎО ОлО пÑÑÑа Ма ÑелеÑПМÑ, ÑкÑÑÑÑÑÑÑО звÑк, ÑлОке, ОМÑПÑЌаÑОÑе П плаÑаÑÑ, лПзОМке О пПÑÑке.<br/><br/>%1$s Ñе ЌПÑО Ўа ÑÑÑОЌÑÑе аплОкаÑОÑе О ÑÑМкÑОÑе ÑОÑÑеЌа ЎПк Ме ÑклПМОÑе пÑОÑÑÑп ÐŸÐ²ÐŸÑ ÐŽÐŸÐ·Ð²ÐŸÐ»Ðž."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ÐплОкаÑОÑа <xliff:g id="APP_NAME">%1$s</xliff:g> заÑ
Ñева ÐŽÐŸÐ·Ð²ÐŸÐ»Ñ Ñ ÐžÐŒÐµ ÑÑеÑаÑа <xliff:g id="DEVICE_NAME">%2$s</xliff:g> Ўа ÑÑÑОЌÑÑе аплОкаÑОÑе О ÐŽÑÑге ÑОÑÑеЌÑке ÑÑМкÑОÑе Ма ÑÑеÑаÑе Ñ Ð±Ð»ÐžÐ·ÐžÐœÐž"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ÑÑеÑаÑ"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ðва аплОкаÑОÑа Ñе ЌПÑО Ўа ÑОМÑ
ÑПМОзÑÑе пПЎаÑке, пПпÑÑ ÐžÐŒÐµÐœÐ° ПÑПбе кПÑа ÑпÑÑÑÑе пПзОв, ОзЌеÑÑ ÑелеÑПМа О ПЎабÑаМПг ÑÑеÑаÑа"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index fdde926..2c0f9c4 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"enhet"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Appen får tillåtelse att använda dessa behörigheter på din <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vill du tillåta <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> att streama telefonens appar?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s får åtkomst till allt som visas eller spelas på telefonen, inklusive ljud, foton, lösenord och meddelanden.<br/><br/>%1$s kan streama appar tills du tar bort behörigheten."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att låta <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> streama appar mellan enheter"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att visa och streama appar mellan enheter åt din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att ge <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> åtkomst till foton, mediefiler och aviseringar på telefonen"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vill du tillåta att <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> utför denna åtgärd?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vill du tillåta <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> att streama telefonens appar och systemfunktioner?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s får åtkomst till allt som visas eller spelas på telefonen, inklusive ljud, foton, betalningsuppgifter, lösenord och meddelanden.<br/><br/>%1$s kan streama appar och systemfunktioner tills du tar bort behörigheten."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att streama appar och andra systemfunktioner till enheter i närheten för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="1761976003668044801">"Den här appen kommer att kunna synkronisera information mellan telefonen och den valda enheten, till exempel namnet på någon som ringer"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 2fb4677..5820279 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"kifaa"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Programu hii itaruhusiwa kufikia ruhusa hizi kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> itiririshe programu za simu yako?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s itakuwa na uwezo wa kufikia chochote kinachoonekana au kuchezwa kwenye simu, ikiwa ni pamoja na sauti, picha, manenosiri na ujumbe.<br/><br/>%1$s itaweza kutiririsha programu hadi uondoe ruhusa hii."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yako ili itiririshe programu kati ya vifaa vyako"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yako ili ionyeshe na kutiririsha programu kati ya vifaa vyako"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yako ili ifikie picha, maudhui na arifa za simu yako"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ungependa kuruhusu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> itekeleze kitendo hiki?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Ungependa kuruhusu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> itiririshe programu za simu na vipengele vya mfumo wako?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s itakuwa na uwezo wa kufikia chochote kinachoonekana au kuchezwa kwenye simu yako, ikiwa ni pamoja na sauti, picha, maelezo ya malipo, manenosiri na ujumbe.<br/><br/>%1$s itaweza kutiririsha programu na vipengele vya mfumo hadi uondoe ruhusa hii."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> chako ili itiririshe programu na vipengele vingine vya mfumo kwenye vifaa vilivyo karibu"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
<string name="summary_generic" msgid="1761976003668044801">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu yako na kifaa ulichochagua"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 62a9c33..5133073 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"à®à®Ÿà®€à®©à®®à¯"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à®à®à¯à®à®³à¯ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> à®à®Ÿà®€à®©à®€à¯à®€à®¿à®²à¯ à®à®šà¯à®€ à®
னà¯à®®à®€à®¿à®à®³à¯ à®
ணà¯à® à®à®šà¯à®€ à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®à¯à®à®ªà¯à®ªà®à¯à®®à¯"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"à®®à¯à®ªà¯à®²à®¿à®²à¯ à®à®³à¯à®³ à®à®šà¯à®€à®€à¯ ஀à®à®µà®²à¯à®à®³à¯ à®
ணà¯à®, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®à¯à®à®µà¯à®®à¯"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à®¿à®©à¯ à®à®ªà¯à®žà¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®à¯à®à®µà®Ÿ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"à®à®à®¿à®¯à¯, பà®à®à¯à®à®³à¯, à®à®à®µà¯à®à¯à®à¯à®±à¯à®à®³à¯, à®®à¯à®à¯à®à¯à®à®³à¯ à®à®à¯à®ªà® à®®à¯à®ªà¯à®²à®¿à®²à¯ à®à®Ÿà®à¯à®à®ªà¯à®ªà®à¯à®à®¿à®©à¯à®± à®
லà¯à®²à®€à¯ பிள௠à®à¯à®¯à¯à®¯à®ªà¯à®ªà®à¯à®à®¿à®©à¯à®± à®
னà¯à®€à¯à®€à¯à®¯à¯à®®à¯ %1$s à®
ணà¯à®à¯à®®à¯.<br/><br/>à®à®šà¯à®€ à®
னà¯à®®à®€à®¿à®à¯à®à®Ÿà®© à®
ணà¯à®à®²à¯ சà¯à®à¯à®à®³à¯ à®
à®à®±à¯à®±à¯à®®à¯ வர௠%1$s à®à®²à¯ à®à®ªà¯à®žà¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ à®®à¯à®à®¿à®¯à¯à®®à¯."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"பனà¯à®®à¯à® à®à®Ÿà®€à®© à®à¯à®µà¯à®à®³à¯"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"à®à®à¯à®à®³à¯ à®à®Ÿà®€à®©à®à¯à®à®³à¯à®à¯à®à¯ à®à®à¯à®¯à¯ à®à®ªà¯à®žà¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ à®à®à¯à®à®³à¯ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à®à®Ÿà®°à¯à®ªà®Ÿà® <xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®¯à¯à®à¯ à®à¯à®°à¯à®à®¿à®±à®€à¯"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"à®à®à¯à®à®³à¯ à®à®Ÿà®€à®©à®à¯à®à®³à¯à®à¯à®à¯ à®à®à¯à®¯à¯ à®à®ªà¯à®žà¯à®à¯ à®à®Ÿà®à¯à®à®¿à®ªà¯à®ªà®à¯à®€à¯à®€à®µà¯à®®à¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯à®µà¯à®®à¯ à®à®à¯à®à®³à¯ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à®à®Ÿà®°à¯à®ªà®Ÿà® <xliff:g id="APP_NAME">%1$s</xliff:g> à®
னà¯à®®à®€à®¿ à®à¯à®à¯à®à®¿à®±à®€à¯"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à®¿à®²à®¿à®°à¯à®šà¯à®€à¯ à®à®šà¯à®€à®€à¯ ஀à®à®µà®²à¯ à®
ணà¯à® <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®¯à¯à®à¯à®à®³à¯"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play à®à¯à®µà¯à®à®³à¯"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à®¿à®²à¯ à®à®³à¯à®³ பà®à®à¯à®à®³à¯, à®®à¯à®à®¿à®¯à®Ÿ, à®
றிவிபà¯à®ªà¯à®à®³à¯ à®à®à®¿à®¯à®µà®±à¯à®±à¯ à®
ணà¯à® à®à®à¯à®à®³à¯ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à®à®Ÿà®°à¯à®ªà®Ÿà® <xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®¯à¯à®à¯ à®à¯à®°à¯à®à®¿à®±à®€à¯"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"à®à®šà¯à®€à®à¯ à®à¯à®¯à®²à¯à®à¯ à®à¯à®¯à¯à®¯ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à® à®
னà¯à®®à®€à®¿à®à¯à®à®µà®Ÿ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à®¿à®©à¯ à®à®ªà¯à®žà¯ மறà¯à®±à¯à®®à¯ à®à®¿à®žà¯à®à®®à¯ à®
à®®à¯à®à®à¯à®à®³à¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à®à®ªà¯à®žà¯ à®
னà¯à®®à®€à®¿à®à¯à®à®µà®Ÿ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"à®à®à®¿à®¯à¯, பà®à®à¯à®à®³à¯, பà¯à®®à¯à®£à¯à®à¯ ஀à®à®µà®²à¯à®à®³à¯, à®à®à®µà¯à®à¯à®à¯à®±à¯à®à®³à¯, à®®à¯à®à¯à®à¯à®à®³à¯ à®à®à¯à®ªà® à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à®¿à®²à¯ à®à®Ÿà®à¯à®à®ªà¯à®ªà®à¯à®à®¿à®©à¯à®± à®
லà¯à®²à®€à¯ பிள௠à®à¯à®¯à¯à®¯à®ªà¯à®ªà®à¯à®à®¿à®©à¯à®± à®
னà¯à®€à¯à®€à¯à®¯à¯à®®à¯ %1$s à®
ணà¯à®à¯à®®à¯.<br/><br/>à®à®šà¯à®€ à®
னà¯à®®à®€à®¿à®à¯à®à®Ÿà®© à®
ணà¯à®à®²à¯ சà¯à®à¯à®à®³à¯ à®
à®à®±à¯à®±à¯à®®à¯ வர௠%1$s à®à®²à¯ à®à®ªà¯à®žà¯ மறà¯à®±à¯à®®à¯ à®à®¿à®žà¯à®à®®à¯ à®
à®®à¯à®à®à¯à®à®³à¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ à®®à¯à®à®¿à®¯à¯à®®à¯."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"à®
à®°à¯à®à®¿à®²à¯à®³à¯à®³ à®à®Ÿà®€à®©à®à¯à®à®³à¯à®à¯à®à¯ à®à®ªà¯à®žà¯à®¯à¯à®®à¯ பிற à®à®¿à®žà¯à®à®®à¯ à®
à®®à¯à®à®à¯à®à®³à¯à®¯à¯à®®à¯ ஞà¯à®à¯à®°à¯à®®à¯ à®à¯à®¯à¯à®¯ à®à®à¯à®à®³à¯ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à®à®Ÿà®°à¯à®ªà®Ÿà® <xliff:g id="APP_NAME">%1$s</xliff:g> à®
னà¯à®®à®€à®¿ à®à¯à®°à¯à®à®¿à®±à®€à¯"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"à®à®Ÿà®€à®©à®®à¯"</string>
<string name="summary_generic" msgid="1761976003668044801">"à®
எà¯à®ªà¯à®ªà®µà®°à®¿à®©à¯ பà¯à®¯à®°à¯ பà¯à®©à¯à®± ஀à®à®µà®²à¯ à®à®à¯à®à®³à¯ à®®à¯à®ªà¯à®²à¯ மறà¯à®±à¯à®®à¯ ஀à¯à®°à¯à®µà¯à®à¯à®¯à¯à®€ à®à®Ÿà®€à®©à®€à¯à®€à®¿à®±à¯à®à¯ à®à®à¯à®¯à®¿à®²à¯ à®à®šà¯à®€ à®à®ªà¯à®žà®Ÿà®²à¯ à®à®€à¯à®€à®¿à®à¯à®à¯à® à®®à¯à®à®¿à®¯à¯à®®à¯"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 4e26141..ede266e 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"పరిà°à°°à°"</string>
<string name="summary_glasses" msgid="2872254734959842579">"మౠ<xliff:g id="DEVICE_NAME">%1$s</xliff:g>లౠఠà°
à°šà±à°®à°€à±à°²à°šà± యటà°à±à°žà±à°žà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ ఠయటపౠà°
à°šà±à°®à°€à°¿à°à°à°¬à°¡à±à°€à±à°à°Šà°¿"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"మౠఫà±à°šà± à°šà±à°à°¡à°¿ ఠఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ యటà°à±à°žà±à°žà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యటపà±à°šà± à°
à°šà±à°®à°€à°¿à°à°à°à°¡à°¿"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"మౠఫà±à°šà± యటపà±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>à°šà± à°
à°šà±à°®à°€à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"à°à°¡à°¿à°¯à±, à°«à±à°à±à°²à±, పటఞà±à°µà°°à±à°¡à±à°²à±, à°®à±à°žà±à°à±à°²à°€à± ఞహట à°«à±à°šà±à°²à± à°à°šà°¿à°ªà°¿à°à°à± à°²à±à°Šà°Ÿ à°ªà±à°²à± à°
à°¯à±à°¯à± à°Šà±à°šà°¿à°à±à°šà°Ÿ %1$sà°à± యటà°à±à°žà±à°žà± à°à°à°à±à°à°Šà°¿.<br/><br/>à°®à±à°°à± à° à°
à°šà±à°®à°€à°¿à°à°¿ యటà°à±à°žà±à°žà±à°šà± à°€à±à°žà°¿à°µà±à°žà± వరà°à± %1$s యటపà±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°à°²à°Šà±."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"మౠపరిà°à°°à°Ÿà°² మధà±à°¯ యటపà±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <xliff:g id="APP_NAME">%1$s</xliff:g> మౠ<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ఀరఫà±à°š à°
à°šà±à°®à°€à°¿à°šà°¿ à°°à°¿à°à±à°µà±à°žà±à°à± à°à±à°žà±à°€à±à°à°Šà°¿"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"మౠపరిà°à°°à°Ÿà°²à°²à± యటపà±à°²à°šà± à°¡à°¿à°žà±à°ªà±à°²à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿, à°žà±à°à±à°°à±à°®à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ఀరఫà±à°š <xliff:g id="APP_NAME">%1$s</xliff:g> à°
à°šà±à°®à°€à°¿à°šà°¿ à°°à°¿à°à±à°µà±à°žà±à°à± à°à±à°žà±à°€à±à°à°Šà°¿"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"మౠఫà±à°šà± à°šà±à°à°¡à°¿ ఠఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ యటà°à±à°žà±à°žà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యటపà±à°šà± à°
à°šà±à°®à°€à°¿à°à°à°à°¡à°¿"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play à°žà°°à±à°µà±à°žà±à°²à±"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> మౠఫà±à°šà±à°²à±à°šà°¿ à°«à±à°à±à°²à°šà±, à°®à±à°¡à°¿à°¯à°Ÿà°šà±, à°à°à°à°Ÿ à°šà±à°à°¿à°«à°¿à°à±à°·à°šà±à°²à°šà± యటà°à±à°žà±à°žà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ మౠ<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ఀరఫà±à°š à°
à°šà±à°®à°€à°¿à°šà°¿ à°°à°¿à°à±à°µà±à°žà±à°à± à°à±à°žà±à°€à±à°à°Šà°¿"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"à° à°à°°à±à°¯à°šà± à°
మలౠà°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>à°šà± à°
à°šà±à°®à°€à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"మౠఫà±à°šà± యటపà±à°²à°šà±, à°žà°¿à°žà±à°à°®à± à°«à±à°à°°à±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>à°šà± à°
à°šà±à°®à°€à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"à°à°¡à°¿à°¯à±, à°«à±à°à±à°²à±, à°ªà±à°®à±à°à°à± ఞమటà°à°Ÿà°°à°, పటఞà±à°µà°°à±à°¡à±à°²à±, à°®à±à°žà±à°à±à°²à°€à± ఞహట మౠఫà±à°šà±à°²à± à°à°šà°¿à°ªà°¿à°à°à± à°²à±à°Šà°Ÿ à°ªà±à°²à± à°
à°¯à±à°¯à± à°Šà±à°šà°¿à°à±à°šà°Ÿ %1$sà°à± యటà°à±à°žà±à°žà± à°à°à°à±à°à°Šà°¿.<br/><br/>à°®à±à°°à± à° à°
à°šà±à°®à°€à°¿à°à°¿ యటà°à±à°žà±à°žà±à°šà± à°€à±à°žà°¿à°µà±à°žà± వరà°à± %1$s యటపà±à°²à°šà±, à°žà°¿à°žà±à°à°®à± à°«à±à°à°°à±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°à°²à°Šà±."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"à°žà°®à±à°ªà°à°²à±à°šà°¿ పరిà°à°°à°Ÿà°²à°à± యటపà±à°²à°šà±, à°à°€à°° à°žà°¿à°žà±à°à°®à± à°«à±à°à°°à±à°²à°šà± à°žà±à°à±à°°à±à°®à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ <xliff:g id="APP_NAME">%1$s</xliff:g> మౠ<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ఀరఫà±à°š à°
à°šà±à°®à°€à°¿à°šà°¿ à°°à°¿à°à±à°µà±à°žà±à°à± à°à±à°žà±à°€à±à°à°Šà°¿"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరిà°à°°à°"</string>
<string name="summary_generic" msgid="1761976003668044801">"à°à°Ÿà°²à± à°à±à°žà±à°€à±à°šà±à°š వటరి à°ªà±à°°à± à°µà°à°à°¿ ఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ ఠయటపౠమౠఫà±à°šà± à°à±, à°à°à°à±à°à±à°šà±à°š పరిà°à°°à°Ÿà°šà°¿à°à± మధà±à°¯ à°žà°¿à°à°à± à°à±à°¯à°à°²à±à°à±à°€à±à°à°Šà°¿"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 8be8b34..a2424ec 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"àžàžžàžàžàž£àžà¹"</string>
<string name="summary_glasses" msgid="2872254734959842579">"à¹àžàžàžàžµà¹àžàž°à¹àžà¹àž£àž±àžàžªàžŽàžàžàžŽà¹àžàž±àžàžà¹àžà¹àžàžàžµà¹à¹àž<xliff:g id="DEVICE_NAME">%1$s</xliff:g>àžàžàžàžàžžàž"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"àžàžàžžàžàž²àžà¹àž«à¹ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à¹àžà¹àž²àžàž¶àžàžà¹àžàž¡àž¹àž¥àžàžµà¹àžàž²àžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàž"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"àžàžàžžàžàž²àžà¹àž«à¹ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> àžªàžàž£àžµàž¡à¹àžàžà¹àžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàžà¹àž«àž¡"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s àžàž°àž¡àžµàžªàžŽàžàžàžŽà¹à¹àžà¹àž²àžàž¶àžàžàžžàžàžàž¢à¹àž²àžàžàžµà¹àžàž£àž²àžàžàž«àž£àž·àžà¹àž¥à¹àžàžàžà¹àžàž£àžšàž±àžàžà¹ àžàž¶à¹àžàž£àž§àž¡àžàž¶àžà¹àžªàžµàž¢àž àž£àž¹àžàž àž²àž àž£àž«àž±àžªàžà¹àž²àž à¹àž¥àž°àžà¹àžàžàž§àž²àž¡<br/><br/>%1$s àžàž°àžªàž²àž¡àž²àž£àžàžªàžàž£àžµàž¡à¹àžàžà¹àžà¹àžàžàžàž§à¹àž²àžàžžàžàžàž°àžàž³àžªàžŽàžàžàžŽà¹à¹àžà¹àž²àžàž¶àžàžàžµà¹àžàžàž"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"àžàž£àžŽàžàž²àž£àžà¹àž²àž¡àžàžžàžàžàž£àžà¹"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> àžàž³àž¥àž±àžàžàžàžªàžŽàžàžàžŽà¹à¹àžàžàž²àž¡àžàžàž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à¹àžàž·à¹àžàžªàžàž£àžµàž¡à¹àžàžàž£àž°àž«àž§à¹àž²àžàžàžžàžàžàž£àžà¹àžà¹àž²àžà¹ àžàžàžàžàžžàž"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> àžàž³àž¥àž±àžàžàžàžªàžŽàžàžàžŽà¹à¹àžàžàž²àž¡àžàžàž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à¹àžàž·à¹àžà¹àžªàžàžà¹àž¥àž°àžªàžàž£àžµàž¡à¹àžàžàž£àž°àž«àž§à¹àž²àžàžàžžàžàžàž£àžà¹àžà¹àž²àžà¹ àžàžàžàžàžžàž"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"àžàžàžžàžàž²àžà¹àž«à¹ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à¹àžà¹àž²àžàž¶àžàžà¹àžàž¡àž¹àž¥àžàžµà¹àžàž²àžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàž"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"àžàž£àžŽàžàž²àž£ Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> àžàž³àž¥àž±àžàžàžàžªàžŽàžàžàžŽà¹à¹àžàžàž²àž¡àžàžàž <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> à¹àžàž·à¹àžà¹àžà¹àž²àžàž¶àžàž£àž¹àžàž àž²àž àžªàž·à¹àž à¹àž¥àž°àžàž²àž£à¹àžà¹àžà¹àžàž·àžàžà¹àžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàž"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"àžàžàžžàžàž²àžà¹àž«à¹ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àžàž³àžàž²àžàžàžµà¹à¹àž«àž¡"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"àžàžàžžàžàž²àžà¹àž«à¹ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> àžªàžàž£àžµàž¡à¹àžàžà¹àž¥àž°àžàžµà¹àžàžàž£à¹àžàžàžàž£àž°àžàžà¹àžà¹àžàž£àžšàž±àžàžà¹à¹àž«àž¡"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s àžàž°àž¡àžµàžªàžŽàžàžàžŽà¹à¹àžà¹àž²àžàž¶àžàžàžžàžàžàž¢à¹àž²àžàžàžµà¹àžàž£àž²àžàžàž«àž£àž·àžà¹àž¥à¹àžàžàžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàž àžàž¶à¹àžàž£àž§àž¡àžàž¶àžà¹àžªàžµàž¢àž àž£àž¹àžàž àž²àž àžà¹àžàž¡àž¹àž¥àžàž²àž£àžàž³àž£àž°à¹àžàžŽàž àž£àž«àž±àžªàžà¹àž²àž à¹àž¥àž°àžà¹àžàžàž§àž²àž¡<br/><br/>%1$s àžàž°àžªàž²àž¡àž²àž£àžàžªàžàž£àžµàž¡à¹àžàžà¹àž¥àž°àžàžµà¹àžàžàž£à¹àžàžàžàž£àž°àžàžà¹àžà¹àžàžàžàž§à¹àž²àžàžžàžàžàž°àžàž³àžªàžŽàžàžàžŽà¹à¹àžà¹àž²àžàž¶àžàžàžµà¹àžàžàž"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> àžàž³àž¥àž±àžàžàžàžªàžŽàžàžàžŽà¹à¹àžàžàž²àž¡àžàžàž <xliff:g id="DEVICE_NAME">%2$s</xliff:g> à¹àžàž·à¹àžàžªàžàž£àžµàž¡à¹àžàžà¹àž¥àž°àžàžµà¹àžàžàž£à¹àžàž·à¹àžà¹ àžàžàžàž£àž°àžàžà¹àžàž¢àž±àžàžàžžàžàžàž£àžà¹àžàžµà¹àžàž¢àž¹à¹à¹àžàž¥à¹à¹àžàžµàž¢àž"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"àžàžžàžàžàž£àžà¹"</string>
<string name="summary_generic" msgid="1761976003668044801">"à¹àžàžàžàžµà¹àžàž°àžªàž²àž¡àž²àž£àžàžàžŽàžàžà¹àžà¹àžàž¡àž¹àž¥ à¹àžà¹àž àžàž·à¹àžàžàžàžàžàžžàžàžàž¥àžàžµà¹à¹àžàž£à¹àžà¹àž²àž¡àž² àž£àž°àž«àž§à¹àž²àžà¹àžàž£àžšàž±àžàžà¹àžàžàžàžàžžàžà¹àž¥àž°àžàžžàžàžàž£àžà¹àžàžµà¹à¹àž¥àž·àžàžà¹àž§à¹à¹àžà¹"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index d5c51e8..3efc299 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"Cihaz"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Bu uygulamanın <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda Åu izinlere eriÅmesine izin verilecek:"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere eriÅmesine izin verin"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adlı uygulamanın telefonunuzdaki uygulamaları aktarmasına izin verilsin mi?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s; ses, fotoÄraflar, Åifreler ve mesajlar da dahil olmak üzere telefonda görünen veya oynatılan her Åeye eriÅebilecek.<br/><br/>%1$s siz bu iznin eriÅimini kaldırana kadar uygulamaları aktarabilecek."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akıÅı gerçekleÅtirmek için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulamaları göstermek ve aktarmak için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere eriÅmesine izin verin"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Hizmetleri"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoÄraf, medya ve bildirimlere eriÅmek için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazının bu iÅlemi yapmasına izin verilsin mi?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> adlı uygulamanın telefonunuzdaki uygulamaları ve sistem özelliklerini aktarmasına izin verilsin mi?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s; ses, fotoÄraflar, ödeme bilgileri, Åifreler ve mesajlar da dahil olmak üzere telefonunuzda görünen veya oynatılan her Åeye eriÅebilecek.<br/><br/>%1$s siz bu iznin eriÅimini kaldırana kadar uygulamaları ve diÄer sistem özelliklerini aktarabilecek."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına uygulamaları ve diÄer sistem özelliklerini yakındaki cihazlara aktarmak için izin istiyor"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="1761976003668044801">"Bu uygulama, arayan kiÅinin adı gibi bilgileri telefonunuz ve seçili cihaz arasında senkronize edebilir"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 97a3dbc..745e4f7 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"пÑОÑÑÑÑй"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Њей ЎПЎаÑПк ЌаÑОЌе ЎПÑÑÑп ЎП пеÑелÑÑеМОÑ
МОжÑе ЎПзвПлÑв Ма ваÑÐŸÐŒÑ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"ÐаЎайÑе ЎПЎаÑÐºÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ЎПÑÑÑп ЎП ÑÑÑÑ ÑМÑПÑЌаÑÑÑ Ð· ÑелеÑПМа"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ÐПзвПлОÑО ЎПЎаÑÐºÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ÑÑаМÑлÑваÑО ЎПЎаÑкО ÑелеÑПМа?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ЌаÑОЌе ЎПÑÑÑп ЎП кПМÑеМÑÑ, ÑП вÑЎПбÑажаÑÑÑÑÑ ÑО вÑÐŽÑвПÑÑÑÑÑÑÑ ÐœÐ° ÑелеÑПМÑ, зПкÑеЌа ЎП аÑÐŽÑП, ÑПÑП, паÑПлÑв Ñ Ð¿ÐŸÐ²ÑЎПЌлеМÑ.<br/><br/>%1$s зЌПже ÑÑаМÑлÑваÑО ЎПЎаÑкО, пПкО вО Ме ÑкаÑÑÑÑе Ñей ЎПзвÑл."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"СеÑвÑÑО ÐŽÐ»Ñ ÐºÑлÑкПÑ
пÑОÑÑÑПÑв"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ÐПЎаÑПк <xliff:g id="APP_NAME">%1$s</xliff:g> вÑÐŽ ÑÐŒÐµÐœÑ Ð²Ð°ÑПгП пÑОÑÑÑÐŸÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" запОÑÑÑ ÐŽÐŸÐ·Ð²Ñл Ма ÑÑаМÑлÑÑÑÑ ÐŽÐŸÐŽÐ°ÑкÑв ÐŒÑж ваÑОЌО пÑОÑÑÑПÑЌО"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ÐПЎаÑПк <xliff:g id="APP_NAME">%1$s</xliff:g> вÑÐŽ ÑÐŒÐµÐœÑ Ð²Ð°ÑПгП пÑОÑÑÑÐŸÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" запОÑÑÑ ÐŽÐŸÐ·Ð²Ñл Ма вÑЎПбÑÐ°Ð¶ÐµÐœÐœÑ Ð¹ ÑÑаМÑлÑÐ²Ð°ÐœÐœÑ ÐŽÐŸÐŽÐ°ÑкÑв Ма ваÑОÑ
пÑОÑÑÑПÑÑ
"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"ÐаЎайÑе пÑОÑÑÑÐŸÑ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ЎПÑÑÑп ЎП ÑÑÑÑ ÑМÑПÑЌаÑÑÑ Ð· ÑелеÑПМа"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"СеÑвÑÑО Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ÐПЎаÑПк <xliff:g id="APP_NAME">%1$s</xliff:g> вÑÐŽ ÑÐŒÐµÐœÑ Ð²Ð°ÑПгП пÑОÑÑÑÐŸÑ \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" запОÑÑÑ ÐŽÐŸÐ·Ð²Ñл Ма ЎПÑÑÑп ЎП ÑПÑПгÑаÑÑй, ЌеЎÑаÑайлÑв Ñ ÑпПвÑÑÐµÐœÑ Ð²Ð°ÑПгП ÑелеÑПМа"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"ÐПзвПлОÑО ЎПЎаÑÐºÑ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> вОкПМÑваÑО ÑÑ ÐŽÑÑ?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ÐПзвПлОÑО пÑОÑÑÑÐŸÑ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ÑÑаМÑлÑваÑО ЎПЎаÑкО й ÑОÑÑÐµÐŒÐœÑ ÑÑМкÑÑÑ ÑелеÑПМа?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ЌаÑОЌе ЎПÑÑÑп ЎП кПМÑеМÑÑ, ÑП вÑЎПбÑажаÑÑÑÑÑ ÑО вÑÐŽÑвПÑÑÑÑÑÑÑ ÐœÐ° ÑелеÑПМÑ, зПкÑеЌа ЎП аÑÐŽÑП, ÑПÑП, плаÑÑÐ¶ÐœÐŸÑ ÑМÑПÑЌаÑÑÑ, паÑПлÑв Ñ Ð¿ÐŸÐ²ÑЎПЌлеМÑ.<br/><br/>%1$s зЌПже ÑÑаМÑлÑваÑО ЎПЎаÑкО й ÑОÑÑÐµÐŒÐœÑ ÑÑМкÑÑÑ, пПкО вО Ме ÑкаÑÑÑÑе Ñей ЎПзвÑл."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ÐПЎаÑПк <xliff:g id="APP_NAME">%1$s</xliff:g> вÑÐŽ ÑÐŒÐµÐœÑ Ð²Ð°ÑПгП пÑОÑÑÑÐŸÑ (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) запОÑÑÑ ÐŽÐŸÐ·Ð²Ñл Ма ÑÑаМÑлÑÑÑÑ ÐŽÐŸÐŽÐ°ÑкÑв Ñа ÑМÑОÑ
ÑОÑÑеЌМОÑ
ÑÑМкÑÑй Ма пÑОÑÑÑÐŸÑ Ð¿ÐŸÐ±Ð»ÐžÐ·Ñ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"пÑОÑÑÑÑй"</string>
<string name="summary_generic" msgid="1761976003668044801">"Њей ЎПЎаÑПк зЌПже ÑОМÑ
ÑПМÑзÑваÑО ÑМÑПÑЌаÑÑÑ (МапÑОклаЎ, ÑÐŒ’Ñ Ð°Ð±ÐŸÐœÐµÐœÑа, ÑкОй вОклОкаÑ) ÐŒÑж ÑелеÑПМПЌ Ñ Ð²ÐžÐ±ÑаМОЌ пÑОÑÑÑПÑÐŒ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 52826b3..109a011 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"Ø¢ÙÛ"</string>
<string name="summary_glasses" msgid="2872254734959842579">"اس اÛÙŸ ک٠آٟ Ú©Û <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ٟر ا٠اجازتÙÚº تک Ø±Ø³Ø§ØŠÛ Ú©Û Ø§Ø¬Ø§Ø²Øª ÛÙÚ¯Û"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"اٟÙÛ ÙÙÙ Ø³Û Ø§Ù Ù
عÙÙÙ
ات تک Ø±Ø³Ø§ØŠÛ ØØ§ØµÙ کرÙÛ Ú©Û <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ک٠اجازت دÛÚº"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"اجازت دÛÚº<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اٟÙÛ ÙÙÙ Ú©Û Ø§Ûٟس Ú©Ù Ø³ÙØ³ÙÛ ØšÙØ¯Û کرÙÛ Ú©Û ÙÛÛØ"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s Ú©Ù ÙÙ٠ٟر Ø¯Ú©ÚŸØ§ØŠÛ Ø¯ÛÙÛ ÙØ§ÙÛ ÛØ§ ÚÙØ§ØŠÛ جاÙÛ ÙØ§ÙÛ Ú©Ø³Û ØšÚŸÛ ÚÛØ² تک Ø±Ø³Ø§ØŠÛ ØØ§ØµÙ ÛÙÚ¯ÛØ ؚ؎Ù
Ù٠آÚÛÙØ تصاÙÛØ±Ø ٟاس ÙØ±Úز Ø§ÙØ± ÙŸÛØºØ§Ù
اتÛ<br/><br/>%1$s اس ÙÙØª تک اÛٟس ک٠اسٹرÛÙ
کر Ø³Ú©Û Ú¯ÛØ¯ جؚ تک آٟ اس اجازت تک Ø±Ø³Ø§ØŠÛ Ú©Ù Ûٹا Ø¯ÛØªÛ ÛÛÚºÛ"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ÚÛÙØ§ØŠØ³ Ø³Ø±ÙØ³Ø²"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> اÛÙŸ آٟ Ú©Û <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Ú©Û Ø¬Ø§ÙØš Ø³Û Ø¢ÙŸ Ú©Û Ø¢ÙØ§Øª Ú©Û Ø¯Ø±Ù
ÛØ§Ù اÛٟس Ú©Û Ø³ÙØ³ÙÛ ØšÙØ¯Û کرÙÛ Ú©Û Ø§Ø¬Ø§Ø²Øª Ú©Û Ø¯Ø±Ø®ÙØ§Ø³Øª کر رÛÛ ÛÛ"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> آٟ Ú©Û <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Ú©Û Ø¬Ø§ÙØš Ø³Û Ø¢ÙŸ Ú©Û Ø¢ÙØ§Øª Ú©Û Ø¯Ø±Ù
ÛØ§Ù اÛٟس Ú©Ù ÚØ³ÙŸÙÛ Ø§ÙØ± اسٹرÛÙ
کرÙÛ Ú©Û ÙÛÛ Ø§Ø¬Ø§Ø²Øª Ú©Û Ø¯Ø±Ø®ÙØ§Ø³Øª کر رÛÛ ÛÛ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"اٟÙÛ ÙÙÙ Ø³Û Ø§Ø³ Ù
عÙÙÙ
ات تک Ø±Ø³Ø§ØŠÛ ØØ§ØµÙ کرÙÛ Ú©Û <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ک٠اجازت دÛÚº"</string>
@@ -41,8 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play Ø³Ø±ÙØ³Ø²"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> اÛÙŸ آٟ Ú©Û <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Ú©Û Ø¬Ø§ÙØš Ø³Û Ø¢ÙŸ Ú©Û ÙÙÙ Ú©Û ØªØµØ§ÙÛØ±Ø Ù
ÛÚÛØ§ Ø§ÙØ± Ø§Ø·ÙØ§Ø¹Ø§Øª تک Ø±Ø³Ø§ØŠÛ Ú©Û Ø§Ø¬Ø§Ø²Øª Ú©Û Ø¯Ø±Ø®ÙØ§Ø³Øª کر رÛÛ ÛÛ"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> Ú©Ù ÛÛ Ú©Ø§Ø±Ø±ÙØ§ØŠÛ Ø§ÙØ¬Ø§Ù
دÛÙÛ Ú©Û Ø§Ø¬Ø§Ø²Øª دÛÚºØ"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"اجازت دÛÚº <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> اٟÙÛ ÙÙÙ Ú©Û Ø§Ûٟس Ø§ÙØ± سسٹÙ
Ú©Û Ø®ØµÙØµÛات Ú©Ù Ø³ÙØ³ÙÛ ØšÙØ¯Û کرÙÛ Ú©Û ÙÛÛØ"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
<skip />
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> آٟ Ú©Û <xliff:g id="DEVICE_NAME">%2$s</xliff:g> Ú©Û Ø¬Ø§ÙØš Ø³Û Ø§Ûٟس Ø§ÙØ± سسٹÙ
Ú©Û Ø¯Ûگر Ø®ØµÙØµÛات Ú©Û Ø³ÙØ³ÙÛ ØšÙØ¯Û ÙØ±ÛØšÛ Ø¢ÙØ§Øª ٟر کرÙÛ Ú©Û Ø§Ø¬Ø§Ø²Øª Ø·ÙØš کر رÛÛ ÛÛ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index b2c81e1..80cd92c 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"qurilma"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasida quyidagi ruxsatlarni oladi"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maÊŒlumot uchun ruxsat bering"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> telefondagi ilovalarni striming qilishiga ruxsat berasizmi?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s telefonda koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, parollar va xabarlarga kirish huquqini oladi.<br/><br/>Bu ruxsatni olib tashlamaguningizcha, %1$s ilovalarni striming qila oladi."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"Qurilamalararo ilovalar strimingi uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nomidan ilovalarni koʻrsatish va striming qilishga ruxsat soʻramoqda"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maÊŒlumot uchun ruxsat bering"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Telefoningizdagi rasm, media va bildirishnomalarga kirish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ilovasiga bu amalni bajarish uchun ruxsat berilsinmi?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> telefondagi ilovalar va tizim funksiyalarini striming qilishiga ruxsat berasizmi?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s telefonda koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, toʻlov axboroti, parollar va xabarlarga kirish huquqini oladi.<br/><br/>Bu ruxsatni olib tashlamaguningizcha, %1$s ilovalarni va tizim funksiyalarini striming qila oladi."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME">%2$s</xliff:g> qurilmangizdan nomidan atrofdagi qurilmalarga ilova va boshqa tizim funksiyalarini uzatish uchun ruxsat olmoqchi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
<string name="summary_generic" msgid="1761976003668044801">"Bu ilova telefoningiz va tanlangan qurilmada chaqiruvchining ismi kabi maÊŒlumotlarni sinxronlay oladi"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index ae6fc7f..ca3f5cc 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"thiết bá»"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Ớng dụng này sẜ ÄÆ°á»£c phép dùng những quyá»n sau trên <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cá»§a bạn"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cáºp vào thông tin này trên Äiá»n thoại cá»§a bạn"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truyá»n trá»±c tuyến các ứng dụng trên Äiá»n thoại cá»§a bạn?"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s sẜ có quyá»n truy cáºp vào má»i ná»i dung hiá»n thá» hoặc ÄÆ°á»£c phát trên Äiá»n thoại, bao gá»m âm thanh, hình ảnh, máºt khẩu và tin nhắn.<br/><br/>%1$s sẜ có thá» truyá»n trá»±c tuyến các ứng dụng cho Äến khi bạn ngừng cấp quyá»n này cho ứng dụng Äó."</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Dá»ch vụ trên nhiá»u thiết bá»"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> Äang yêu cầu quyá»n thay cho <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Äá» truyá»n trá»±c tuyến ứng dụng giữa các thiết bá» cá»§a bạn"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> Äang yêu cầu quyá»n thay mặt cho <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Äá» hiá»n thá» và truyá»n trá»±c tuyến các ứng dụng giữa các thiết bá» cá»§a bạn"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cáºp vào thông tin này trên Äiá»n thoại cá»§a bạn"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Dá»ch vụ Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> Äang yêu cầu quyá»n thay cho <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> Äá» truy cáºp vào ảnh, ná»i dung nghe nhìn và thông báo trên Äiá»n thoại cá»§a bạn"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Cho phép <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> thá»±c hiá»n hành Äá»ng này?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Cho phép <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> truyá»n trá»±c tuyến các ứng dụng và tính nÄng há» thá»ng trên Äiá»n thoại cá»§a bạn?"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s sẜ có quyá»n truy cáºp vào má»i ná»i dung hiá»n thá» hoặc ÄÆ°á»£c phát trên Äiá»n thoại, bao gá»m âm thanh, hình ảnh, thông tin thanh toán, máºt khẩu và tin nhắn.<br/><br/>%1$s sẜ có thá» truyá»n trá»±c tuyến các ứng dụng và tính nÄng há» thá»ng cho Äến khi bạn ngừng cấp quyá»n này cho ứng dụng Äó."</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> Äang thay <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yêu cầu quyá»n truyá»n trá»±c tuyến ứng dụng và các tính nÄng khác cá»§a há» thá»ng Äến các thiết bá» á» gần"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"thiết bá»"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ớng dụng này sẜ Äá»ng bá» hoá thông tin (ví dụ: tên ngưá»i gá»i) giữa Äiá»n thoại cá»§a bạn và thiết bá» bạn chá»n"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 8bc8287..750ff0d 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"讟å€"</string>
<string name="summary_glasses" msgid="2872254734959842579">"该åºçšå°å¯ä»¥è·åŸæš<xliff:g id="DEVICE_NAME">%1$s</xliff:g>äžçä»¥äžæé"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"å
讞“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>è®¿é®æšææºäžçè¿é¡¹ä¿¡æ¯"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"å
讞 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> æµåŒäŒ èŸææºçåºçšïŒ"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"“%1$s”å°èœå€è®¿é®ææºäžå¯è§æææŸçä»»äœå
容ïŒå
æ¬é³é¢ãç
§çãå¯ç åæ¶æ¯ã<br/><br/>“%1$s”å°èœå€æµåŒäŒ èŸåºçšïŒé€éæšæ€æ¶æ€è®¿é®æéã"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"è·šè®Ÿå€æå¡"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”æ£ä»£è¡šæšç<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请æ±åšæšç讟å€ä¹éŽæµåŒäŒ èŸåºçšå
容"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”æ£ä»£è¡šæšç<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请æ±åšè®Ÿå€ä¹éŽæŸç€ºåæµåŒäŒ èŸåºçš"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"å
讞 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> è®¿é®æšææºäžçè¿é¡¹ä¿¡æ¯"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play æå¡"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”æ£ä»£è¡šæšç<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请æ±è®¿é®æšææºäžçç
§çãåªäœå
容åéç¥"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"å
讞<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>è¿è¡æ€æäœïŒ"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"å
讞 <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> æµåŒäŒ èŸææºçåºçšåç³»ç»åèœïŒ"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"“%1$s”å°èœå€è®¿é®ææºäžå¯è§æææŸçä»»äœå
容ïŒå
æ¬é³é¢ãç
§çã仿¬Ÿä¿¡æ¯ãå¯ç åæ¶æ¯ã<br/><br/>“%1$s”å°èœå€æµåŒäŒ èŸåºçšåç³»ç»åèœïŒé€éæšæ€æ¶æ€è®¿é®æéã"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”æ£ä»£è¡šæšç<xliff:g id="DEVICE_NAME">%2$s</xliff:g>请æ±å°åºçšåå
¶ä»ç³»ç»åèœæµåŒäŒ èŸå°éè¿ç讟å€"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"讟å€"</string>
<string name="summary_generic" msgid="1761976003668044801">"æ€åºçšå°èœåšæšçææºåæé讟å€ä¹éŽåæ¥ä¿¡æ¯ïŒäŸåŠæ¥çµè
çå§å"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index a085893..ad9b4a2 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"è£çœ®"</string>
<string name="summary_glasses" msgid="2872254734959842579">"æ€æçšçšåŒå°å¯åš<xliff:g id="DEVICE_NAME">%1$s</xliff:g>äžååŸä»¥äžæ¬é"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"å
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ã<strong></strong>ååäœ ææ©äžçéé
è³æ"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"èŠå
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãäž²æµææ©æçšçšåŒå
§å®¹åïŒ"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"%1$s å°èœååææ©äžé¡¯ç€ºæææŸçä»»äœå
§å®¹ïŒå
æ¬é³èšãçžçãå¯ç¢Œåèšæ¯ã<br/><br/>%1$s å°èœäž²æµæçšçšåŒå
§å®¹ïŒçŽè³äœ ç§»é€æ€å忬éçºæ¢ã"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"è·šè£çœ®æå"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡š <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±æ¬éïŒä»¥äŸ¿åšè£çœ®éäž²æµæçšçšåŒçå
§å®¹"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡š <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±æ¬éïŒä»¥äŸ¿åšè£çœ®é顯瀺åäž²æµæçšçšåŒçå
§å®¹"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"å
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ã<strong></strong>ååäœ ææ©äžçéé
è³æ"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play æå"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡š <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±æ¬éïŒä»¥äŸ¿ååææ©äžççžçãåªé«åéç¥"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"èŠå
èš±ã<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ã<strong></strong>å·è¡æ€æäœåïŒ"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"èŠå
èš±ã<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ãäž²æµææ©æçšçšåŒå
§å®¹å系統åèœåïŒ"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s å°èœååææ©äžé¡¯ç€ºæææŸçä»»äœå
§å®¹ïŒå
æ¬é³èšãçžçã仿¬Ÿè³æãå¯ç¢Œåèšæ¯ã<br/><br/>%1$s å°èœäž²æµæçšçšåŒå
§å®¹å系統åèœïŒçŽè³äœ ç§»é€æ€å忬éçºæ¢ã"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡šã<xliff:g id="DEVICE_NAME">%2$s</xliff:g>ãèŠæ±æ¬éïŒæèœåšéè¿çè£çœ®äžäž²æµææŸæçšçšåŒåå
¶ä»ç³»çµ±åèœ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"è£çœ®"</string>
<string name="summary_generic" msgid="1761976003668044801">"æ€æçšçšåŒå°å¯åæ¥ææ©åæéžè£çœ®çè³èšïŒäŸåŠäŸé»è
çåçš±"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index a93034f..a5817c4 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -26,14 +26,11 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"è£çœ®"</string>
<string name="summary_glasses" msgid="2872254734959842579">"éåæçšçšåŒå°å¯ååŸ<xliff:g id="DEVICE_NAME">%1$s</xliff:g>äžçéäºæ¬é"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"å
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ã<strong></strong>ååææ©äžçéé
è³èš"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
- <!-- no translation found for summary_app_streaming (295548145144086753) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"èŠå
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ã<strong></strong>äž²æµå³èŒžææ©çæçšçšåŒåïŒ"</string>
+ <string name="summary_app_streaming" msgid="295548145144086753">"ã%1$sãå°å¯ååææ©é¡¯ç€ºæææŸçææå
§å®¹ïŒå
æ¬é³èšãçžçãå¯ç¢Œåèšæ¯ã<br/><br/>ã%1$sãå°å¯äž²æµå³èŒžæçšçšåŒïŒçŽå°äœ ç§»é€é忬éçºæ¢ã"</string>
<string name="helper_title_app_streaming" msgid="4151687003439969765">"è·šè£çœ®æå"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"çºäºåšè£çœ®éäž²æµå³èŒžæçšçšåŒå
§å®¹ïŒã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡š <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±çžéæ¬é"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡šäœ ç <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±å¿
èŠæ¬éïŒä»¥äŸ¿åšè£çœ®é顯瀺åäž²æµå³èŒžæçšçšåŒ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"å
èš±ã<xliff:g id="APP_NAME">%1$s</xliff:g>ã<strong></strong>ååäœ ææ©äžçéé
è³èš"</string>
@@ -41,10 +38,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Google Play æå"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"çºäºååææ©äžççžçãåªé«åéç¥ïŒã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡š <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> èŠæ±çžéæ¬é"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"èŠå
èš±ã<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ã<strong></strong>å·è¡éé
æäœåïŒ"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
- <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"èŠå
èš±ã<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ã<strong></strong>äž²æµå³èŒžææ©çæçšçšåŒååå系統åèœåïŒ"</string>
+ <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"ã%1$sãå°å¯ååææ©é¡¯ç€ºæææŸçææå
§å®¹ïŒå
æ¬é³èšãçžçã仿¬Ÿè³èšãå¯ç¢Œåèšæ¯ã<br/><br/>ã%1$sãå°å¯äž²æµå³èŒžæçšçšåŒååå系統åèœïŒçŽå°äœ ç§»é€é忬éçºæ¢ã"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãæ£åšä»£è¡šã<xliff:g id="DEVICE_NAME">%2$s</xliff:g>ãèŠæ±å¿
èŠæ¬éïŒæèœåšé°è¿è£çœ®äžäž²æµææŸæçšçšåŒåå
¶ä»ç³»çµ±åèœ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"è£çœ®"</string>
<string name="summary_generic" msgid="1761976003668044801">"éåæçšçšåŒå°å¯åšææ©åæå®è£çœ®é忥è³èšïŒäŸåŠäŸé»è
åçš±"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index ddda3e3..4b00dcb 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -26,14 +26,13 @@
<string name="profile_name_glasses" msgid="3506504967216601277">"idivayisi"</string>
<string name="summary_glasses" msgid="2872254734959842579">"Le-app izovunyelwa ukufinyelela lezi zimvume ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho"</string>
<string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifinyelele lolu lwazi kusukela efonini yakho"</string>
- <!-- no translation found for title_app_streaming_with_mirroring (3364582597581570658) -->
- <skip />
+ <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukusakaza ama-app efoni yakho?"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for summary_app_streaming (295548145144086753) -->
<skip />
<string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
<string name="helper_summary_app_streaming" msgid="2396773196949578425">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string>
- <!-- no translation found for helper_summary_app_streaming_with_mirroring (6138581029144467467) -->
- <skip />
+ <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yakho yokubonisa nokusakaza ama-app phakathi kwamadivayisi wakho"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela lolu lwazi kusuka efonini yakho"</string>
@@ -41,8 +40,8 @@
<string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DISPLAY_NAME">%2$s</xliff:g> yakho ukuze ifinyelele izithombe zefoni yakho, imidiya nezaziso"</string>
<string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vumela i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ukwenza lesi senzo?"</string>
- <!-- no translation found for title_nearby_device_streaming_with_mirroring (242855799919611657) -->
- <skip />
+ <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Vumela i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ukuze usakaze ama-app wefoni yakho nezakhi zesistimu?"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->
<skip />
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukusakaza ama-app nezinye izakhi zesistimu kumadivayisi aseduze"</string>
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
index 572a669..8627eac 100644
--- a/packages/CrashRecovery/aconfig/flags.aconfig
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -10,6 +10,7 @@
flag {
name: "enable_crashrecovery"
+ is_exported: true
namespace: "crashrecovery"
description: "Enables various dependencies of crashrecovery module"
bug: "289203818"
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index 37b5d40..a8d8f9a 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.net.ConnectivityModuleConnector;
import android.os.Environment;
import android.os.Handler;
@@ -57,16 +58,20 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -130,8 +135,25 @@
@VisibleForTesting
static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
- @VisibleForTesting
+
static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+ // Boot loop at which packageWatchdog starts first mitigation
+ private static final String BOOT_LOOP_THRESHOLD =
+ "persist.device_config.configuration.boot_loop_threshold";
+ @VisibleForTesting
+ static final int DEFAULT_BOOT_LOOP_THRESHOLD = 15;
+ // Once boot_loop_threshold is surpassed next mitigation would be triggered after
+ // specified number of reboots.
+ private static final String BOOT_LOOP_MITIGATION_INCREMENT =
+ "persist.device_config.configuration..boot_loop_mitigation_increment";
+ @VisibleForTesting
+ static final int DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT = 2;
+
+ // Threshold level at which or above user might experience significant disruption.
+ private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+ "persist.device_config.configuration.major_user_impact_level_threshold";
+ private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
private long mNumberOfNativeCrashPollsRemaining;
@@ -145,6 +167,7 @@
private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
+ private static final String ATTR_MITIGATION_COUNT = "mitigation-count";
// A file containing information about the current mitigation count in the case of a boot loop.
// This allows boot loop information to persist in the case of an fs-checkpoint being
@@ -230,8 +253,16 @@
mConnectivityModuleConnector = connectivityModuleConnector;
mSystemClock = clock;
mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
- mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
+ if (Flags.recoverabilityDetection()) {
+ mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ SystemProperties.getInt(BOOT_LOOP_MITIGATION_INCREMENT,
+ DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
+ }
+
loadFromFile();
sPackageWatchdog = this;
}
@@ -436,8 +467,13 @@
mitigationCount =
currentMonitoredPackage.getMitigationCountLocked();
}
- currentObserverToNotify.execute(versionedPackage,
- failureReason, mitigationCount);
+ if (Flags.recoverabilityDetection()) {
+ maybeExecute(currentObserverToNotify, versionedPackage,
+ failureReason, currentObserverImpact, mitigationCount);
+ } else {
+ currentObserverToNotify.execute(versionedPackage,
+ failureReason, mitigationCount);
+ }
}
}
}
@@ -467,37 +503,76 @@
}
}
if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(failingPackage, failureReason, 1);
+ if (Flags.recoverabilityDetection()) {
+ maybeExecute(currentObserverToNotify, failingPackage, failureReason,
+ currentObserverImpact, /*mitigationCount=*/ 1);
+ } else {
+ currentObserverToNotify.execute(failingPackage, failureReason, 1);
+ }
}
}
+ private void maybeExecute(PackageHealthObserver currentObserverToNotify,
+ VersionedPackage versionedPackage,
+ @FailureReasons int failureReason,
+ int currentObserverImpact,
+ int mitigationCount) {
+ if (currentObserverImpact < getUserImpactLevelLimit()) {
+ currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
+ }
+ }
+
+
/**
* Called when the system server boots. If the system server is detected to be in a boot loop,
* query each observer and perform the mitigation action with the lowest user impact.
*/
+ @SuppressWarnings("GuardedBy")
public void noteBoot() {
synchronized (mLock) {
- if (mBootThreshold.incrementAndTest()) {
- mBootThreshold.reset();
+ boolean mitigate = mBootThreshold.incrementAndTest();
+ if (mitigate) {
+ if (!Flags.recoverabilityDetection()) {
+ mBootThreshold.reset();
+ }
int mitigationCount = mBootThreshold.getMitigationCount() + 1;
PackageHealthObserver currentObserverToNotify = null;
+ ObserverInternal currentObserverInternal = null;
int currentObserverImpact = Integer.MAX_VALUE;
for (int i = 0; i < mAllObservers.size(); i++) {
final ObserverInternal observer = mAllObservers.valueAt(i);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
- int impact = registeredObserver.onBootLoop(mitigationCount);
+ int impact = Flags.recoverabilityDetection()
+ ? registeredObserver.onBootLoop(
+ observer.getBootMitigationCount() + 1)
+ : registeredObserver.onBootLoop(mitigationCount);
if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
+ currentObserverInternal = observer;
currentObserverImpact = impact;
}
}
}
if (currentObserverToNotify != null) {
- mBootThreshold.setMitigationCount(mitigationCount);
- mBootThreshold.saveMitigationCountToMetadata();
- currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
+ if (Flags.recoverabilityDetection()) {
+ if (currentObserverImpact < getUserImpactLevelLimit()
+ || (currentObserverImpact >= getUserImpactLevelLimit()
+ && mBootThreshold.getCount() >= getBootLoopThreshold())) {
+ int currentObserverMitigationCount =
+ currentObserverInternal.getBootMitigationCount() + 1;
+ currentObserverInternal.setBootMitigationCount(
+ currentObserverMitigationCount);
+ saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
+ currentObserverToNotify.executeBootLoopMitigation(
+ currentObserverMitigationCount);
+ }
+ } else {
+ mBootThreshold.setMitigationCount(mitigationCount);
+ mBootThreshold.saveMitigationCountToMetadata();
+ currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
+ }
}
}
}
@@ -567,13 +642,27 @@
mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
}
+ private int getUserImpactLevelLimit() {
+ return SystemProperties.getInt(MAJOR_USER_IMPACT_LEVEL_THRESHOLD,
+ DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD);
+ }
+
+ private int getBootLoopThreshold() {
+ return SystemProperties.getInt(BOOT_LOOP_THRESHOLD,
+ DEFAULT_BOOT_LOOP_THRESHOLD);
+ }
+
/** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
@Retention(SOURCE)
@IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_10,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_50,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_71,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_75,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_90,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_100})
public @interface PackageHealthObserverImpact {
@@ -582,11 +671,15 @@
/* Action has low user impact, user of a device will barely notice. */
int USER_IMPACT_LEVEL_10 = 10;
/* Actions having medium user impact, user of a device will likely notice. */
+ int USER_IMPACT_LEVEL_20 = 20;
int USER_IMPACT_LEVEL_30 = 30;
int USER_IMPACT_LEVEL_50 = 50;
int USER_IMPACT_LEVEL_70 = 70;
- int USER_IMPACT_LEVEL_90 = 90;
/* Action has high user impact, a last resort, user of a device will be very frustrated. */
+ int USER_IMPACT_LEVEL_71 = 71;
+ int USER_IMPACT_LEVEL_75 = 75;
+ int USER_IMPACT_LEVEL_80 = 80;
+ int USER_IMPACT_LEVEL_90 = 90;
int USER_IMPACT_LEVEL_100 = 100;
}
@@ -1144,6 +1237,12 @@
}
}
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ void registerObserverInternal(ObserverInternal observerInternal) {
+ mAllObservers.put(observerInternal.name, observerInternal);
+ }
+
/**
* Represents an observer monitoring a set of packages along with the failure thresholds for
* each package.
@@ -1151,17 +1250,23 @@
* <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
* instances of this class.
*/
- private static class ObserverInternal {
+ static class ObserverInternal {
public final String name;
@GuardedBy("mLock")
private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
@Nullable
@GuardedBy("mLock")
public PackageHealthObserver registeredObserver;
+ private int mMitigationCount;
ObserverInternal(String name, List<MonitoredPackage> packages) {
+ this(name, packages, /*mitigationCount=*/ 0);
+ }
+
+ ObserverInternal(String name, List<MonitoredPackage> packages, int mitigationCount) {
this.name = name;
updatePackagesLocked(packages);
+ this.mMitigationCount = mitigationCount;
}
/**
@@ -1173,6 +1278,9 @@
try {
out.startTag(null, TAG_OBSERVER);
out.attribute(null, ATTR_NAME, name);
+ if (Flags.recoverabilityDetection()) {
+ out.attributeInt(null, ATTR_MITIGATION_COUNT, mMitigationCount);
+ }
for (int i = 0; i < mPackages.size(); i++) {
MonitoredPackage p = mPackages.valueAt(i);
p.writeLocked(out);
@@ -1185,6 +1293,14 @@
}
}
+ public int getBootMitigationCount() {
+ return mMitigationCount;
+ }
+
+ public void setBootMitigationCount(int mitigationCount) {
+ mMitigationCount = mitigationCount;
+ }
+
@GuardedBy("mLock")
public void updatePackagesLocked(List<MonitoredPackage> packages) {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
@@ -1289,6 +1405,7 @@
**/
public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
String observerName = null;
+ int observerMitigationCount = 0;
if (TAG_OBSERVER.equals(parser.getName())) {
observerName = parser.getAttributeValue(null, ATTR_NAME);
if (TextUtils.isEmpty(observerName)) {
@@ -1299,6 +1416,9 @@
List<MonitoredPackage> packages = new ArrayList<>();
int innerDepth = parser.getDepth();
try {
+ if (Flags.recoverabilityDetection()) {
+ observerMitigationCount = parser.getAttributeInt(null, ATTR_MITIGATION_COUNT);
+ }
while (XmlUtils.nextElementWithin(parser, innerDepth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
try {
@@ -1319,7 +1439,7 @@
if (packages.isEmpty()) {
return null;
}
- return new ObserverInternal(observerName, packages);
+ return new ObserverInternal(observerName, packages, observerMitigationCount);
}
/** Dumps information about this observer and the packages it watches. */
@@ -1679,6 +1799,27 @@
}
}
+ @GuardedBy("mLock")
+ @SuppressWarnings("GuardedBy")
+ void saveAllObserversBootMitigationCountToMetadata(String filePath) {
+ HashMap<String, Integer> bootMitigationCounts = new HashMap<>();
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ bootMitigationCounts.put(observer.name, observer.getBootMitigationCount());
+ }
+
+ try {
+ FileOutputStream fileStream = new FileOutputStream(new File(filePath));
+ ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
+ objectStream.writeObject(bootMitigationCounts);
+ objectStream.flush();
+ objectStream.close();
+ fileStream.close();
+ } catch (Exception e) {
+ Slog.i(TAG, "Could not save observers metadata to file: " + e);
+ }
+ }
+
/**
* Handles the thresholding logic for system server boots.
*/
@@ -1686,10 +1827,16 @@
private final int mBootTriggerCount;
private final long mTriggerWindow;
+ private final int mBootMitigationIncrement;
BootThreshold(int bootTriggerCount, long triggerWindow) {
+ this(bootTriggerCount, triggerWindow, /*bootMitigationIncrement=*/ 1);
+ }
+
+ BootThreshold(int bootTriggerCount, long triggerWindow, int bootMitigationIncrement) {
this.mBootTriggerCount = bootTriggerCount;
this.mTriggerWindow = triggerWindow;
+ this.mBootMitigationIncrement = bootMitigationIncrement;
}
public void reset() {
@@ -1761,8 +1908,13 @@
/** Increments the boot counter, and returns whether the device is bootlooping. */
+ @GuardedBy("mLock")
public boolean incrementAndTest() {
- readMitigationCountFromMetadataIfNecessary();
+ if (Flags.recoverabilityDetection()) {
+ readAllObserversBootMitigationCountIfNecessary(METADATA_FILE);
+ } else {
+ readMitigationCountFromMetadataIfNecessary();
+ }
final long now = mSystemClock.uptimeMillis();
if (now - getStart() < 0) {
Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
@@ -1770,8 +1922,12 @@
setMitigationStart(now);
}
if (now - getMitigationStart() > DEFAULT_DEESCALATION_WINDOW_MS) {
- setMitigationCount(0);
setMitigationStart(now);
+ if (Flags.recoverabilityDetection()) {
+ resetAllObserversBootMitigationCount();
+ } else {
+ setMitigationCount(0);
+ }
}
final long window = now - getStart();
if (window >= mTriggerWindow) {
@@ -1782,9 +1938,48 @@
int count = getCount() + 1;
setCount(count);
EventLogTags.writeRescueNote(Process.ROOT_UID, count, window);
+ if (Flags.recoverabilityDetection()) {
+ boolean mitigate = (count >= mBootTriggerCount)
+ && (count - mBootTriggerCount) % mBootMitigationIncrement == 0;
+ return mitigate;
+ }
return count >= mBootTriggerCount;
}
}
+ @GuardedBy("mLock")
+ private void resetAllObserversBootMitigationCount() {
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ observer.setBootMitigationCount(0);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @SuppressWarnings("GuardedBy")
+ void readAllObserversBootMitigationCountIfNecessary(String filePath) {
+ File metadataFile = new File(filePath);
+ if (metadataFile.exists()) {
+ try {
+ FileInputStream fileStream = new FileInputStream(metadataFile);
+ ObjectInputStream objectStream = new ObjectInputStream(fileStream);
+ HashMap<String, Integer> bootMitigationCounts =
+ (HashMap<String, Integer>) objectStream.readObject();
+ objectStream.close();
+ fileStream.close();
+
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ if (bootMitigationCounts.containsKey(observer.name)) {
+ observer.setBootMitigationCount(
+ bootMitigationCounts.get(observer.name));
+ }
+ }
+ } catch (Exception e) {
+ Slog.i(TAG, "Could not read observer metadata file: " + e);
+ }
+ }
+ }
+
}
}
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 7bdc1a0..7093ba4 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -20,6 +20,7 @@
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -27,6 +28,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.os.Build;
import android.os.Environment;
import android.os.PowerManager;
@@ -53,6 +55,8 @@
import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -89,6 +93,40 @@
@VisibleForTesting
static final int LEVEL_FACTORY_RESET = 5;
@VisibleForTesting
+ static final int RESCUE_LEVEL_NONE = 0;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET = 1;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET = 2;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_WARM_REBOOT = 3;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 4;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 5;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 6;
+ @VisibleForTesting
+ static final int RESCUE_LEVEL_FACTORY_RESET = 7;
+
+ @IntDef(prefix = { "RESCUE_LEVEL_" }, value = {
+ RESCUE_LEVEL_NONE,
+ RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET,
+ RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET,
+ RESCUE_LEVEL_WARM_REBOOT,
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+ RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+ RESCUE_LEVEL_FACTORY_RESET
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RescueLevels {}
+
+ @VisibleForTesting
+ static final String RESCUE_NON_REBOOT_LEVEL_LIMIT = "persist.sys.rescue_non_reboot_level_limit";
+ @VisibleForTesting
+ static final int DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT = RESCUE_LEVEL_WARM_REBOOT - 1;
+ @VisibleForTesting
static final String TAG = "RescueParty";
@VisibleForTesting
static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
@@ -347,11 +385,20 @@
}
private static int getMaxRescueLevel(boolean mayPerformReboot) {
- if (!mayPerformReboot
- || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
- return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ if (Flags.recoverabilityDetection()) {
+ if (!mayPerformReboot
+ || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return SystemProperties.getInt(RESCUE_NON_REBOOT_LEVEL_LIMIT,
+ DEFAULT_RESCUE_NON_REBOOT_LEVEL_LIMIT);
+ }
+ return RESCUE_LEVEL_FACTORY_RESET;
+ } else {
+ if (!mayPerformReboot
+ || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ }
+ return LEVEL_FACTORY_RESET;
}
- return LEVEL_FACTORY_RESET;
}
/**
@@ -379,6 +426,46 @@
}
}
+ /**
+ * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+ * When failedPackage is null then 1st and 2nd mitigation counts are redundant (scoped and
+ * all device config reset). Behaves as if one mitigation attempt was already done.
+ *
+ * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+ * @param mayPerformReboot whether or not a reboot and factory reset may be performed
+ * for the given failure.
+ * @param failedPackage in case of bootloop this is null.
+ * @return the rescue level for the n-th mitigation attempt.
+ */
+ private static @RescueLevels int getRescueLevel(int mitigationCount, boolean mayPerformReboot,
+ @Nullable VersionedPackage failedPackage) {
+ // Skipping RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET since it's not defined without a failed
+ // package.
+ if (failedPackage == null && mitigationCount > 0) {
+ mitigationCount += 1;
+ }
+ if (mitigationCount == 1) {
+ return RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET;
+ } else if (mitigationCount == 2) {
+ return RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET;
+ } else if (mitigationCount == 3) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT);
+ } else if (mitigationCount == 4) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+ } else if (mitigationCount == 5) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
+ } else if (mitigationCount == 6) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot),
+ RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
+ } else if (mitigationCount >= 7) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET);
+ } else {
+ return RESCUE_LEVEL_NONE;
+ }
+ }
+
private static void executeRescueLevel(Context context, @Nullable String failedPackage,
int level) {
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -397,6 +484,15 @@
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
+ if (Flags.recoverabilityDetection()) {
+ executeRescueLevelInternalNew(context, level, failedPackage);
+ } else {
+ executeRescueLevelInternalOld(context, level, failedPackage);
+ }
+ }
+
+ private static void executeRescueLevelInternalOld(Context context, int level, @Nullable
+ String failedPackage) throws Exception {
if (level <= LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS) {
// Disabling flag resets on master branch for trunk stable launch.
@@ -410,8 +506,6 @@
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
- Runnable runnable;
- Thread thread;
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
try {
@@ -453,21 +547,7 @@
}
break;
case LEVEL_WARM_REBOOT:
- // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
- // when device shutting down.
- setRebootProperty(true);
- runnable = () -> {
- try {
- PowerManager pm = context.getSystemService(PowerManager.class);
- if (pm != null) {
- pm.reboot(TAG);
- }
- } catch (Throwable t) {
- logRescueException(level, failedPackage, t);
- }
- };
- thread = new Thread(runnable);
- thread.start();
+ executeWarmReboot(context, level, failedPackage);
break;
case LEVEL_FACTORY_RESET:
// Before the completion of Reboot, if any crash happens then PackageWatchdog
@@ -475,23 +555,9 @@
// Adding a check to prevent factory reset to execute before above reboot completes.
// Note: this reboot property is not persistent resets after reboot is completed.
if (isRebootPropertySet()) {
- break;
+ return;
}
- setFactoryResetProperty(true);
- long now = System.currentTimeMillis();
- setLastFactoryResetTimeMs(now);
- runnable = new Runnable() {
- @Override
- public void run() {
- try {
- RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
- } catch (Throwable t) {
- logRescueException(level, failedPackage, t);
- }
- }
- };
- thread = new Thread(runnable);
- thread.start();
+ executeFactoryReset(context, level, failedPackage);
break;
}
@@ -500,6 +566,83 @@
}
}
+ private static void executeRescueLevelInternalNew(Context context, @RescueLevels int level,
+ @Nullable String failedPackage) throws Exception {
+ CrashRecoveryStatsLog.write(CrashRecoveryStatsLog.RESCUE_PARTY_RESET_REPORTED,
+ level, levelToString(level));
+ switch (level) {
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ // Temporary disable deviceConfig reset
+ // resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ break;
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ // Temporary disable deviceConfig reset
+ // resetDeviceConfig(context, /*isScoped=*/false, failedPackage);
+ break;
+ case RESCUE_LEVEL_WARM_REBOOT:
+ executeWarmReboot(context, level, failedPackage);
+ break;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, level);
+ break;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, level);
+ break;
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, level);
+ break;
+ case RESCUE_LEVEL_FACTORY_RESET:
+ // Before the completion of Reboot, if any crash happens then PackageWatchdog
+ // escalates to next level i.e. factory reset, as they happen in separate threads.
+ // Adding a check to prevent factory reset to execute before above reboot completes.
+ // Note: this reboot property is not persistent resets after reboot is completed.
+ if (isRebootPropertySet()) {
+ return;
+ }
+ executeFactoryReset(context, level, failedPackage);
+ break;
+ }
+ }
+
+ private static void executeWarmReboot(Context context, int level,
+ @Nullable String failedPackage) {
+ // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
+ // when device shutting down.
+ setRebootProperty(true);
+ Runnable runnable = () -> {
+ try {
+ PowerManager pm = context.getSystemService(PowerManager.class);
+ if (pm != null) {
+ pm.reboot(TAG);
+ }
+ } catch (Throwable t) {
+ logRescueException(level, failedPackage, t);
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+ private static void executeFactoryReset(Context context, int level,
+ @Nullable String failedPackage) {
+ setFactoryResetProperty(true);
+ long now = System.currentTimeMillis();
+ setLastFactoryResetTimeMs(now);
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+ } catch (Throwable t) {
+ logRescueException(level, failedPackage, t);
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+
private static String getCompleteMessage(Throwable t) {
final StringBuilder builder = new StringBuilder();
builder.append(t.getMessage());
@@ -521,17 +664,38 @@
}
private static int mapRescueLevelToUserImpact(int rescueLevel) {
- switch(rescueLevel) {
- case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
- case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- case LEVEL_WARM_REBOOT:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
- case LEVEL_FACTORY_RESET:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
- default:
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ if (Flags.recoverabilityDetection()) {
+ switch (rescueLevel) {
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_20;
+ case RESCUE_LEVEL_WARM_REBOOT:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_75;
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_80;
+ case RESCUE_LEVEL_FACTORY_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+ default:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ }
+ } else {
+ switch (rescueLevel) {
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10;
+ case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ case LEVEL_WARM_REBOOT:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ case LEVEL_FACTORY_RESET:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100;
+ default:
+ return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ }
}
}
@@ -548,7 +712,7 @@
final ContentResolver resolver = context.getContentResolver();
try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
- UserHandle.SYSTEM.getIdentifier());
+ UserHandle.SYSTEM.getIdentifier());
} catch (Exception e) {
res = new RuntimeException("Failed to reset global settings", e);
}
@@ -667,8 +831,13 @@
@FailureReasons int failureReason, int mitigationCount) {
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ if (Flags.recoverabilityDetection()) {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage), failedPackage));
+ } else {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
mayPerformReboot(failedPackage)));
+ }
} else {
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
@@ -682,8 +851,10 @@
}
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
- final int level = getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage));
+ final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage), failedPackage)
+ : getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage));
executeRescueLevel(mContext,
failedPackage == null ? null : failedPackage.getPackageName(), level);
return true;
@@ -716,7 +887,12 @@
if (isDisabled()) {
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
+ if (Flags.recoverabilityDetection()) {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ true, /*failedPackage=*/ null));
+ } else {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
+ }
}
@Override
@@ -725,8 +901,10 @@
return false;
}
boolean mayPerformReboot = !shouldThrottleReboot();
- executeRescueLevel(mContext, /*failedPackage=*/ null,
- getRescueLevel(mitigationCount, mayPerformReboot));
+ final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
+ mayPerformReboot, /*failedPackage=*/ null)
+ : getRescueLevel(mitigationCount, mayPerformReboot);
+ executeRescueLevel(mContext, /*failedPackage=*/ null, level);
return true;
}
@@ -843,14 +1021,44 @@
}
private static String levelToString(int level) {
- switch (level) {
- case LEVEL_NONE: return "NONE";
- case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
- case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
- case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
- case LEVEL_WARM_REBOOT: return "WARM_REBOOT";
- case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
- default: return Integer.toString(level);
+ if (Flags.recoverabilityDetection()) {
+ switch (level) {
+ case RESCUE_LEVEL_NONE:
+ return "NONE";
+ case RESCUE_LEVEL_SCOPED_DEVICE_CONFIG_RESET:
+ return "SCOPED_DEVICE_CONFIG_RESET";
+ case RESCUE_LEVEL_ALL_DEVICE_CONFIG_RESET:
+ return "ALL_DEVICE_CONFIG_RESET";
+ case RESCUE_LEVEL_WARM_REBOOT:
+ return "WARM_REBOOT";
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+ case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+ case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+ case RESCUE_LEVEL_FACTORY_RESET:
+ return "FACTORY_RESET";
+ default:
+ return Integer.toString(level);
+ }
+ } else {
+ switch (level) {
+ case LEVEL_NONE:
+ return "NONE";
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+ case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+ return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+ case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+ return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+ case LEVEL_WARM_REBOOT:
+ return "WARM_REBOOT";
+ case LEVEL_FACTORY_RESET:
+ return "FACTORY_RESET";
+ default:
+ return Integer.toString(level);
+ }
}
}
}
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 0fb9327..93f26ae 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -69,7 +69,7 @@
*
* @hide
*/
-final class RollbackPackageHealthObserver implements PackageHealthObserver {
+public final class RollbackPackageHealthObserver implements PackageHealthObserver {
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
@@ -89,7 +89,7 @@
private boolean mTwoPhaseRollbackEnabled;
@VisibleForTesting
- RollbackPackageHealthObserver(Context context, ApexManager apexManager) {
+ public RollbackPackageHealthObserver(Context context, ApexManager apexManager) {
mContext = context;
HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
handlerThread.start();
diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml
index a5ccdb6..7a8c25b 100644
--- a/packages/CredentialManager/AndroidManifest.xml
+++ b/packages/CredentialManager/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
<uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
+ <uses-permission android:name="android.permission.USE_BIOMETRIC" />
<application
android:allowBackup="true"
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 5d9295b..c12b685 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Wagwoorde sal steeds saam met toegangsleutels beskikbaar wees terwyl ons na ’n wagwoordlose toekoms beweeg."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Kies waar om jou <xliff:g id="CREATETYPES">%1$s</xliff:g> te stoor"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Kies ’n wagwoordbestuurder om jou inligting te stoor en volgende keer vinniger aan te meld"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Wil jy toegangsleutel skep om by <xliff:g id="APPNAME">%1$s</xliff:g> aan te meld?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Wil jy wagwoord stoor om by <xliff:g id="APPNAME">%1$s</xliff:g> aan te meld?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Stoor aanmeldinligting vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"toegangsleutel"</string>
<string name="password" msgid="6738570945182936667">"wagwoord"</string>
<string name="passkeys" msgid="5733880786866559847">"toegangsleutels"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Maak toe"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde toegangsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Gebruik jou gestoorde wagwoord vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Gebruik jou aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Ontsluit aanmeldingopsies vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Kies ’n gestoorde toegangsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 2e8021d..fac267a 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"áá° ášááá áá ášááá áá°ááµ áµáááµ ášááá áááµ ášááá áááᜠáá ááá ááááá¢"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ášá¥ááµáá <xliff:g id="CREATETYPES">%1$s</xliff:g> ášáµ á¥áá°áá«áµááá¡ ááášá¡"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"áášááá áááµááᥠá¥á á áá£á áá á áá¥ááµ á ááá« áááá£áµ ášááµá¥á ááá á áµá°á³á³áªá ááášá¡"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"áá° <xliff:g id="APPNAME">%1$s</xliff:g> áááá£áµ ášááá ááá ááá á?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"áá° <xliff:g id="APPNAME">%1$s</xliff:g> áááá£áµ ášááá áá áááá¥?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"á<xliff:g id="APPNAME">%1$s</xliff:g> ášááá¢á« áášá áááá¥?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ášááá ááá"</string>
<string name="password" msgid="6738570945182936667">"ášááá áá"</string>
<string name="passkeys" msgid="5733880786866559847">"ášááá ááááœ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"á á°áá¥áµ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ášá°ááá ášááá ááááá á<xliff:g id="APP_NAME">%1$s</xliff:g> áá áá?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"á<xliff:g id="APP_NAME">%1$s</xliff:g> ášá°ááá áá ášááá áááá áá áá?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"á<xliff:g id="APP_NAME">%1$s</xliff:g> ááá¢á«á á¥á
á áá ááá?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"á<xliff:g id="APP_NAME">%1$s</xliff:g> ášááá¢á« á áá«á®áœ áášáá±?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"á<xliff:g id="APP_NAME">%1$s</xliff:g> ášá°ááá ášááá ááá ááášá¡"</string>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index a2d328c..835eceb 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ØšÙÙÙ
ا ÙÙØ·ÙÙ ÙØÙ Ù
Ø³ØªÙØšÙ ؚدÙÙ ÙÙÙ
ات Ù
Ø±ÙØ±Ø ست؞٠ÙÙÙ
ات اÙÙ
Ø±ÙØ± Ù
تÙÙÙØ±Ø© Ø¥ÙÙ Ø¬Ø§ÙØš Ù
ÙØ§ØªÙØ Ø§ÙÙ
Ø±ÙØ±."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Ø§Ø®ØªÙØ§Ø± اÙÙ
ÙØ§Ù Ø§ÙØ°Ù ØªØ±ÙØ¯ ØÙØž <xliff:g id="CREATETYPES">%1$s</xliff:g> ÙÙÙ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Ø§Ø®ØªÙØ± Ù
Ø¯ÙØ± ÙÙÙ
ات Ù
Ø±ÙØ± ÙØÙØž Ù
عÙÙÙ
Ø§ØªÙ ÙØªØ³Ø¬ÙÙ Ø§ÙØ¯Ø®Ù٠ؚ؎Ù٠أسرع Ù٠اÙÙ
رة اÙÙØ§Ø¯Ù
Ø©."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ÙÙ ØªØ±ÙØ¯ Ø¥ÙØŽØ§Ø¡ Ù
ÙØªØ§Ø Ù
Ø±ÙØ± ÙØªØ³Ø¬ÙÙ Ø§ÙØ¯Ø®Ù٠إÙ٠تطؚÙÙ <xliff:g id="APPNAME">%1$s</xliff:g>Ø"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÙÙ ØªØ±ÙØ¯ ØÙØž ÙÙÙ
Ø© اÙÙ
Ø±ÙØ± ÙØªØ³Ø¬ÙÙ Ø§ÙØ¯Ø®Ù٠إÙ٠تطؚÙÙ <xliff:g id="APPNAME">%1$s</xliff:g>Ø"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ÙÙ ØªØ±ÙØ¯ ØÙØž Ù
عÙÙÙ
ات تسجÙÙ Ø§ÙØ¯Ø®ÙÙ ÙØªØ·ØšÙÙ \"<xliff:g id="APPNAME">%1$s</xliff:g>\"Ø"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"Ù
ÙØªØ§Ø اÙÙ
Ø±ÙØ±"</string>
<string name="password" msgid="6738570945182936667">"ÙÙÙ
Ø© اÙÙ
Ø±ÙØ±"</string>
<string name="passkeys" msgid="5733880786866559847">"Ù
ÙØ§ØªÙØ Ø§ÙÙ
Ø±ÙØ±"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Ø¥ØºÙØ§Ù"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ÙÙ ØªØ±ÙØ¯ استخداÙ
Ù
ÙØªØ§Ø اÙÙ
Ø±ÙØ± اÙÙ
ØÙÙØž ÙØªØ·ØšÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"Ø"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÙÙ ØªØ±ÙØ¯ استخداÙ
ÙÙÙ
Ø© اÙÙ
Ø±ÙØ± اÙÙ
ØÙÙØžØ© ÙØªØ·ØšÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"Ø"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ÙÙ ØªØ±ÙØ¯ استخداÙ
Ù
عÙÙÙ
ات تسجÙ٠دخÙÙÙ ÙØªØ·ØšÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"Ø"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"ÙÙ ØªØ±ÙØ¯ ÙØªØ اÙÙÙÙ ÙØ§Ø³ØªØ¹Ø§Ø¯Ø© Ø®ÙØ§Ø±Ø§Øª تسجÙÙ Ø§ÙØ¯Ø®ÙÙ ÙØªØ·ØšÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"Ø"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Ø§Ø®ØªÙØ§Ø± Ù
ÙØªØ§Ø Ù
Ø±ÙØ± Ù
ØÙÙØž ÙØªØ·ØšÙÙ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index 3efcea8..c65e734 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"àŠàŠ®àŠ¿ àŠªàŠŸàŠà§±à§°à§àŠ¡àŠ¬àŠ¿àŠ¹à§àŠš àŠà§±àŠ¿àŠ·à§àŠ¯àŠ€à§° àŠŠàŠ¿àŠ¶à§ àŠàŠàŠ¬àŠ¢àŠŒàŠŸà§° àŠ²àŠà§ àŠ²àŠà§ àŠªàŠŸàŠàŠà§à§° àŠ²àŠàŠ€à§ àŠªàŠŸàŠà§±à§°à§àŠ¡àŠžàŠ®à§àŠ¹à§ àŠàŠªàŠ²àŠ¬à§àЧ àŠ¹’àŠ¬à¥€"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"àŠàŠªà§àŠšàŠŸà§° <xliff:g id="CREATETYPES">%1$s</xliff:g> àŠ’àŠ€ àŠà§àŠ àŠà§°àŠ¿àŠ¬ àŠ²àŠŸàŠà§ àŠžà§àŠ¯àŠŒàŠŸ àŠ¬àŠŸàŠàŠšàŠ¿ àŠà§°àŠ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"àŠàŠªà§àŠšàŠŸà§° àŠ€àŠ¥à§àН àŠà§àŠ àŠà§°àŠ¿ àŠªà§°à§±à§°à§àŠ€à§ àŠžàŠ®àŠ¯àŠŒàŠ€ àŠŠà§à§°à§àŠ€àŠàŠŸà§±à§ àŠàŠŸàŠàŠš àŠàŠš àŠà§°àŠ¿àŠ¬àŠ²à§ àŠàŠàŠŸ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠªà§°àŠ¿àŠàŠŸàŠ²àŠ àŠ¬àŠŸàŠàŠšàŠ¿ àŠà§°àŠ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g>àŠ€ àŠàŠŸàŠàŠš àŠàŠš àŠà§°àŠ¿àŠ¬àŠ²à§ àŠªàŠŸàŠàŠà§ àŠžà§àŠ·à§àŠàŠ¿ àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g>àŠ€ àŠàŠŸàŠàŠš àŠàŠš àŠà§°àŠ¿àŠ¬àŠ²à§ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠà§àŠ àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠàŠŸàŠàŠš àŠàŠšà§° àŠ€àŠ¥à§àН àŠà§àŠ àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àŠªàŠŸàŠàŠà§"</string>
<string name="password" msgid="6738570945182936667">"àŠªàŠŸàŠà§±à§°à§àŠ¡"</string>
<string name="passkeys" msgid="5733880786866559847">"àŠªàŠŸàŠàŠà§"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àŠ
àŠà§à§°àŠŸàŠ¹à§àН àŠà§°àŠ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠàŠªà§àŠšàŠŸà§° àŠà§àŠ àŠ¹à§ àŠ¥àŠàŠŸ àŠªàŠŸàŠàŠà§ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠàŠªà§àŠšàŠŸà§° àŠà§àŠ àŠà§°àŠ¿ àŠ¥à§à§±àŠŸ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠàŠŸàŠàŠš àŠàŠš àŠà§°àŠ¿àŠ¬àŠ²à§ àŠàŠªà§àŠšàŠŸà§° àŠà§à§°àŠ¿àŠ¡à§àŠšàŠ¶à§àŠ¬àŠ¿àŠ¯àŠŒà§àв àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠàŠŸàŠàŠš àŠàŠšà§° àŠ¬àŠ¿àŠàвà§àŠªàŠžàŠ®à§àй àŠàŠšàŠ²àŠ àŠà§°àŠ¿àŠ¬àŠšà§?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g>à§° àŠ¬àŠŸàŠ¬à§ àŠà§àŠ àŠ¹à§ àŠ¥àŠàŠŸ àŠàŠàŠŸ àŠªàŠŸàŠàŠà§ àŠ¬àŠŸàŠàŠšàŠ¿ àŠà§°àŠ"</string>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index 627e2c0..7df31b8 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Parolsuz gÉlÉcÉyÉ doÄru irÉlilÉdikcÉ parollar hÉlÉ dÉ açarlar ilÉ yanaÅı Élçatan olacaq."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> elementinin saxlanacaÄı yeri seçin"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"MÉlumatlarınızı yadda saxlamaq vÉ növbÉti dÉfÉ daha sürÉtli daxil olmaq üçün parol meneceri seçin"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> tÉtbiqinÉ daxil olmaq üçün giriÅ açarı yaradılsın?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> tÉtbiqinÉ daxil olmaq üçün parol yadda saxlansın?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriÅ mÉlumatları yadda saxlansın?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"açar"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
<string name="passkeys" msgid="5733880786866559847">"açarlar"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"İmtina edin"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmıŠgiriÅ açarı istifadÉ edilsin?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmıŠparol istifadÉ edilsin?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün giriÅ istifadÉ edilsin?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün giriÅ seçimlÉri kiliddÉn çıxarılsın?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmıŠgiriÅ açarı seçin"</string>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index c4111e4..e1c92c3 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Kako se kreÄemo ka buduÄnosti bez lozinki, lozinke Äe i dalje biti dostupne uz pristupne kodove."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gde Äete saÄuvati: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Izaberite menadÅŸera lozinki da biste saÄuvali podatke i brÅŸe se prijavili sledeÄi put"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Åœelite da napravite pristupni kljuÄ da biste se prijavili u <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Åœelite da saÄuvate lozinku da biste se prijavili u <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Åœelite da saÄuvate podatke za prijavljivanje za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
<string name="passkeys" msgid="5733880786866559847">"pristupni kodovi"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Odbaci"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Åœelite da koristite saÄuvani pristupni kôd za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Åœelite da koristite saÄuvanu lozinku za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Åœelite li da koristite svoje podatke za prijavljivanje za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Åœelite da otkljuÄate opcije prijavljivanja za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Izaberite saÄuvan pristupni kljuÄ za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index f970d16..ef0c12d 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ХПÑÑ ÐŒÑ ÑжП ÑÑÑ
аеЌÑÑ Ñ Ð±ÐŸÐº бÑÐŽÑÑÑÐœÑ Ð±ÐµÐ· вÑкаÑÑÑÑÐ°ÐœÐœÑ Ð¿Ð°ÑПлÑÑ, ÑÐœÑ Ð¿Ð°-ÑаМейÑÐ°ÐŒÑ Ð·Ð°ÑÑаМÑÑÑа ЎаÑÑÑпМÑÐŒÑ ÐœÐ°ÑПÑÐœÑ Ð· клÑÑÐ°ÐŒÑ ÐŽÐŸÑÑÑпÑ."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÐÑбеÑÑÑе, кÑÐŽÑ Ð·Ð°Ñ
аваÑÑ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐÑбеÑÑÑе ÐŒÐµÐœÐµÐŽÐ¶Ð°Ñ Ð¿Ð°ÑПлÑÑ, каб заÑ
аваÑÑ Ñвае ЎаМÑÑ Ñ Ð·Ð°Ð±ÑÑпеÑÑÑÑ Ñ
ÑÑÐºÑ ÑваÑ
ПЎ Ñ ÐœÐ°ÑÑÑпМÑÑ ÑазÑ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"СÑваÑÑÑÑ ÐºÐ»ÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ ÑваÑ
ÐŸÐŽÑ Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÐаÑ
аваÑÑ Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÐ»Ñ ÑваÑ
ÐŸÐŽÑ Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ÐаÑ
аваÑÑ ÑМÑаÑЌаÑÑÑ Ð¿Ñа ÑпПÑаб ÑваÑ
ÐŸÐŽÑ Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"клÑÑ ÐŽÐŸÑÑÑпÑ"</string>
<string name="password" msgid="6738570945182936667">"паÑПлÑ"</string>
<string name="passkeys" msgid="5733880786866559847">"клÑÑÑ ÐŽÐŸÑÑÑпÑ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐакÑÑÑÑ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"СкаÑÑÑÑаÑÑ Ð·Ð°Ñ
Ð°Ð²Ð°ÐœÑ ÐºÐ»ÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÐÑкаÑÑÑÑПÑваÑÑ Ð¿Ð°ÑПлÑ, заÑ
Ð°Ð²Ð°ÐœÑ ÐŽÐ»Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"СкаÑÑÑÑаÑÑ Ð²Ð°Ñ ÑпПÑаб ÑваÑ
ÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑагÑÐ°ÐŒÑ <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"РазблакÑÑаваÑÑ Ð²Ð°ÑÑÑМÑÑ ÑваÑ
ÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑагÑаЌÑ\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐÑбеÑÑÑе заÑ
Ð°Ð²Ð°ÐœÑ ÐºÐ»ÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ Ð¿ÑагÑÐ°ÐŒÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index e3758ea3..fc6932e 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÐаÑПлОÑе Ñе пÑПЎÑÐ»Ð¶Ð°Ñ ÐŽÐ° Ñа МалОÑе заеЎМП Ñ ÐºÐ»ÑÑПвеÑе за ЎПÑÑÑп пП пÑÑÑ ÐœÐž кÑÐŒ бÑЎеÑе без паÑПлО."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÐзбеÑеÑе кÑЎе Ўа запазОÑе ÑвПОÑе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐзбеÑеÑе ЌеМОЎжÑÑ ÐœÐ° паÑПлО, в кПйÑП Ўа Ñе запазÑÑ ÐŽÐ°ÐœÐœÐžÑе вО, Ñака Ñе ÑлеЎваÑÐžÑ Ð¿ÑÑ ÐŽÐ° влезеÑе пП-бÑÑзП в пÑПÑОла ÑО"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ÐÑкаÑе лО Ўа ÑÑзЎаЎеÑе клÑÑ Ð·Ð° ЎПÑÑÑп, Ñ ÐºÐŸÐ¹ÑП Ўа влОзаÑе в(Ñв) <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÐÑкаÑе лО Ўа запазОÑе паÑПлаÑа, за Ўа влОзаÑе в(Ñв) <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ðа Ñе запазÑÑ Ð»Ðž ЎаММОÑе за вÑ
ПЎ за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"кПЎ за ЎПÑÑÑп"</string>
<string name="password" msgid="6738570945182936667">"паÑПла"</string>
<string name="passkeys" msgid="5733880786866559847">"клÑÑПве за ЎПÑÑÑп"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐÑÑ
вÑÑлÑМе"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ðа Ñе ОзпПлзва лО запазеМОÑÑ Ð²Ðž кПЎ за ЎПÑÑÑп за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÐÑкаÑе лО Ўа ОзпПлзваÑе запазеМаÑа ÑО паÑПла за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Ðа Ñе ÐžÐ·Ð¿ÐŸÐ»Ð·Ð²Ð°Ñ Ð»Ðž ваÑОÑе ЎаММО за вÑ
ПЎ за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"ÐÑкаÑе лО Ўа ПÑклÑÑОÑе ПпÑООÑе за влОзаМе в пÑПÑОла за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐзбеÑеÑе запазеМ клÑÑ Ð·Ð° ЎПÑÑÑп за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index b6f9a88..329189e 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"àŠàŠ®àŠ°àŠŸ àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡àŠ¬àŠ¿àŠ¹à§àŠš àŠàŠ¬àŠ¿àŠ·à§àŠ¯àŠ€à§àа àŠŠàŠ¿àŠà§ àŠàŠàŠ¿àŠ¯àŠŒà§ àŠà§àвà§àŠ, àŠàŠàŠšàŠ \'àŠªàŠŸàŠžàŠà§\'-àŠàа àŠªàŠŸàŠ¶àŠŸàŠªàŠŸàŠ¶àŠ¿ àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¬à§à¥€"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"àŠàŠªàŠšàŠŸàŠ° <xliff:g id="CREATETYPES">%1$s</xliff:g> àŠà§àŠ¥àŠŸàŠ¯àŠŒ àŠžà§àŠ àŠàŠ°àŠ¬à§àŠš àŠ€àŠŸ àŠ¬à§àŠà§ àŠšàŠ¿àŠš"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"àŠàŠªàŠšàŠŸàŠ° àŠ€àŠ¥à§àН àŠžà§àŠ àŠàŠ°àŠ€à§ àŠàŠàŠàŠ¿ Password Manager àŠ¬à§àŠà§ àŠšàŠ¿àŠš àŠàŠ¬àŠ àŠªàŠ°à§àа àŠ¬àŠŸàŠ° àŠàŠ°àŠ àŠŠà§àаà§àŠ€ àŠžàŠŸàŠàŠš-àŠàŠš àŠàаà§àŠš"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> àŠ
à§àŠ¯àŠŸàŠªà§ àŠžàŠŸàŠàŠš-àŠàŠš àŠàŠ°àŠŸàŠ° àŠàŠšà§àН àŠªàŠŸàŠžàŠà§ àŠ€à§àŠ°àŠ¿ àŠàŠ°àŠ¬à§àŠš?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> àŠ
à§àŠ¯àŠŸàŠªà§ àŠžàŠŸàŠàŠš-àŠàŠš àŠàŠ°àŠŸàŠ° àŠàŠšà§àН àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠžà§àŠ àŠàŠ°àŠ¬à§àŠš?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠžàŠŸàŠàŠš-àŠàŠš àŠžàŠàŠà§àŠ°àŠŸàŠšà§àŠ€ àŠ€àŠ¥à§àН àŠžà§àŠ àŠàŠ°àŠ¬à§àŠš?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àŠªàŠŸàŠžàŠà§"</string>
<string name="password" msgid="6738570945182936667">"àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡"</string>
<string name="passkeys" msgid="5733880786866559847">"àŠªàŠŸàŠžàŠà§"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àŠ¬àŠŸàŠ€àŠ¿àŠ² àŠàаà§àŠš"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠàŠªàŠšàŠŸàŠ° àŠžà§àŠ àŠàŠ°àŠŸ àŠªàŠŸàŠžàŠà§ àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°àŠ¬à§àŠš?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"àŠàŠªàŠšàŠŸàŠ° àŠžà§àŠ àŠàŠ°àŠŸ àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ <xliff:g id="APP_NAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°àŠ¬à§àŠš?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠàŠªàŠšàŠŸàŠ° àŠžàŠŸàŠàŠš-àŠàŠš àŠà§àаà§àŠ¡à§àŠšàŠ¶àŠ¿àŠ¯àŠŒàŠŸàŠ² àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°àŠ¬à§àŠš?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠžàŠŸàŠàŠš-àŠàŠš àŠàŠ°àŠŸàŠ° àŠ¬àŠ¿àŠàвà§àŠª àŠàŠšàŠ²àŠ àŠàŠ°àŠ€à§ àŠàŠŸàŠš?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g>-àŠàа àŠàŠšà§àН àŠžà§àŠ àŠàŠ°àŠŸ àŠªàŠŸàŠžàŠà§ àŠ¬à§àŠà§ àŠšàŠ¿àŠš"</string>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 6c00ac0..05f0f1e 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Kako se kreÄemo prema buduÄnosti bez lozinki, lozinke Äe i dalje biti dostupne uz pristupne kljuÄeve."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje Äe se pohranjivati <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja lozinki da saÄuvate svoje informacije i brÅŸe se prijavite sljedeÄi put"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Kreirati pristupni kljuÄ da se prijavite u aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"SaÄuvati lozinku da se prijavite u aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"SaÄuvati informacije o prijavi za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"pristupni kljuÄ"</string>
<string name="password" msgid="6738570945182936667">"lozinka"</string>
<string name="passkeys" msgid="5733880786866559847">"pristupni kljuÄevi"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Odbacivanje"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Koristiti saÄuvani pristupni kljuÄ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Koristiti saÄuvanu lozinku za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Koristiti prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"OtkljuÄati opcije prijave za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Odaberite saÄuvani pristupni kljuÄ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 0d0850f..ba34d61 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Tot i que avancem cap a un futur sense contrasenyes, continuaran estant disponibles juntament amb les claus d\'accés."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Tria on vols desar les <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contrasenyes per desar la teva informació i iniciar la sessió més ràpidament la pròxima vegada"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Vols crear una clau d\'accés per iniciar la sessió a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vols desar la contrasenya per iniciar la sessió a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vols desar la informació d\'inici de sessió per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>
<string name="password" msgid="6738570945182936667">"contrasenya"</string>
<string name="passkeys" msgid="5733880786866559847">"claus d\'accés"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Ignora"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vols utilitzar la clau d\'accés desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vols utilitzar la contrasenya desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vols utilitzar el teu inici de sessió per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vols desbloquejar les opcions d\'inici de sessió per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Tria una clau d\'accés desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index d21afe7..2727737 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"AÄkoliv smÄÅujeme k budoucnosti bez hesel, vedle pÅístupových klíÄů budou stále k dispozici i hesla."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"UrÄete, kam ukládat <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správce hesel k uloÅŸení svých údajů, abyste se pÅíštÄ mohli pÅihlásit rychleji"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"VytvoÅit pÅístupový klíÄ k pÅihlašování do aplikace <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"UloÅŸit heslo k pÅihlašování do aplikace <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"UloÅŸit pÅihlašovací údaje pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"pÅístupový klíÄ"</string>
<string name="password" msgid="6738570945182936667">"heslo"</string>
<string name="passkeys" msgid="5733880786866559847">"pÅístupové klíÄe"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ZavÅít"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"PouÅŸít uloÅŸený pÅístupový klíÄ pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"PouÅŸít pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g> uloÅŸené heslo?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"PouÅŸít pÅihlášení pro <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Odemknout moÅŸnosti pÅihlášení pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Vyberte uloÅŸený pÅístupový klíÄ pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index c868a4b..d3ff9e7 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Selvom vi nærmer os en fremtid, hvor adgangskoder er mindre fremtrædende, kan de stadig bruges i samspil med adgangsnøgler."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Vælg, hvor du vil gemme dine <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Vælg en adgangskodeadministrator for at gemme dine oplysninger, så du kan logge ind hurtigere næste gang"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Vil du oprette en adgangsnøgle for at logge ind på <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vil du gemme adgangskoden for at logge ind på <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du gemme loginoplysningerne til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>
<string name="password" msgid="6738570945182936667">"adgangskode"</string>
<string name="passkeys" msgid="5733880786866559847">"adgangsnøgler"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Luk"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruge din gemte adgangsnøgle til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vil du bruge din gemte adgangskode til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vil du bruge dine loginoplysninger til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vil du låse enheden op for at se loginmetoder for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Vælg en gemt adgangsnøgle til <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index 4fba522..cb01139 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Auch wenn wir uns auf eine passwortlose Zukunft zubewegen, werden neben Passkeys weiter Passwörter verfügbar sein."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Wähle aus, wo deine <xliff:g id="CREATETYPES">%1$s</xliff:g> gespeichert werden sollen"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Du kannst einen Passwortmanager auswählen, um deine Anmeldedaten zu speichern, damit du dich nächstes Mal schneller anmelden kannst"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Passkey zur Anmeldung in <xliff:g id="APPNAME">%1$s</xliff:g> erstellen?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Passwort zur Anmeldung in <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Anmeldedaten für <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"Passkey"</string>
<string name="password" msgid="6738570945182936667">"Passwort"</string>
<string name="passkeys" msgid="5733880786866559847">"Passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Schließen"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Soll dein gespeichertes Passwort für <xliff:g id="APP_NAME">%1$s</xliff:g> verwendet werden?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Anmeldeoptionen für <xliff:g id="APP_NAME">%1$s</xliff:g> freischalten?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Einen gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> auswählen"</string>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index ad6a424..c8e4099 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ΚαθÏς κινοÏμαστε προς Îνα μÎλλον χωρίς κωδικοÏς πρÏσβασης, οι κωδικοί πρÏσβασης θα εξακολουθοÏν να είναι διαθÎσιμοι μαζί με τα κλειδιά πρÏσβασης."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ΕπιλÎξτε ποÏ θα αποθηκεÏονται τα <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ΕπιλÎξτε Îνα πρÏγραμμα διαχείρισης κωδικÏν πρÏσβασης για να αποθηκεÏσετε τα στοιχεία σας και να συνδεθείτε πιο γρήγορα την επÏμενη φορά."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Δημιουργία κλειδιοÏ πρÏσβασης για σÏνδεση στην εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Αποθήκευση κωδικοÏ πρÏσβασης για σÏνδεση στην εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Αποθήκευση στοιχείων σÏνδεσης για <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"κλειδί πρÏσβασης"</string>
<string name="password" msgid="6738570945182936667">"κωδικÏς πρÏσβασης"</string>
<string name="passkeys" msgid="5733880786866559847">"κλειδιά πρÏσβασης"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Παράβλεψη"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Να χρησιμοποιηθεί το αποθηκευμÎνο κλειδί πρÏσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Χρήση του αποθηκευμÎνου κωδικοÏ πρÏσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Χρήση της σÏνδεσής σας για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Ξεκλείδωμα των επιλογÏν σÏνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Επιλογή αποθηκευμÎνου κλειδιοÏ πρÏσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 6aa1b5e..f30b856 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Create passkey to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Save password to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Use your saved password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Use your sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Unlock sign-in options for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choose a saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index 10d95993..5eb63c6 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Create passkey to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Save password to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Use your saved password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Use your sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Unlock sign-in options for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choose a saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 6aa1b5e..f30b856 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Create passkey to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Save password to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Use your saved password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Use your sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Unlock sign-in options for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choose a saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 6aa1b5e..f30b856 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Create passkey to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Save password to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Use your saved password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Use your sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Unlock sign-in options for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choose a saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index 16c0d1d..067d106 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Create passkey to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Save password to sign in to <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkeys"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Use your saved password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Use your sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Unlock sign-in options for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choose a saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index 6bab1ae..41918f2 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"A medida que avanzamos hacia un futuro sin contraseñas, estas seguirán estando disponibles junto a las llaves de acceso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un administrador de contraseñas para guardar tu información y acceder más rápido la próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"¿Quieres crear una llave de acceso para acceder a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"¿Quieres guardar la contraseña para acceder a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Quieres guardar la información de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
<string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Descartar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Quieres usar tu llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"¿Quieres usar la contraseña guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"¿Quieres usar tu acceso para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"¿Quieres desbloquear las opciones de acceso para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Elige una llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index a727f458..35f9cad 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Aunque nos dirigimos hacia un mundo sin contraseñas, estas seguirán estando disponibles junto con las llaves de acceso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contraseñas para guardar tu información e iniciar sesión más rápido la próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"¿Crear llave de acceso para iniciar sesión en <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"¿Guardar contraseña para iniciar sesión en <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Guardar la información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contraseña"</string>
<string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Cerrar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Usar la llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"¿Usar la contraseña que tienes guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"¿Usar tu inicio de sesión en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"¿Desbloquear las opciones de inicio de sesión de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Elige una llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 2727612..d9581bd 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Liikudes paroolivaba tuleviku poole, jäävad paroolid pääsuvõtmete kõrval siiski kättesaadavaks."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Valige, kuhu soovite oma <xliff:g id="CREATETYPES">%1$s</xliff:g> salvestada"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Valige paroolihaldur, et salvestada oma teave ja järgmisel korral kiiremini sisse logida"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Kas luua rakendusse <xliff:g id="APPNAME">%1$s</xliff:g> sisselogimiseks pääsuvõti?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Kas salvestada rakendusse <xliff:g id="APPNAME">%1$s</xliff:g> sisselogimiseks parool?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Kas salvestada rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks sisselogimisandmed?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"pääsuvõti"</string>
<string name="password" msgid="6738570945182936667">"parool"</string>
<string name="passkeys" msgid="5733880786866559847">"pääsuvõtmed"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Loobu"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud pääsuvõtit?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> puhul salvestatud parooli?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Kas soovite rakendusse <xliff:g id="APP_NAME">%1$s</xliff:g> sisselogimiseks kasutada oma mandaati?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Kas avada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks sisselogimisvalikud?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Valige rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud pääsuvõti"</string>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index f0debcc..ffe2091 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Pasahitzik gabeko etorkizun baterantz goazen arren, pasahitzek sarbide-gakoen bizikide izaten jarraituko dute."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Aukeratu non gorde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Hautatu informazioa gordetzeko pasahitz-kudeatzaile bat eta hasi saioa bizkorrago hurrengoan"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioan saioa hasteko sarbide-gako bat sortu nahi duzu?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioan saioa hasteko pasahitza gorde nahi duzu?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioko saioa hasteko informazioa gorde nahi duzu?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>
<string name="password" msgid="6738570945182936667">"pasahitza"</string>
<string name="passkeys" msgid="5733880786866559847">"sarbide-gakoak"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Baztertu"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde duzun sarbide-gakoa erabili nahi duzu?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako pasahitza erabili nahi duzu?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> zerbitzuan saioa hasteko kredentzialak erabili nahi dituzu?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko aukerak desblokeatu nahi dituzu?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako sarbide-gakoa"</string>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index a88b353..5d3198c 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Ø¯Ø±ØØ§ÙÛÚ©Ù ØšÙØ³ÙÛ Ø¢ÛÙØ¯ÙØ§Û ØšÛÚ¯Ø°Ø±ÙØ§ÚÙ ØØ±Ú©Øª Ù
ÛÚ©ÙÛÙ
Ø Ú¯Ø°Ø±ÙØ§ÚÙÙØ§ ÙÙ
ÚÙØ§Ù در Ú©ÙØ§Ø± گذرکÙÛØ¯Ùا دردسترس Ø®ÙØ§ÙÙØ¯ ØšÙØ¯"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"جاÛÛ Ø±Ø§ ØšØ±Ø§Û Ø°Ø®ÛØ±Ù کرد٠<xliff:g id="CREATETYPES">%1$s</xliff:g> Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Ù
Ø¯ÛØ± Ú¯Ø°Ø±ÙØ§ÚÙØ§Û Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯ تا Ø§Ø·ÙØ§Ø¹Ø§ØªØªØ§Ù را Ø°Ø®ÛØ±Ù Ú©ÙÛØ¯ Ù Ø¯ÙØ¹Ù ؚعد Ø³Ø±ÛØ¹ØªØ± ØšÙ Ø³ÛØ³ØªÙ
ÙØ§Ø±Ø¯ ØŽÙÛØ¯"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ØšØ±Ø§Û ÙØ±Ùد ØšÙ Ø³ÛØ³ØªÙ
<xliff:g id="APPNAME">%1$s</xliff:g>Ø Ú¯Ø°Ø±Ú©ÙÛØ¯ Ø§ÛØ¬Ø§Ø¯ ØŽÙØ¯Ø"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ØšØ±Ø§Û ÙØ±Ùد ØšÙ Ø³ÛØ³ØªÙ
<xliff:g id="APPNAME">%1$s</xliff:g>Ø Ú¯Ø°Ø±ÙØ§ÚÙ Ø°Ø®ÛØ±Ù ØŽÙØ¯Ø"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ø§Ø·ÙØ§Ø¹Ø§Øª ÙØ±Ùد ØšÙ Ø³ÛØ³ØªÙ
<xliff:g id="APPNAME">%1$s</xliff:g> Ø°Ø®ÛØ±Ù ØŽÙØ¯Ø"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"گذرکÙÛØ¯"</string>
<string name="password" msgid="6738570945182936667">"Ú¯Ø°Ø±ÙØ§ÚÙ"</string>
<string name="passkeys" msgid="5733880786866559847">"گذرکÙÛØ¯Ùا"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ؚستÙ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"از گذرکÙÛØ¯ Ø°Ø®ÛØ±ÙØŽØ¯Ù ØšØ±Ø§Û «<xliff:g id="APP_NAME">%1$s</xliff:g>» Ø§Ø³ØªÙØ§Ø¯Ù ØŽÙØ¯Ø"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"از Ú¯Ø°Ø±ÙØ§ÚÙ Ø°Ø®ÛØ±ÙØŽØ¯ÙØªØ§Ù ØšØ±Ø§Û <xliff:g id="APP_NAME">%1$s</xliff:g> Ø§Ø³ØªÙØ§Ø¯Ù ØŽÙØ¯Ø"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"از Ø±ÙØŽ ÙØ±Ùد ØšÙ Ø³ÛØ³ØªÙ
ØŽÙ
ا ØšØ±Ø§Û <xliff:g id="APP_NAME">%1$s</xliff:g> Ø§Ø³ØªÙØ§Ø¯Ù ØŽÙØ¯Ø"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"گزÛÙÙÙØ§Û ÙØ±Ùد ØšÙ Ø³ÛØ³ØªÙ
ØšØ±Ø§Û <xliff:g id="APP_NAME">%1$s</xliff:g> ؚاز ØŽÙØ¯Ø"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"گذرکÙÛØ¯ Ø°Ø®ÛØ±ÙØŽØ¯ÙØ§Û را ØšØ±Ø§Û <xliff:g id="APP_NAME">%1$s</xliff:g> Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯"</string>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index 82af70f..7091da8 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Kehitys kulkee kohti salasanatonta tulevaisuutta, mutta salasanat ovat edelleen käytettävissä avainkoodien ohella."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Valitse, minne <xliff:g id="CREATETYPES">%1$s</xliff:g> tallennetaan"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Valitse salasanojen ylläpitotyökalu, niin voit tallentaa tietosi ja kirjautua ensi kerralla nopeammin sisään"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Luodaanko avainkoodi sisäänkirjautumista (<xliff:g id="APPNAME">%1$s</xliff:g>) varten?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Tallennetaanko salasana sisäänkirjautumista (<xliff:g id="APPNAME">%1$s</xliff:g>) varten?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Tallennetaanko kirjautumistiedot (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"avainkoodi"</string>
<string name="password" msgid="6738570945182936667">"salasana"</string>
<string name="passkeys" msgid="5733880786866559847">"avainkoodit"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Sulje"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Käytetäänkö tallennettua avainkoodiasi täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Käytetäänkö tallennettua salasanaasi sovelluksessa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Käytetäänkö kirjautumistapaa: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Avataanko kirjautumisvaihtoehdot (<xliff:g id="APP_NAME">%1$s</xliff:g>)?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g>: valitse tallennettu avainkoodi"</string>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index 61f2204..ac7b77c 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"À mesure que nous nous dirigeons vers un avenir sans mot de passe, ils resteront toujours utilisés parallèlement aux clés d\'accès."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choisir où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos renseignements et vous connecter plus rapidement la prochaine fois"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Créer une clé d\'accès pour se connecter à <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Enregistrer un mot de passe pour se connecter à <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les renseignements de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
<string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Fermer"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Utiliser votre mot de passe enregistré pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Utiliser votre identifiant de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Déverrouiller les options de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choisissez une clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index 15715f3..a6b2fe2 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Nous nous dirigeons vers un futur sans mots de passe, mais ceux-ci resteront disponibles en plus des clés d\'accès."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Choisissez où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos informations et vous connecter plus rapidement la prochaine fois"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Créer une clé d\'accès pour se connecter à <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Enregistrer un mot de passe pour se connecter à <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les informations de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
<string name="password" msgid="6738570945182936667">"mot de passe"</string>
<string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Fermer"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Utiliser votre mot de passe enregistré pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Utiliser vos infos de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Déverrouiller les options de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choisir une clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index 1ca0774..76a9d4b 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Durante este percorrido cara a un futuro sen contrasinais, estes seguirán estando dispoñibles a canda as claves de acceso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Escolle onde queres gardar: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un xestor de contrasinais para gardar a túa información e iniciar sesión máis rápido a próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Queres crear unha clave de acceso para iniciar sesión en <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Queres gardar o contrasinal para iniciar sesión en <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Queres gardar a información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"clave de acceso"</string>
<string name="password" msgid="6738570945182936667">"contrasinal"</string>
<string name="passkeys" msgid="5733880786866559847">"claves de acceso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Pechar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Queres usar a clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Queres usar o contrasinal gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Queres usar o teu inicio de sesión para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Queres desbloquear as opcións de inicio de sesión para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Escolle unha clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index 7d8df9a..11d1df6 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"àªàªªàª£à« પટઞવરà«àª¡ રહિ઀ àªàªµàª¿àª·à«àª¯ ઀રફ àªàªàª³ વધૠરહà«àª¯àªŸàª àªà«àª, àªàª€àªŸàª પટઞàªà«àªšà« ઞટથà«àªžàªŸàª¥ હàªà« પણ પટઞવરà«àª¡ àªàªªàª²àª¬à«àª§ રહà«àª¶à«."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"઀મટરૠ<xliff:g id="CREATETYPES">%1$s</xliff:g> àªà«àª¯àªŸàª ઞટàªàªµàªµà« ઀ૠપઞàªàªŠ àªàª°à«"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"઀મટરૠમટહિ઀ૠઞટàªàªµàªµàªŸ મટàªà« પટઞવરà«àª¡ મà«àªšà«àªàª° પઞàªàªŠ àªàª°à« àª
ચૠàªàªàª²à« વàªàª€à« વધૠàªàª¡àªªàª¥à« ઞટàªàªš àªàªš àªàª°à«"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g>મટઠઞટàªàªš àªàªš àªàª°àªµàªŸ મટàªà« પટઞàªà« બચટવà«àª?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g>મટઠપટઞવરà«àª¡ ઞટàªàªµàªµàªŸ મટàªà« પટઞàªà« બચટવà«àª?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> મટàªà« ઞટàªàªš-àªàªš àªàª°àªµàªŸàªšà« મટહિ઀ૠઞટàªàªµà«àª?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"પટઞàªà«"</string>
<string name="password" msgid="6738570945182936667">"પટઞવરà«àª¡"</string>
<string name="passkeys" msgid="5733880786866559847">"પટઞàªà«"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àªà«àª¡à« ઊà«"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> મટàªà« શà«àª ઀મટરૠઞટàªàªµà«àª²à« પટઞàªà«àªšà« àªàªªàª¯à«àª àªàª°à«àª?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"શà«àª <xliff:g id="APP_NAME">%1$s</xliff:g> મટàªà« ઀મટરટ ઞટàªàªµà«àª²àªŸ પટઞવરà«àª¡àªšà« àªàªªàª¯à«àª àªàª°à«àª?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"શà«àª <xliff:g id="APP_NAME">%1$s</xliff:g>મટઠઞટàªàªš àªàªš àªàª°àªµàªŸ મટàªà« ઀મટરૠઠલà«àª àªàªš વિàªàª€à«àªšà« àªàªªàª¯à«àª àªàª°à«àª?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> મટàªà« ઞટàªàªš àªàªš વિàªàª²à«àªªà« àª
ચલà«àª àªàª°à«àª?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> મટàªà« àªà«àª ઞટàªàªµà«àª²à« પટઞàªà« પઞàªàªŠ àªàª°à«"</string>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index b644864..0e9e106 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à€à€šà¥ à€µà€Ÿà€²à¥ à€žà€®à€¯ à€®à¥à€ à€¬à€¿à€šà€Ÿ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€µà€Ÿà€²à¥ à€à¥à€à¥à€šà¥à€²à¥à€à¥ à€¯à€Ÿà€šà¥ à€ªà€Ÿà€žà€à¥ à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€¬à€¢à€Œà¥à€à€Ÿ, à€¹à€Ÿà€²à€Ÿà€à€à€¿ à€à€žà€à¥ à€žà€Ÿà€¥-à€žà€Ÿà€¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à¥ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€¿à€ à€à€Ÿ à€žà€à¥à€à€à¥."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à€à¥à€šà¥à€ à€à€¿ à€
à€ªà€šà¥ <xliff:g id="CREATETYPES">%1$s</xliff:g> à€à€¹à€Ÿà€ à€žà¥à€µ à€à€°à€šà¥ à€¹à¥à€"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à€
à€ªà€šà¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà¥à€µ à€à€°à€šà¥ à€à¥ à€²à€¿à€, à€ªà€Ÿà€žà€µà€°à¥à€¡ à€®à¥à€šà¥à€à€° à€à¥à€šà¥à€ à€à€° à€
à€à€²à¥ à€¬à€Ÿà€° à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€€à¥à€à€Œà¥ à€žà¥ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APPNAME">%1$s</xliff:g> à€®à¥à€ à€žà€Ÿà€à€š à€à€š à€à€°à€šà¥ à€à¥ à€²à€¿à€ à€ªà€Ÿà€žà€à¥ à€¬à€šà€Ÿà€šà¥ à€¹à¥?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APPNAME">%1$s</xliff:g> à€®à¥à€ à€žà€Ÿà€à€š à€à€š à€à€°à€šà¥ à€à¥ à€²à€¿à€ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€žà¥à€µ à€à€°à€šà€Ÿ à€¹à¥?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APPNAME">%1$s</xliff:g> à€à¥ à€²à€¿à€ à€žà€Ÿà€à€š-à€à€š à€à¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà¥à€µ à€à€°à€šà¥ à€¹à¥?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"à€ªà€Ÿà€žà€à¥"</string>
<string name="password" msgid="6738570945182936667">"à€ªà€Ÿà€žà€µà€°à¥à€¡"</string>
<string name="passkeys" msgid="5733880786866559847">"à€ªà€Ÿà€žà€à¥"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"à€à€Ÿà€°à€¿à€ à€à€°à¥à€"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APP_NAME">%1$s</xliff:g> à€ªà€° à€žà€Ÿà€à€š à€à€š à€à€°à€šà¥ à€à¥ à€²à€¿à€, à€žà¥à€µ à€à¥ à€à€ à€ªà€Ÿà€žà€à¥ à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€šà€Ÿ à€¹à¥?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APP_NAME">%1$s</xliff:g> à€à¥ à€²à€¿à€ à€žà¥à€µ à€à€¿à€¯à€Ÿ à€¹à¥à€ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€šà€Ÿ à€¹à¥?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APP_NAME">%1$s</xliff:g> à€à¥ à€²à€¿à€ à€
à€ªà€šà¥ à€žà€Ÿà€à€š-à€à€š à€à¥à€°à¥à€¡à¥à€à€¶à€¿à€¯à€² à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€šà€Ÿ à€¹à¥?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"à€à¥à€¯à€Ÿ à€à€ªà€à¥ <xliff:g id="APP_NAME">%1$s</xliff:g> à€®à¥à€ à€žà€Ÿà€à€š à€à€š à€à€°à€šà¥ à€à¥ à€µà€¿à€à€²à¥à€ªà¥à€ à€à¥ à€
à€šà€²à¥à€ à€à€°à€šà€Ÿ à€¹à¥?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à¥ à€²à€¿à€ à€žà¥à€µ à€à¥ à€à€ à€ªà€Ÿà€žà€à¥ à€à¥à€šà¥à€"</string>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 86d52d5..61a16b7 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Kako idemo u smjeru buduÄnosti bez zaporki, one Äe i dalje biti dostupne uz pristupne kljuÄeve."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje Äe se spremati <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja zaporki kako biste spremili svoje informacije i drugi se put brÅŸe prijavili"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Åœelite li izraditi pristupni kljuÄ za prijavu u aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Åœelite li spremiti zaporku za prijavu u aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Spremiti informacije o prijavi za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"pristupni kljuÄ"</string>
<string name="password" msgid="6738570945182936667">"zaporka"</string>
<string name="passkeys" msgid="5733880786866559847">"pristupni kljuÄevi"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Odbaci"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Åœelite li upotrijebiti spremljeni pristupni kljuÄ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Åœelite li upotrijebiti spremljenu zaporku za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Åœelite li upotrijebiti prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Åœelite li otkljuÄati opcije za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Odaberite spremljeni pristupni kljuÄ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 539feb4..f9c5861 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Miközben a jelszó nélküli jövÅ felé haladunk, a jelszavak továbbra is rendelkezésre állnak majd az azonosítókulcsok mellett."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Válassza ki, hogy hova szeretné menteni <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Válasszon jelszókezelÅt, hogy menthesse az adatait, és gyorsabban jelentkezhessen be a következÅ alkalommal."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Létrehoz azonosítókulcsot a következÅbe való bejelentkezéshez: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Menti a jelszót a következÅbe való bejelentkezéshez: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Menti a bejelentkezési adatokat a következÅhöz: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>
<string name="password" msgid="6738570945182936667">"jelszó"</string>
<string name="passkeys" msgid="5733880786866559847">"azonosítókulcsait"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Elvetés"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett azonosítókulcsot használni?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Szeretné az elmentett jelszavát használni a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Szeretné használni bejelentkezési adatait a következÅhöz: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Feloldja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> bejelentkezési lehetÅségeit?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Mentett azonosítókulcs kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index 5f06a7a..2159840 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Ô¹Õ¥Ö ÕŽÕ¥Õ¶Ö Õ¡ÕŒÕ¡Õ¶Ö Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡ÕŒÕ¥ÖÕ« Õ¡ÕºÕ¡Õ£Õ¡ÕµÕ« Õ³Õ¡Õ¶Õ¡ÕºÕ¡ÖÕ°Õ«Õ¶ Õ¥Õ¶Ö, Õ€ÖÕ¡Õ¶Ö Õ€Õ¥ÕŒ հա՜անելի Õ¯Õ¬Õ«Õ¶Õ¥Õ¶ Õ¡Õ¶ÖաբաՌեÖÕ« Õ°Õ¥Õ¿ ÕŽÕ¥Õ¯Õ¿Õ¥Õ²Ö"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÕÕ·Õ¥Ö, Õ©Õ¥ ÕžÖÕ¿Õ¥Õ² Õ¥Ö ÕžÖÕŠÕžÖÕŽ ÕºÕ¡Õ°Õ¥Õ¬ Õ±Õ¥Ö <xliff:g id="CREATETYPES">%1$s</xliff:g>Õš"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÔžÕ¶Õ¿ÖÕ¥Ö Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡ÕŒÕ¥ÖÕ« կաՌա՟աÖÕ«Õ¹Õ Õ±Õ¥Ö Õ¿Õ¥Õ²Õ¥Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš ÕºÕ¡Õ°Õ¥Õ¬ÕžÖ Ö Õ°Õ¡Õ»ÕžÖÕ€ Õ¡Õ¶Õ£Õ¡ÕŽ Õ¡ÕŸÕ¥Õ¬Õ« Õ¡ÖÕ¡Õ£ ÕŽÕžÖÕ¿Ö Õ£ÕžÖÕ®Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ÕÕ¿Õ¥Õ²Õ®Õ¥ÕÕ¬ Õ¡Õ¶ÖÕ¡Õ¢Õ¡ÕŒÕ <xliff:g id="APPNAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ® ÕŽÕžÖÕ¿Ö Õ£ÕžÖÕ®Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÕÕ¡Õ°Õ¥ÕÕ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡ÕŒÕšÕ <xliff:g id="APPNAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ® ÕŽÕžÖÕ¿Ö Õ£ÕžÖÕ®Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ÕÕ¡Õ°Õ¥ÕÕ¬ «<xliff:g id="APPNAME">%1$s</xliff:g>» Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ« ÕŽÕžÖÕ¿ÖÕ« Õ¿ÕŸÕµÕ¡Õ¬Õ¶Õ¥ÖÕš"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"Õ¡Õ¶ÖÕ¡Õ¢Õ¡ÕŒ"</string>
<string name="password" msgid="6738570945182936667">"գաղտնաբաՌ"</string>
<string name="passkeys" msgid="5733880786866559847">"Õ¡Õ¶ÖաբաՌեÖ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÕÕ¡Õ¯Õ¥Õ¬"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ÕÕ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥ÕÕ¬ ÕºÕ¡Õ°ÕŸÕ¡Õ® Õ¡Õ¶ÖաբաՌ՚ <xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ« Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÕÕ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥ÕÕ¬ <xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ« Õ°Õ¡ÕŽÕ¡Ö ÕºÕ¡Õ°ÕŸÕ¡Õ® Õ±Õ¥Ö Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡ÕŒÕš"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ÕÕ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥ÕÕ¬ Õ¡ÕµÕœ Õ¿ÕŸÕµÕ¡Õ¬Õ¶Õ¥ÖÕš <xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ® ÕŽÕžÖÕ¿Ö Õ£ÕžÖÕ®Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Ô±ÕºÕ¡Õ¯ÕžÕ²ÕºÕ¥ÕÕ¬ ÕŽÕžÖÕ¿ÖÕ« Õ¿Õ¡ÖÕ¢Õ¥ÖÕ¡Õ¯Õ¶Õ¥Ö <xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ« Õ°Õ¡ÕŽÕ¡Ö"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÔžÕ¶Õ¿ÖÕ¥Ö ÕºÕ¡Õ°ÕŸÕ¡Õ® Õ¡Õ¶ÖÕ¡Õ¢Õ¡ÕŒ <xliff:g id="APP_NAME">%1$s</xliff:g> Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ« Õ°Õ¡ÕŽÕ¡Ö"</string>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index ad8aeec..77b2e43 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Sandi akan tetap tersedia bersama kunci sandi seiring perjalanan menuju era di mana sandi tidak diperlukan lagi."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat penyimpanan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Pilih pengelola sandi untuk menyimpan info Anda dan login lebih cepat lain kali"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Buat kunci sandi untuk login ke <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Simpan sandi untuk login ke <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan info login untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"kunci sandi"</string>
<string name="password" msgid="6738570945182936667">"sandi"</string>
<string name="passkeys" msgid="5733880786866559847">"kunci sandi"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Tutup"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Gunakan sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Gunakan login Anda untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Autentikasi opsi login untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Pilih kunci sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index bc6bdfc..fd8c7fd 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Við stefnum að framtíð án aðgangsorða en aðgangsorð verða áfram í boði samhliða aðgangslyklum."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Veldu hvar þú vilt vista <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Veldu aðgangsorðastjórnun til að vista upplýsingarnar og vera fljótari að skrá þig inn næst"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Búa til aðgangslykil til að skrá þig inn á <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vista aðgangsorð til að skrá þig inn á <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Viltu vista innskráningarupplýsingar fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>
<string name="password" msgid="6738570945182936667">"aðgangsorð"</string>
<string name="passkeys" msgid="5733880786866559847">"aðgangslykla"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Hunsa"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Nota vistaðan aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Nota vistaða aðgangsorðið þitt fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Nota innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Opna fyrir innskráningarvalkosti fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Veldu vistaðan aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index 2b0d83c..515e860 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Il futuro sarà senza password, ma per ora saranno ancora disponibili insieme alle passkey."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Scegli dove salvare le <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Seleziona un gestore delle password per salvare i tuoi dati e accedere più velocemente la prossima volta"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Creare passkey per accedere all\'app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Salvare password per accedere all\'app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vuoi salvare i dati di accesso di <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"passkey"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Chiudi"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vuoi usare la passkey salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vuoi usare la password salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vuoi usare il tuo accesso per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vuoi sbloccare le opzioni di accesso per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Scegli una passkey salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index ee9dd5d..8016afc 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"×× ×× × ×תק×××× ××¢×ך עת×× ××× ×¡×ס×××ת, ××× ×¢×××× ×׀שך ×××× ××שת×ש ×ס×ס×××ת ××× ××׀ת××ת ××ש×."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"×××ךת ×××§×× ×ש×××š× ×©× <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"×׀שך ××××ך ×××× ×ש×ך××ª× × ×××× ×ס×ס×××ת ××× ×ש××ך ×ת ×׀ך××× ×××××× ×¡ ××ש××× ××ך ××תך ××€×¢× ××××"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"××׊×ך ××€×ª× ×××©× ××× ××××× ×¡ ××ש××× ×-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"×ש××ך ×ת ×ס×ס×× ××× ××××× ×¡ ××ש××× ×-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"×ש××ך ×ת ׀ך×× ××× ××¡× ×©× <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"××€×ª× ××ש×"</string>
<string name="password" msgid="6738570945182936667">"ס×ס××"</string>
<string name="passkeys" msgid="5733880786866559847">"×׀ת××ת ××ש×"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ס××ך×"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"××שת×ש ×××€×ª× ×××©× ×©× ×©×ך ×¢××ך <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"××שת×ש ×ס×ס×× ×ש×××š× ×©× <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"××שת×ש ××ש××× ×©×× ××× ××××× ×¡ ×× <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"×××× ×ת ×× ×¢××× ×©× ×׀שך×××ת ××× ××¡× ×× <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"×××ךת ××€×ª× ×××©× ×©××ך ×-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index b60638b..72dc156 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"å°æ¥çã«ãã¹ã¯ãŒãã¬ã¹ã«ç§»è¡ããã«ãããããã¹ã¯ãŒãããã¹ããŒãšäžŠè¡ããŠåŒãç¶ããå©çšããã ããŸãã"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>ã®ä¿åå
ãéžæ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ãã¹ã¯ãŒã ãããŒãžã£ãŒãéžæããŠæ
å ±ãä¿åããŠãããšã次åãããã°ãããã°ã€ã³ã§ããŸã"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> ã«ãã°ã€ã³ããããã«ãã¹ããŒãäœæããŸããïŒ"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> ã«ãã°ã€ã³ããããã«ãã¹ã¯ãŒããä¿åããŸããïŒ"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ã®ãã°ã€ã³æ
å ±ãä¿åããŸããïŒ"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ãã¹ããŒ"</string>
<string name="password" msgid="6738570945182936667">"ãã¹ã¯ãŒã"</string>
<string name="passkeys" msgid="5733880786866559847">"ãã¹ããŒ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"éãã"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ã®ä¿åãããã¹ããŒã䜿çšããŸããïŒ"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> ã®ä¿åãããã¹ã¯ãŒãã䜿çšããŸããïŒ"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ãã®èªèšŒæ
å ±ã䜿çšã㊠<xliff:g id="APP_NAME">%1$s</xliff:g> ã«ãã°ã€ã³ããŸããïŒ"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> ããã°ã€ã³æ¹æ³ã䜿çšã§ããããã«ããŸããïŒ"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> ã«äœ¿çšãããã¹ããŒãéžæããŠãã ãã"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index c089f4a..0ba8d2d 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"á£ááá ááá áááááááášá ááá ááááá ááááá á®ááááá¡áá¬ááááá áá¥áááá, á¬áááááá¡ ááá¡ááŠááááááá áá ááá."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ááá á©ááá á¡áá ášááááá®áá áá¥áááá <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ááá á©ááá ááá áááááá¡ áááá ááááá áá¥áááá ááá€áá áááªááá¡ ášáá¡áááá®áá, á áá áááááááášá á£á€á á á¡á¬á áá€áá ášáá®ááááá."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ášáá¡áá¡áááááá á¬áááááá¡ ááá¡ááŠáááá¡ ášáá¥ááá: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ášáá¡áá¡ááááá ááá áááá¡ ášáááá®áá: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ášááááá®ááá <xliff:g id="APPNAME">%1$s</xliff:g> ááášá ášáá¡áááá¡ ááá€áá áááªááá¡?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"á¬áááááá¡ ááá¡ááŠááá"</string>
<string name="password" msgid="6738570945182936667">"ááá ááá"</string>
<string name="passkeys" msgid="5733880786866559847">"á¬áááááá¡ ááá¡ááŠááá"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ááá®á£á áá"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"áá¡á£á á áá¥áááá ááááá®á¡ááá ááá£áá á¬áááááá¡ ááá¡ááŠáááá¡ ááááá§ááááá áááá¡áááá¡: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"áááááá§ááááá ášáááá®á£á ááá ááá¡ <xliff:g id="APP_NAME">%1$s</xliff:g>-á¡áááá¡?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"áá¡á£á á ášáá¡áááá¡ <xliff:g id="APP_NAME">%1$s</xliff:g>-áá¡áááá¡ ááááá§ááááá?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"áá¡á£á á ášáá¡áááá¡ ááá áááá¢áááá¡ ááááááááá <xliff:g id="APP_NAME">%1$s</xliff:g>-á¡áááá¡?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ááá á©ááá ášáááá®á£áá á¬áááááá¡ ááá¡ááŠááá <xliff:g id="APP_NAME">%1$s</xliff:g>-á¡áááá¡"</string>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index 2200b18..e45d34c 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÒÒ±Ð¿ÐžÑ ÑөзÑÑз бПлаÑÐ°Ò Ð¶Ð°ÒÑМ бПлÒаМÑМа ÒаÑаЌаÑÑаМ, келеÑекÑе ÒÒ±Ð¿ÐžÑ ÑөзЎеÑÐŽÑ ÐºÑÑÑ ÐºÑлÑÑеÑÑЌеМ ÒаÑÐ°Ñ ÒПлЎаМа беÑÑге бПлаЎÑ."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ÒайЎа ÑаÒÑалаÑÑМÑМ ÑаңЎаңÑз"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐÓлÑЌеÑÑÒ£ÑÐ·ÐŽÑ ÑаÒÑап, келеÑÑЎе жÑлЎаЌ кÑÑÑ Ò¯ÑÑМ ÒÒ±Ð¿ÐžÑ Ñөз ЌеМеЎжеÑÑМ ÑаңЎаңÑз."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> ÒПлЎаМбаÑÑМа кÑÑÑ Ò¯ÑÑМ кÑÑÑ ÐºÑлÑÑ Ð¶Ð°ÑалÑÑМ ба?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> ÒПлЎаМбаÑÑМа кÑÑÑ Ò¯ÑÑМ ÒÒ±Ð¿ÐžÑ Ñөз ÑаÒÑалÑÑМ ба?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> Ò¯ÑÑМ кÑÑÑ ÐŒÓлÑЌеÑÑМ ÑаÒÑÐ°Ñ ÐºÐµÑек пе?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ÐÑÑÑ ÐºÑлÑÑ"</string>
<string name="password" msgid="6738570945182936667">"ÒÒ±Ð¿ÐžÑ Ñөз"</string>
<string name="passkeys" msgid="5733880786866559847">"кÑÑÑ ÐºÑлÑÑеÑÑ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐабÑ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑÑМ ÑаÒÑалÒаМ кÑÑÑ ÐºÑлÑÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑлÑÑМ ба?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑÑМ ÑаÒÑалÒаМ ÒÒ±Ð¿ÐžÑ ÑөзÑÒ£ÑÐ·ÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÐ°ÑÑз ба?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> ÒПлЎаМбаÑÑМа кÑÑÑ ÐŽÐµÑекÑеÑÑМ пайЎалаМаÑÑз ба?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑÑМ кÑÑÑ ÐŸÐ¿ÑОÑлаÑÑ Ð°ÑÑлÑÑМ ба?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑÑМ ÑаÒÑалÒаМ кÑÑÑ ÐºÑлÑÑМ ÑаңЎаңÑз"</string>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index d0faaec..b004c56 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"áá
ááááááááŸááá¶ááá
ááá¢áá¶ááááááááá¶ááá¶áááááááá¶áá áá¶áááááááá¶áááá
ááá¢á¶á
ááááŸáá¶áááœááá¶ááœáááŒáááááá¶ááá"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ááááŸáááŸáááááááâáááááááŒáááááá¶áá»á<xliff:g id="CREATETYPES">%1$s</xliff:g>ááááá¢ááá"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ááááŸáááŸáâáááááá·áážááááááááááá¶áááááááá¶áá ááŸáááážááááá¶áá»áâáááááá¶áááááá¢ááá áá·áá
áŒááááážâáá¶ááá¶áááááá ááâáá
áááááŸáááááá"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"áááááŸáááŒáááááá¶áá ááŸáááážá
áŒáááááž <xliff:g id="APPNAME">%1$s</xliff:g> á¬?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ááááá¶áá»ááá¶áááááááá¶áá ááŸáááážá
áŒáááááž <xliff:g id="APPNAME">%1$s</xliff:g> á¬?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ááááá¶áá»áâáááááá¶áá¢ááážâáá¶áá
áŒááááážááááá¶áá <xliff:g id="APPNAME">%1$s</xliff:g> á¬?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ááŒáááááá¶áá"</string>
<string name="password" msgid="6738570945182936667">"áá¶áááááááá¶áá"</string>
<string name="passkeys" msgid="5733880786866559847">"ááŒáááááá¶áá"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"á
ááá¶áá
áá"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ááááŸááŒáááááá¶ááááááá¶áááááá¶áá»áááááá¢áááááááá¶áá <xliff:g id="APP_NAME">%1$s</xliff:g> á¬?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ááááŸáá¶áááááááá¶ááâáááá¢ááááá¶áâááááá¶áá»áááááá¶áá <xliff:g id="APP_NAME">%1$s</xliff:g> á¬?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ááááŸáá¶áá
áŒááááážááááá¢áááááááá¶áá <xliff:g id="APP_NAME">%1$s</xliff:g> á¬?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"áááâáááááááŸáá
áŒáâáááážááááá¶áá <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ááááŸáááŸáááŒáááááá¶ááááááá¶áááááá¶áá»áááááá¶áá <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index 59e3b5c..b6f5340 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ಚಟವೠಪಟಞà³à²µà²°à³à²¡à³ ರಹಿಀ ಀà²à²€à³à²°à²à³à²à²Ÿà²šà²Š à²à²¡à³à²à³ ಞಟà²à³à²€à³à²€à²¿à²°à³à²µà²Ÿà², ಪಟಞà³à²à³à²à²³ à²à³à²€à³à²à³ ಪಟಞà³à²µà²°à³à²¡à³à²à²³à³ à²à²šà³à²šà³ ಲà²à³à²¯à²µà²¿à²°à³à²€à³à²€à²µà³."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ಚಿಮà³à²® <xliff:g id="CREATETYPES">%1$s</xliff:g> à²à²²à³à²²à²¿ ಞà³à²µà³ à²à²à²¬à³à²à³ à²à²à²¬à³à²Šà²šà³à²šà³ à²à²°à²¿à²žà²¿"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ಚಿಮà³à²® ಮಟಹಿಀಿಯಚà³à²šà³ à²à²³à²¿à²žà²²à³ ಪಟಞà³à²µà²°à³à²¡à³ ಚಿರà³à²µà²Ÿà²¹à²à²µà²šà³à²šà³ à²à²¯à³à²à³à²®à²Ÿà²¡à²¿ ಹಟà²à³ ಮà³à²à²Šà²¿à²š ಬಟರಿ ವà³à²à²µà²Ÿà²à²¿ ಞà³à²šà³ à²à²šà³ ಮಟಡಿ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> à²à³ ಞà³à²šà³ à²à²šà³ ಮಟಡಲೠಪಟಞà³à²à³ ರà²à²¿à²žà³à²µà³à²Šà³?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> à²à³ ಞà³à²šà³ à²à²šà³ ಮಟಡಲೠಪಟಞà³à²µà²°à³à²¡à³ à²
ಚà³à²šà³ ಞà³à²µà³ ಮಟಡà³à²µà³à²Šà³?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à²à²Ÿà²à²¿ ಞà³à²šà³-à²à²šà³ ಮಟಹಿಀಿಯಚà³à²šà³ à²à²³à²¿à²žà³à²µà³à²Šà³?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ಪಟಞà³à²à³"</string>
<string name="password" msgid="6738570945182936667">"ಪಟಞà³à²µà²°à³à²¡à³"</string>
<string name="passkeys" msgid="5733880786866559847">"ಪಟಞà³à²à³à²à²³à³"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ವà²à²Ÿà²à³à²³à²¿à²žà²¿"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> à²à²Ÿà²à²¿ à²à²³à²¿à²žà²²à²Ÿà²Š ಚಿಮà³à²® ಪಟಞà³à²à³ à²
ಚà³à²šà³ ಬಳಞಬà³à²à³?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> à²à²Ÿà²à²¿ ಚಿಮà³à²® à²à²³à²¿à²žà²²à²Ÿà²Š ಪಟಞà³à²µà²°à³à²¡à³ à²
ಚà³à²šà³ ಬಳಞಬà³à²à³?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à²à²Ÿà²à²¿ ಚಿಮà³à²® ಞà³à²šà³ à²à²šà³ à²
ಚà³à²šà³ ಬಳಞಬà³à²à³?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à²à²Ÿà²à²¿ ಞà³à²šà³-à²à²šà³ à²à²¯à³à²à³à²à²³à²šà³à²šà³ à²
ಚà³à²²à²Ÿà²à³ ಮಟಡಬà³à²à³?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à²à²Ÿà²à²¿ à²à²³à²¿à²žà²²à²Ÿà²Š ಪಟಞà³à²à³ à²
ಚà³à²šà³ à²à²°à²¿à²žà²¿"</string>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index fd48d18..8e2c333 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ë¹ë°ë²íž ìë 믞ëë¡ ëìê°ë 곌ì ìì ë¹ë°ë²ížë ì¬ì í íšì€í€ì íšê» ì¬ì©ë ê²ì
ëë€."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ì ì¥ ìì¹ ì í"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ì 볎륌 ì ì¥íŽì ë€ìì ë ë¹ ë¥Žê² ë¡ê·žìžíë €ë©Ž ë¹ë°ë²íž êŽëЬì륌 ì ííìžì."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"íšì€í€ë¥Œ ìì±íì¬ <xliff:g id="APPNAME">%1$s</xliff:g>ì ë¡ê·žìžíìê² ìµëê¹?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ë¹ë°ë²ížë¥Œ ì ì¥íì¬ <xliff:g id="APPNAME">%1$s</xliff:g>ì ë¡ê·žìžíìê² ìµëê¹?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>ì ë¡ê·žìž ì 볎륌 ì ì¥íìê² ìµëê¹?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"íšì€í€"</string>
<string name="password" msgid="6738570945182936667">"ë¹ë°ë²íž"</string>
<string name="passkeys" msgid="5733880786866559847">"íšì€í€"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ë«êž°"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ì±ì©ìŒë¡ ì ì¥ë íšì€í€ë¥Œ ì¬ì©íìê² ìµëê¹?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ì ì¥ë ë¹ë°ë²ížë¥Œ <xliff:g id="APP_NAME">%1$s</xliff:g>ì ì¬ì©í ê¹ì?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g>ì ë¡ê·žìžì ì¬ì©íìê² ìµëê¹?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g>ì ëíŽ ë¡ê·žìž ìµì
ì ì êž íŽì íìê² ìµëê¹?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g>ì ëíŽ ì ì¥ë íšì€í€ ì í"</string>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index 6a01462..d65e5d2 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"СÑÑÑөзÑүз келеÑекÑО көзЎөй баÑаÑÑак Ўа, алаÑÐŽÑ ÐºÐžÑгОзүүÑÒ¯ аÑкÑÑÑÐ°Ñ ÐŒÐµÐœÐµÐœ бОÑге кПлЎПМП беÑүүгө бПлПÑ."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> кайЎа ÑакÑалаÑÑМ ÑаМЎаңÑз"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐаалÑЌаÑÑÒ£ÑÐ·ÐŽÑ ÑакÑПП жаМа кОйОМкО Ð¶ÐŸÐ»Ñ ÑезОÑÑÑк кОÑÒ¯Ò¯ Ò¯ÑүМ ÑÑÑÑөзЎөÑÐŽÒ¯ баÑкаÑгÑÑÑÑ ÑаМЎаңÑз"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> кПлЎПМЌПÑÑМа кОÑÒ¯Ò¯ Ò¯ÑүМ кОÑгОзүүÑÒ¯ аÑкÑÑÑÑ ÑүзөÑүзбү?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> кПлЎПМЌПÑÑМа кОÑÒ¯Ò¯ Ò¯ÑүМ ÑÑÑÑөзЎү ÑакÑайÑÑзбÑ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> Ò¯ÑүМ кОÑÒ¯Ò¯ ЌаалÑЌаÑÑ ÑакÑалÑÑМбÑ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"кОÑгОзүүÑÒ¯ аÑкÑÑ"</string>
<string name="password" msgid="6738570945182936667">"ÑÑÑÑөз"</string>
<string name="passkeys" msgid="5733880786866559847">"кОÑгОзүүÑÒ¯ аÑкÑÑÑаÑ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐабÑÑ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> кПлЎПМЌПÑÑМа кОÑÒ¯Ò¯ Ò¯ÑүМ ÑакÑалгаМ аÑкÑÑÑÑ ÐºÐŸÐ»ÐŽÐŸÐœÐŸÑÑзбÑ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑүМ ÑакÑалгаМ ÑÑÑÑөзЎү кПлЎПМПÑÑзбÑ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> кПлЎПМЌПÑÑМа ÑөЌөМкү аккаÑÐœÑ ÐŒÐµÐœÐµÐœ кОÑеÑОзбО?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑүМ кОÑÒ¯Ò¯ паÑаЌеÑÑлеÑОМОМ кÑлпÑÑÑ Ð°ÑÑлÑÑМбÑ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ò¯ÑүМ ÑакÑалгаМ кОÑгОзүүÑÒ¯ аÑкÑÑÑÑ ÑаМЎаңÑз"</string>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index e71c60f..594bac3 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à»àºàºàº°àºàº°àºàºµà»àºàº§àºà»àº®àº»àº²àºà»àº²àº§à»àºàºªàº¹à»àºàº°àºàº²àºàº»àºàºàºµà»àºà»à»àºà»àºàºà»àºà»àº¥àº°àº«àº±àºàºà»àº²àº, ລະຫັàºàºà»àº²àºàºàº°àºàº±àºàºàº»àºà»àºà»à»àºà»àºàº§àºàºàº¹à»à»àºàºàº±àºàºàº°à»àºàºà»àº²àº."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à»àº¥àº·àºàºàºà»àºàºàºàºµà»àºàº°àºàº±àºàºàº¶àº <xliff:g id="CREATETYPES">%1$s</xliff:g> àºàºàºàºà»àº²àº"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à»àº¥àº·àºàºàºàº»àº§àºàº±àºàºàº²àºàº¥àº°àº«àº±àºàºà»àº²àºà»àºàº·à»àºàºàº±àºàºàº¶àºàºà»à»àº¡àº¹àºàºàºàºàºà»àº²àº à»àº¥àº° à»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àºà»àº§àºàº¶à»àºà»àºà»àºàº·à»àºàºà»à»à»àº"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ສà»àº²àºàºàº°à»àºàºà»àº²àºà»àºàº·à»àºà»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àº <xliff:g id="APPNAME">%1$s</xliff:g> àºà»?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"àºàº±àºàºàº¶àºàº¥àº°àº«àº±àºàºà»àº²àºà»àºàº·à»àºà»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àº <xliff:g id="APPNAME">%1$s</xliff:g> àºà»?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"àºàº±àºàºàº¶àºàºà»à»àº¡àº¹àºàºàº²àºà»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àºàºªàº³àº¥àº±àº <xliff:g id="APPNAME">%1$s</xliff:g> àºà»?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àºàº°à»àºàºà»àº²àº"</string>
<string name="password" msgid="6738570945182936667">"ລະຫັàºàºà»àº²àº"</string>
<string name="passkeys" msgid="5733880786866559847">"àºàº°à»àºàºà»àº²àº"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àºàºŽàºà»àº§à»"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"à»àºà»àºàº°à»àºàºà»àº²àºàºàºµà»àºàº±àºàºàº¶àºà»àº§à»àºàºàºàºà»àº²àºàºªàº³àº¥àº±àº <xliff:g id="APP_NAME">%1$s</xliff:g> àºà»?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"à»àºà»àº¥àº°àº«àº±àºàºà»àº²àºàºàºµà»àºàº±àºàºàº¶àºà»àº§à»àºàºàºàºà»àº²àºàºªàº³àº¥àº±àº <xliff:g id="APP_NAME">%1$s</xliff:g> àºà»?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"à»àº¥àº·àºàºàºàº²àºà»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àºàºàºàºàºà»àº²àºàºªàº³àº¥àº±àº <xliff:g id="APP_NAME">%1$s</xliff:g> àºà»?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"àºàº»àºàº¥àº±àºàºàºàº»àº§à»àº¥àº·àºàºàºàº²àºà»àºàº»à»àº²àºªàº¹à»àº¥àº°àºàº»àºàºªàº³àº¥àº±àº <xliff:g id="APP_NAME">%1$s</xliff:g> àºà»?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"à»àº¥àº·àºàºàºàº°à»àºàºà»àº²àºàºàºµà»àºàº±àºàºàº¶àºà»àº§à»àºªàº³àº¥àº±àº <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index 55c5cd2..4d4a259 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Kol stengiamÄs padaryti, kad ateityje nereikÄtų naudoti slaptaÅŸodÅŸių, jie vis dar bus pasiekiami kartu su prieigos raktais."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Pasirinkite, kur išsaugoti „<xliff:g id="CREATETYPES">%1$s</xliff:g>“"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Pasirinkite slaptaÅŸodÅŸių tvarkyklÄ, kuriÄ
naudodami galÄsite išsaugoti informacijÄ
ir kitÄ
kartÄ
prisijungti greiÄiau"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Sukurti prieigos raktÄ
, skirtÄ
prisijungti prie „<xliff:g id="APPNAME">%1$s</xliff:g>“?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Sukurti slaptaÅŸodį, skirtÄ
prisijungti prie „<xliff:g id="APPNAME">%1$s</xliff:g>“?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Išsaugoti prisijungimo prie „<xliff:g id="APPNAME">%1$s</xliff:g>“ informacijÄ
?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"„passkey“"</string>
<string name="password" msgid="6738570945182936667">"slaptaÅŸodis"</string>
<string name="passkeys" msgid="5733880786866559847">"prieigos raktas"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Atsisakyti"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Naudoti išsaugotÄ
„passkey“ programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Naudoti išsaugotÄ
slaptaÅŸodį programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Naudoti prisijungimo informacijÄ
programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Atrakinti prisijungimo prie „<xliff:g id="APP_NAME">%1$s</xliff:g>“ parinktis?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Išsaugoto prieigos rakto, skirto „<xliff:g id="APP_NAME">%1$s</xliff:g>“, pasirinkimas"</string>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index 2c0f8e1..f76d120 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Lai arÄ« pamazÄm notiek pÄreja uz darbu bez parolÄm, tÄs joprojÄm bÅ«s pieejamas lÄ«dzÄs piekÄŒuves atslÄgÄm."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"IzvÄlieties, kur saglabÄt savas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Lai saglabÄtu informÄciju un nÄkamreiz varÄtu pierakstÄ«ties ÄtrÄk, atlasiet paroÄŒu pÄrvaldnieku."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Vai izveidot piekÄŒuves atslÄgu, lai pierakstÄ«tos lietotnÄ <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vai saglabÄt paroli, lai pierakstÄ«tos lietotnÄ <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vai saglabÄt pierakstÄ«šanÄs informÄciju lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"piekÄŒuves atslÄga"</string>
<string name="password" msgid="6738570945182936667">"parole"</string>
<string name="passkeys" msgid="5733880786866559847">"piekÄŒuves atslÄgas"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"NerÄdÄ«t"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vai izmantot saglabÄto piekÄŒuves atslÄgu lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vai izmantot jÅ«su saglabÄto paroli lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vai izmantot jÅ«su pierakstÄ«šanÄs informÄciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vai vÄlaties atbloÄ·Ät lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> pierakstÄ«šanÄs opcijas?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"SaglabÄtas piekÄŒuves atslÄgas izvÄle lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 6f8f76b..428878a 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÐакП ÑÑП Ñе ЎвОжОЌе кПМ ОЎМОМа без лПзОМкО, лПзОМкОÑе Ñепак Ñе Ð±ÐžÐŽÐ°Ñ ÐŽÐŸÑÑапМО пПкÑÐ°Ñ ÐºÑОпÑПгÑаÑÑкОÑе клÑÑевО."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÐзбеÑеÑе каЎе Ўа гО заÑÑваÑе ваÑОÑе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐзбеÑеÑе ÑпÑавМОк ÑП лПзОМкО за Ўа гО заÑÑваÑе ваÑОÑе пПЎаÑПÑО О Ўа Ñе МаÑавОÑе пПбÑзП ÑÐ»ÐµÐŽÐœÐžÐŸÑ Ð¿Ð°Ñ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Ðа Ñе ÑПзЎаЎе кÑОпÑПгÑаÑÑкО клÑÑ Ð·Ð° МаÑавÑваÑе Ма <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Ðа Ñе заÑÑва лПзОМкаÑа за МаÑавÑваÑе Ма <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ðа Ñе заÑÑÐ²Ð°Ð°Ñ Ð¿ÐŸÐŽÐ°ÑПÑОÑе за МаÑавÑваÑе за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"кÑОпÑПгÑаÑÑкО клÑÑ"</string>
<string name="password" msgid="6738570945182936667">"лПзОМка"</string>
<string name="passkeys" msgid="5733880786866559847">"кÑОпÑПгÑаÑÑкО клÑÑевО"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐÑÑÑлО"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ðа Ñе кПÑОÑÑО ваÑÐžÐŸÑ Ð·Ð°ÑÑваМ кÑОпÑПгÑаÑÑкО клÑÑ Ð·Ð° <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Ðа Ñе кПÑОÑÑÐ°Ñ Ð·Ð°ÑÑваМОÑе лПзОМкО за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Ðа Ñе кПÑОÑÑО ваÑеÑП МаÑавÑваÑе за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Ðа Ñе ПÑклÑÑÐ°Ñ ÐŸÐ¿ÑООÑе за МаÑавÑваÑе за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐзбеÑеÑе заÑÑваМ кÑОпÑПгÑаÑÑкО клÑÑ Ð·Ð° <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index ab32bc9..e686117 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"àŽšàŽ®àµàŽ®àµŸ àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽ°àŽ¹àŽ¿àŽ€ àŽàŽŸàŽµàŽ¿àŽ¯àŽ¿àŽ²àµàŽàµàŽàµ àŽàµà޵àŽàµà޵àµàŽàµàŽàµàŽàµàŽ£àµàŽàŽ¿àŽ°àŽ¿àŽàµàŽàµàŽàŽ¯àŽŸàŽ£àµ àŽàŽàµàŽàŽ¿àŽ²àµàŽ, àŽªàŽŸàŽžàµàŽàµàŽàµŸàŽàµàŽàµàŽªàµàŽªàŽ àŽªàŽŸàŽžàµà޵àµàŽ¡àµàŽàµŸ àŽ€àµàŽàµŒàŽšàµàŽšàµàŽ àŽ²àŽàµàŽ¯àŽ®àŽŸàŽ¯àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽ."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ <xliff:g id="CREATETYPES">%1$s</xliff:g> àŽàŽµàŽ¿àŽàµàŽ¯àŽŸàŽ£àµ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽàµàŽ£àµàŽàŽ€àµàŽšàµàŽšàµ àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽàµàŽàµàŽ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽàŽŸàŽšàµàŽ àŽ
àŽàµàŽ€àµàŽ€ àŽ€àŽµàŽ£ àŽµàµàŽàŽ€àµàŽ€àŽ¿àµœ àŽžàµàµ» àŽàµ» àŽàµàޝàµàŽ¯àŽŸàŽšàµàŽ àŽàŽ°àµ àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽ®àŽŸàŽšàµàŽàµŒ àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽàµàŽàµàŽ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽ²àµàŽàµàŽàµ àŽžàµàµ» àŽàµ» àŽàµàޝàµàŽ¯àŽŸàµ» àŽªàŽŸàŽžàµàŽàµ àŽžàµàŽ·àµàŽàŽ¿àŽàµàŽàŽ£àµ?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽ²àµàŽàµàŽàµ àŽžàµàµ» àŽàµ» àŽàµàޝàµàŽ¯àŽŸàµ» àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽàŽ£àµ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàŽŸàŽ¯àŽ¿ àŽžàµàµ» àŽàµ» àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽàŽ£àµ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àŽªàŽŸàŽžàµàŽàµ"</string>
<string name="password" msgid="6738570945182936667">"àŽªàŽŸàŽžàµà޵àµàŽ¡àµ"</string>
<string name="passkeys" msgid="5733880786866559847">"àŽªàŽŸàŽžàµàŽàµàŽàµŸ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àŽ¡àŽ¿àŽžàµàŽ®àŽ¿àŽžàµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàŽŸàŽ¯àŽ¿ àŽšàŽ¿àŽàµàŽàµŸ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽ àŽªàŽŸàŽžàµàŽàµ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàŽ£àµ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàŽŸàŽ¯àŽ¿ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽ àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàŽ£àµ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽªàµàŽªàŽ¿àŽšàµà޳àµà޳ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽžàµàµ» àŽàµ» àŽàµàްàµàŽ¡àµ»àŽ·àµàŽ¯àŽ²àµàŽàµŸ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàŽ£àµ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàŽŸàŽ¯àŽ¿ àŽžàµàµ» àŽàµ» àŽàŽªàµàŽ·àŽšàµàŽàµŸ àŽ
àµºàŽ²àµàŽàµàŽàµ àŽàµàޝàµàŽ¯àŽ£àµ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àŽšàŽŸàŽ¯àŽ¿ àŽàŽ°àµ àŽžàŽàްàŽàµàŽ·àŽ¿àŽàµàŽ àŽªàŽŸàŽžàµàŽàµ àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽàµàŽàµàŽ"</string>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index a704ea0..72cda9f 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÐОЎ МÑÑÑ Ò¯Ð³Ð³Ò¯Ð¹ ОÑÑÑЎүй ÑÒ¯Ò¯ ÑÑагÑлаÑ
ÑМ Ñ
ÑÑÑÑÑ ÐœÑÑÑ Ò¯Ð³ ÐœÑ ÐœÑвÑÑÑÑ
ÑүлÑ
Ò¯Ò¯ÑОйМ Ñ
аЌÑÐ°Ð°Ñ Ð±ÐŸÐ»ÐŸÐŒÐ¶ÑПй Ñ
ÑвÑÑÑ Ð±Ð°Ð¹Ñ
бПлМП."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>-г Ñ
ааМа Ñ
аЎгалаÑ
аа ÑПМгПМП ÑÑ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐÑÐŽÑÑллÑÑ Ñ
аЎгалж, ЎаÑаагОйМ ÑЎаа Олүү Ñ
ÑÑЎаМ МÑвÑÑÑÑ
ОйМ ÑÑлЎ МÑÑÑ Ò¯Ð³ÐœÐžÐ¹ ЌеМежеÑОйг ÑПМгПМП ÑÑ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g>-ÐŽ МÑвÑÑÑÑ
ОйМ ÑÑлЎ МÑвÑÑÑÑ
ÑүлÑ
Ò¯Ò¯Ñ Ò¯Ò¯ÑгÑÑ
Ò¯Ò¯?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g>-ÐŽ МÑвÑÑÑÑ
ОйМ ÑÑлЎ МÑÑÑ Ò¯Ð³ÐžÐ¹Ð³ Ñ
аЎгалаÑ
ÑÑ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>-М МÑвÑÑÑÑ
ÐŒÑÐŽÑÑллОйг Ñ
аЎгалаÑ
ÑÑ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"МÑÑÑ Ò¯Ð³"</string>
<string name="passkeys" msgid="5733880786866559847">"МÑвÑÑÑÑ
ÑүлÑ
Ò¯Ò¯ÑүүЎ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ХааÑ
"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ÐŽ Ó©Ó©ÑОйМ Ñ
аЎгалÑаМ passkey-г аÑОглаÑ
ÑÑ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ÐŽ Ñ
аЎгалÑаМ МÑÑÑ Ò¯Ð³ÑÑ Ð°ÑОглаÑ
ÑÑ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g>-М МÑвÑÑÑлÑÑÑ Ð°ÑОглаÑ
ÑÑ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ÐŽ МÑвÑÑÑлÑОйМ ÑПМгПлÑÑМ ÑүгжÑÑг ÑайлаÑ
ÑÑ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ÐŽ Ñ
аЎгалÑаМ МÑвÑÑÑÑ
ÑүлÑ
Ò¯Ò¯Ñ ÑПМгПМП ÑÑ"</string>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index d3e14dd..2d72bc0 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à€ªà€Ÿà€žà€µà€°à¥à€¡ à€š à€µà€Ÿà€ªà€°à€£à€Ÿà€±à¥à€¯à€Ÿ à€à€µà€¿à€·à¥à€¯à€Ÿà€€ à€ªà¥à€¢à¥ à€à€Ÿà€€à€Ÿà€šà€Ÿ, à€ªà€Ÿà€žà€µà€°à¥à€¡ à€€à€°à¥à€¹à¥ à€ªà€Ÿà€žà€à¥à€à¥à€¯à€Ÿ à€¬à€°à¥à€¬à€°à¥à€šà¥ à€à€ªà€²à€¬à¥à€§ à€
à€žà€€à¥à€²."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à€€à¥à€®à€à¥ <xliff:g id="CREATETYPES">%1$s</xliff:g> à€à¥à€ à¥ à€žà¥à€µà¥à€¹ à€à€°à€Ÿà€¯à€à¥ à€€à¥ à€šà€¿à€µà€¡à€Ÿ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à€€à¥à€®à€à¥ à€®à€Ÿà€¹à€¿à€€à¥ à€žà¥à€µà¥à€¹ à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à€£à€¿ à€ªà¥à€¢à€à¥à€¯à€Ÿ à€µà¥à€³à¥ à€à€²à€Š à€žà€Ÿà€à€š à€à€š à€à€°à€£à¥à€¯à€Ÿà€à€°à€¿à€€à€Ÿ Password Manager à€šà€¿à€µà€¡à€Ÿ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> à€®à€§à¥à€¯à¥ à€žà€Ÿà€à€š à€à€š à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ à¥ à€ªà€Ÿà€žà€à¥ à€€à€¯à€Ÿà€° à€à€°à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> à€®à€§à¥à€¯à¥ à€žà€Ÿà€à€š à€à€š à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€žà¥à€µà¥à€¹ à€à€°à€Ÿà€¯à€à€Ÿ à€à€¹à¥ à€à€Ÿ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€žà€Ÿà€à€š-à€à€š à€®à€Ÿà€¹à€¿à€€à¥ à€žà¥à€µà¥à€¹ à€à€°à€Ÿà€¯à€à¥ à€à€Ÿ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"à€ªà€Ÿà€žà€à¥"</string>
<string name="password" msgid="6738570945182936667">"à€ªà€Ÿà€žà€µà€°à¥à€¡"</string>
<string name="passkeys" msgid="5733880786866559847">"à€ªà€Ÿà€žà€à¥"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"à€¡à€¿à€žà€®à€¿à€ž à€à€°à€Ÿ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€€à¥à€®à€à¥ à€žà¥à€µà¥à€¹ à€à¥à€²à¥à€²à¥ à€ªà€Ÿà€žà€à¥ à€µà€Ÿà€ªà€°à€Ÿà€¯à€à¥ à€à€Ÿ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"à€€à¥à€®à€à€Ÿ à€žà¥à€µà¥à€¹ à€à¥à€²à¥à€²à€Ÿ à€ªà€Ÿà€žà€µà€°à¥à€¡ <xliff:g id="APP_NAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€µà€Ÿà€ªà€°à€Ÿà€¯à€à€Ÿ à€à€¹à¥ à€à€Ÿ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€€à¥à€®à€à¥ à€žà€Ÿà€à€š-à€à€š à€µà€Ÿà€ªà€°à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€žà€Ÿà€à€š-à€à€š à€ªà€°à¥à€¯à€Ÿà€¯ à€
à€šà€²à¥à€ à€à€°à€Ÿà€¯à€à¥ à€à€¹à¥à€€ à€à€Ÿ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€žà€Ÿà€ à¥ à€žà¥à€µà¥à€¹ à€à¥à€²à¥à€²à¥ à€ªà€Ÿà€žà€à¥ à€šà€¿à€µà€¡à€Ÿ"</string>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index a491177..2a42b87 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Meskipun masa depan kita nanti tidak memerlukan kata laluan, kata laluan masih akan tersedia bersama dengan kunci laluan."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat untuk menyimpan <xliff:g id="CREATETYPES">%1$s</xliff:g> anda"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Pilih Password Manager untuk menyimpan maklumat anda dan log masuk lebih pantas pada kali seterusnya"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Buat kunci laluan untuk log masuk ke <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Simpan kata laluan untuk log masuk ke <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan maklumat log masuk untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"kunci laluan"</string>
<string name="password" msgid="6738570945182936667">"kata laluan"</string>
<string name="passkeys" msgid="5733880786866559847">"kunci laluan"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Ketepikan"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci laluan anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Gunakan kata laluan anda yang disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Gunakan log masuk anda untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Buka kunci pilihan log masuk untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Pilih kunci laluan yang disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index b427a58..a40d973 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"á
áá¬ážááŸááºááá¯á¶ážááŒááºáž á¡áá¬áááºáá®ááá¯á· ááŸá±á·áááºáá¬ááœáẠáá»áŸáá¯á·ááŸááºáá®ážáá»á¬ážááŸáá·áºá¡áá° á
áá¬ážááŸááºáá»á¬ážááᯠáááºáááºá¡áá¯á¶ážááŒá¯ááá¯ááºáá«áááºá"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"áááºá <xliff:g id="CREATETYPES">%1$s</xliff:g> ááááºážáááºáá±áᬠááœá±ážááŒááºáž"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ááá·áºá¡áá»ááºá¡áááºááááºážááŒá®áž áá±á¬ááºáá
áºááŒáááºá ááá¯ááá¯ááŒááºáááºá
áœá¬ áááºááŸááºááá¯ážáááºááẠá
áá¬ážááŸááºáááºáá±áá»á¬ááᯠááœá±ážáá«"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> ááá¯á· áááºááŸááºááá¯ážáááºááẠáá»áŸáá¯á·ááŸááºáá®áž ááŒá¯áá¯ááºááá¬ážá"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> ááá¯á· áááºááŸááºááá¯ážáááºááẠá
áá¬ážááŸááºááᯠááááºážááá¬ážá"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> á¡ááœáẠáááºááŸááºááá¯ážáááºááá·áºá¡áá»ááºá¡áááºááᯠááááºážááá¬ážá"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"áá»áŸáá¯á·ááŸááºáá®áž"</string>
<string name="password" msgid="6738570945182936667">"á
áá¬ážááŸááº"</string>
<string name="passkeys" msgid="5733880786866559847">"áá»áŸáá¯á·ááŸááºáá®ážáá»á¬áž"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"áááºáááº"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ááááºážáá¬ážáá±á¬áá»áŸáá¯á·ááŸááºáá®ážááᯠ<xliff:g id="APP_NAME">%1$s</xliff:g> á¡ááœáẠáá¯á¶ážááá¬ážá"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> á¡ááœáẠááááºážáá¬ážáá±á¬á
áá¬ážááŸáẠáá¯á¶ážááá¬ážá"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> á¡ááœáẠááá·áºáááºááŸááºááá¯ážáááºááŸá¯ááᯠáá¯á¶ážááá¬ážá"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> á¡ááœáẠáááºááŸááºááá¯ážáááºááŸá¯ ááœá±ážá
áá¬ááᯠááœáá·áºááá¬ážá"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> á¡ááœáẠááááºážáá¬ážáá±á¬ áá»áŸáá¯á·ááŸááºáá®áž ááœá±ážáá«"</string>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 1e780ee5..09157bd 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Vi går mot en fremtid uten passord, men passord fortsetter å være tilgjengelige ved siden av passnøkler."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Velg hvor du vil lagre <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Velg et verktøy for passordlagring for å lagre informasjonen din og logge på raskere neste gang"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Vil du opprette en passnøkkel for å logge på <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vil du lagre passordet for å logge på <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du lagre påloggingsinformasjon for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passnøkkel"</string>
<string name="password" msgid="6738570945182936667">"passord"</string>
<string name="passkeys" msgid="5733880786866559847">"passnøkler"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Lukk"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruke den lagrede tilgangsnøkkelen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vil du bruke det lagrede passordet ditt for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vil du bruke påloggingen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vil du låse opp påloggingsalternativene for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Velg en lagret passnøkkel for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 55d4e87..813ecad 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à€¹à€Ÿà€®à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡à€°à€¹à€¿à€€ à€à€µà€¿à€·à¥à€¯à€€à€°à¥à€« à€¬à€¢à¥à€Šà¥ à€à€°à¥à€Šà€Ÿ à€ªà€Ÿà€žà€à¥à€à€Ÿ à€žà€Ÿà€¥à€žà€Ÿà€¥à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€ªà€šà€¿ à€à€ªà€²à€¬à¥à€§ à€¹à¥à€šà¥ à€à¥€"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à€€à€ªà€Ÿà€à€ à€à€«à¥à€šà€Ÿ <xliff:g id="CREATETYPES">%1$s</xliff:g> à€à€¹à€Ÿà€ à€žà¥à€ à€à€°à¥à€š à€à€Ÿà€¹à€šà¥à€¹à¥à€šà¥à€ à€à€šà¥à€šà¥ à€à¥à€°à€Ÿ à€à€šà¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à€à¥à€šà¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€®à¥à€¯à€Ÿà€šà¥à€à€°à€®à€Ÿ à€à€«à¥à€šà¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà¥à€ à€à€°à¥ à€
à€°à¥à€à¥ à€ªà€à€ à€
à€ à€à€¿à€à¥ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€š à€ªà€Ÿà€žà€à¥ à€¬à€šà€Ÿà€à€šà¥ à€¹à¥?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€š à€ªà€Ÿà€žà€µà€°à¥à€¡ à€žà¥à€ à€à€°à¥à€šà¥ à€¹à¥?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€°à¥à€š à€ªà¥à€°à€¯à¥à€ à€à€°à€¿à€šà¥ à€ªà€°à¥à€šà¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€žà¥à€ à€à€°à¥à€šà¥ à€¹à¥?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"à€ªà€Ÿà€žà€à¥"</string>
<string name="password" msgid="6738570945182936667">"à€ªà€Ÿà€žà€µà€°à¥à€¡"</string>
<string name="passkeys" msgid="5733880786866559847">"à€ªà€Ÿà€žà€à¥à€¹à€°à¥"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"à€¹à€à€Ÿà€à€šà¥à€¹à¥à€žà¥"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"à€à€«à¥à€²à¥ à€žà¥à€ à€à€°à¥à€à¥ à€ªà€Ÿà€žà€à¥ à€ªà¥à€°à€¯à¥à€ à€à€°à¥ <xliff:g id="APP_NAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€šà¥ à€¹à¥?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€š à€žà¥à€ à€à€°à€¿à€à€à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€¹à¥?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€šà€à€Ÿ à€²à€Ÿà€à€¿ à€€à€ªà€Ÿà€à€à€à€Ÿ à€à¥à€°à€¿à€¡à¥à€šà¥à€žà€¿à€¯à€²à€¹à€°à¥ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€¹à¥?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€à€Ÿ à€žà€Ÿà€à€š à€à€šà€žà€®à¥à€¬à€šà¥à€§à¥ à€µà€¿à€à€²à¥à€ªà€¹à€°à¥ à€
à€šà€²à€ à€à€°à¥à€šà¥ à€¹à¥?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à€®à€Ÿ à€žà€Ÿà€à€š à€à€š à€à€°à¥à€š à€žà¥à€ à€à€°à€¿à€à€à¥ à€ªà€Ÿà€žà€à¥ à€à€šà¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index 53b3d70..3e46cc9 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"We zijn op weg naar een wachtwoordloze toekomst, maar naast toegangssleutels kun je nog steeds gebruikmaken van wachtwoorden."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Kiezen waar je je <xliff:g id="CREATETYPES">%1$s</xliff:g> wilt opslaan"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecteer een wachtwoordmanager om je informatie op te slaan en de volgende keer sneller in te loggen"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Toegangssleutel maken om in te loggen bij <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Wachtwoord opslaan om in te loggen bij <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Inloggegevens opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"Toegangssleutel"</string>
<string name="password" msgid="6738570945182936667">"wachtwoord"</string>
<string name="passkeys" msgid="5733880786866559847">"toegangssleutels"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Sluiten"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Je opgeslagen toegangssleutel gebruiken voor <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Je opgeslagen wachtwoord voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Je login voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Inlogopties voor <xliff:g id="APP_NAME">%1$s</xliff:g> ontgrendelen?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Opgeslagen toegangssleutel kiezen voor <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index ad268c9..5bf4627 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à¬à¬®à à¬à¬ ପଟଞà±à¬Ÿà¬°àଡବିହàଚ à¬à¬¬à¬¿à¬·àà଀ à¬à¬¡à¬Œà¬à ମàଠà¬à¬°àଥିବଟ ଯàà¬àଠà¬à¬¬à ବି ପଟଞà¬àà¬àଡଌିଠଞହି଀ ପଟଞà±à¬Ÿà¬°àଡ à¬à¬ªà¬²à¬¬àଧ ହàବी"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à¬à¬ªà¬£à¬àଠ<xliff:g id="CREATETYPES">%1$s</xliff:g> à¬àà¬à¬à¬ ଟରà ଞàଠà¬à¬°à¬¿à¬¬à ଀ଟହଟ ବଟà¬à¬šà଀à"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à¬à¬ªà¬£à¬àଠଞàà¬à¬šà¬Ÿ ଞàଠà¬à¬°à¬¿ ପରବରà଀à଀à ଞମàରà ଶàà¬àର ଞଟà¬à¬š à¬à¬š à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ à¬à¬ Password Manager à¬àଚ à¬à¬°à¬šà଀à"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g>ରà ଞଟà¬à¬š à¬à¬š à¬à¬°à¬¿à¬¬à¬Ÿà¬à ପଟଞà¬à ଀ିà¬à¬°à¬¿ à¬à¬°à¬¿à¬¬à?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g>ରà ଞଟà¬à¬š à¬à¬š à¬à¬°à¬¿à¬¬à¬Ÿà¬à ପଟଞà±à¬Ÿà¬°àଡ ଞàଠà¬à¬°à¬¿à¬¬à?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ପଟà¬à¬ ଞଟà¬à¬š-à¬à¬šà¬° ଞàà¬à¬šà¬Ÿ ଞàଠà¬à¬°à¬¿à¬¬à?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ପଟଞà¬à"</string>
<string name="password" msgid="6738570945182936667">"ପଟଞà±à¬Ÿà¬°àଡ"</string>
<string name="passkeys" msgid="5733880786866559847">"ପଟଞà¬àà¬àଡଌିà¬"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"à¬à¬Ÿà¬°à¬ à¬à¬°à¬šà଀à"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପଟà¬à¬ ଞàଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ à¬à¬ªà¬£à¬àଠପଟଞà¬à ବààବହଟର à¬à¬°à¬¿à¬¬à?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପଟà¬à¬ à¬à¬ªà¬£à¬àଠଞàଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ ପଟଞà±à¬Ÿà¬°àଡà¬à ବààବହଟର à¬à¬°à¬¿à¬¬à?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପଟà¬à¬ à¬à¬ªà¬£à¬àଠଞଟà¬à¬š-à¬à¬š ବààବହଟର à¬à¬°à¬¿à¬¬à?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପଟà¬à¬ ଞଟà¬à¬š-à¬à¬š ବିà¬à¬³àପà¬àଡଌିà¬à à¬
ଚଲଠà¬à¬°à¬¿à¬¬à?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପଟà¬à¬ ଞàଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ à¬à¬ ପଟଞà¬à ବଟà¬à¬šà଀à"</string>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 8328d47..aba05c4 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"àš¹àšŸàš²àšŸàšàšàš¿, àš
àšžà©àš àšªàšŸàšžàšµàš°àš¡ àš°àš¹àš¿àš€ àšàšµàš¿à©±àš àšµà©±àš² àšµàš§ àš°àš¹à© àš¹àšŸàš, àšªàš° àšªàšŸàšžàšà©àšàš àšŠà© àššàšŸàš² àšªàšŸàšžàšµàš°àš¡ àš¹àšŸàš²à© àšµà© àšàšªàš²àš¬àš§ àš¹à©àš£àšà©à¥€"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"àšà©àš£à© àšàš¿ àšàšªàš£à©àšàš <xliff:g id="CREATETYPES">%1$s</xliff:g> àššà©à©° àšàš¿à©±àš¥à© àš°à©±àšàš¿àš
àš€ àšàš°àššàšŸ àš¹à©"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"àšàšªàš£à© àšàšŸàš£àšàšŸàš°à© àššà©à©° àš°à©±àšàš¿àš
àš€ àšàš°àšš àš
àš€à© àš
àšàš²à© àšµàšŸàš° àš€à©àšàšŒà© àššàšŸàš² àšžàšŸàšàšš-àšàšš àšàš°àšš àš²àš àšªàšŸàšžàšµàš°àš¡ àšªà©àš°àš¬à©°àš§àš àšà©àš£à©"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"àšà© <xliff:g id="APPNAME">%1$s</xliff:g> àšµàš¿à©±àš àšžàšŸàšàšš-àšàšš àšàš°àšš àš²àš àšªàšŸàšžàšà© àš¬àš£àšŸàšàš£à© àš¹à©?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"àšà© <xliff:g id="APPNAME">%1$s</xliff:g> àšµàš¿à©±àš àšžàšŸàšàšš-àšàšš àšàš°àšš àš²àš àšªàšŸàšžàšµàš°àš¡ àš°à©±àšàš¿àš
àš€ àšàš°àššàšŸ àš¹à©?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"àšà© <xliff:g id="APPNAME">%1$s</xliff:g> àš²àš àšžàšŸàšàšš-àšàšš àšàšŸàš£àšàšŸàš°à© àš°à©±àšàš¿àš
àš€ àšàš°àššà© àš¹à©?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àšªàšŸàšžàšà©"</string>
<string name="password" msgid="6738570945182936667">"àšªàšŸàšžàšµàš°àš¡"</string>
<string name="passkeys" msgid="5733880786866559847">"àšªàšŸàšžàšà©àšàš"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àšàšŸàš°àš àšàš°à©"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"àšà© <xliff:g id="APP_NAME">%1$s</xliff:g> àš²àš àšàšªàš£à© àš°à©±àšàš¿àš
àš€ àšà©àš€à© àšªàšŸàšžàšà© àšŠà© àšµàš°àš€à©àš àšàš°àššà© àš¹à©?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"àšà© <xliff:g id="APP_NAME">%1$s</xliff:g> àš²àš àš€à©àš¹àšŸàš¡àšŸ àš°à©±àšàš¿àš
àš€ àšà©àš€àšŸ àšªàšŸàšžàšµàš°àš¡ àšµàš°àš€àš£àšŸ àš¹à©?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"àšà© <xliff:g id="APP_NAME">%1$s</xliff:g> àš²àš àšàšªàš£àšŸ àšžàšŸàšàšš-àšàšš àšàš°àšš àšŠàšŸ àšµàš¿àšàš²àšª àšµàš°àš€àš£àšŸ àš¹à©?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"àšà© <xliff:g id="APP_NAME">%1$s</xliff:g> àš²àš àšžàšŸàšàšš-àšàšš àšµàš¿àšàš²àšªàšŸàš àššà©à©° àš
àš£àš²àšŸàš àšàš°àššàšŸ àš¹à©?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> àš²àš àšà©àš àš°à©±àšàš¿àš
àš€ àšà©àš€à© àšªàšŸàšžàšà© àšà©àš£à©"</string>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index 7114c3a..4a4a9fa 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"W czasie przechodzenia na technologie niewymagajÄ
ce haseÅ moÅŒliwoÅÄ stosowania haseÅ – niezaleÅŒnie od kluczy dostÄpu – wciÄ
ÅŒ bÄdzie dostÄpna."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Wybierz, gdzie zapisywaÄ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Wybierz menedÅŒera haseÅ, aby zapisywaÄ informacje i logowaÄ siÄ szybciej"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"UtworzyÄ klucz dostÄpu do logowania w aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ZapisaÄ hasÅo do logowania w aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ZapisaÄ dane logowania do aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"klucz"</string>
<string name="password" msgid="6738570945182936667">"hasÅo"</string>
<string name="passkeys" msgid="5733880786866559847">"klucze dostÄpu"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Zamknij"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"UÅŒyÄ zapisanego klucza dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"UÅŒyÄ zapisanego hasÅa do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"UÅŒyÄ tych danych logowania do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"OdblokowaÄ opcje logowania do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Wybierz zapisany klucz dostÄpu do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index 0b03f72..f2e84c1 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Estamos avançando em direção a um futuro sem senhas, mas elas ainda vão estar disponíveis junto às chaves de acesso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Criar chave de acesso para fazer login no app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Salvar senha para fazer login no app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
<string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dispensar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Usar a senha salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Usar seu login para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Desbloquear opções de login para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Escolha uma chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index b4cf374..f95927b 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"À medida que avançamos para um futuro sem palavras-passe, as palavras-passe continuam disponíveis juntamente com as chaves de acesso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde guardar as suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gestor de palavras-passe para guardar as suas informações e iniciar sessão mais rapidamente da próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Criar a chave de acesso para iniciar sessão na app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Guardar a palavra-passe para iniciar sessão na app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Guardar as informações de início de sessão da app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"palavra-passe"</string>
<string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Ignorar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar a sua chave de acesso guardada na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Usar a sua palavra-passe guardada para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Usar o seu início de sessão para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Desbloquear as opções de início de sessão para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Escolha uma chave de acesso guardada para a app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index 0b03f72..f2e84c1 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Estamos avançando em direção a um futuro sem senhas, mas elas ainda vão estar disponíveis junto às chaves de acesso."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Criar chave de acesso para fazer login no app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Salvar senha para fazer login no app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
<string name="password" msgid="6738570945182936667">"senha"</string>
<string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Dispensar"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Usar a senha salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Usar seu login para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Desbloquear opções de login para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Escolha uma chave de acesso salva para o app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 8c865c4..c77c3b2 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Ne îndreptÄm spre un viitor fÄrÄ parole, însÄ acestea sunt încÄ disponibile, alÄturi de cheile de acces."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Alege unde doreÈti sÄ salvezi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"SelecteazÄ un manager de parole pentru a salva informaÈiile Èi a te conecta mai rapid data viitoare"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Creezi o cheie de acces pentru a te conecta la <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Salvezi parola pentru a te conecta la <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvezi informaÈiile de conectare pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"cheia de acces"</string>
<string name="password" msgid="6738570945182936667">"parolÄ"</string>
<string name="passkeys" msgid="5733880786866559847">"cheile de acces"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Închide"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"FoloseÈti cheia de acces salvatÄ pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"FoloseÈti parola salvatÄ pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"FoloseÈti datele de conectare pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Deblochezi opÈiunile de conectare pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Alege o cheie de acces salvatÄ pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index 92eea32..001587d 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ХПÑÑ ÐŽÐ²ÐžÐ¶ÐµÐœÐžÐµ к бÑÐŽÑÑÐµÐŒÑ Ð±ÐµÐ· паÑПлей Ñже МаÑалПÑÑ, ОÑ
пП-пÑÐµÐ¶ÐœÐµÐŒÑ ÐŒÐŸÐ¶ÐœÐŸ бÑÐŽÐµÑ ÐžÑпПлÑзПваÑÑ ÐœÐ°ÑÑÐŽÑ Ñ ÐºÐ»ÑÑаЌО ЎПÑÑÑпа."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"УкажОÑе, кÑЎа МÑжМП ÑПÑ
ÑаМОÑÑ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐÑбеÑОÑе ÐŒÐµÐœÐµÐŽÐ¶ÐµÑ Ð¿Ð°ÑПлей, ÑÑÐŸÐ±Ñ ÑПÑ
ÑаМÑÑÑ ÑÑеÑМÑе ЎаММÑе О бÑÑÑÑП вÑпПлМÑÑÑ Ð²Ñ
ПЎ."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"СПзЎаÑÑ ÐºÐ»ÑÑ ÐŽÐŸÑÑÑпа ÐŽÐ»Ñ Ð²Ñ
ПЎа в пÑОлПжеМОе \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"СПÑ
ÑаМОÑÑ ÐºÐ»ÑÑ ÐŽÐŸÑÑÑпа ÐŽÐ»Ñ Ð²Ñ
ПЎа в пÑОлПжеМОе \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"СПÑ
ÑаМОÑÑ ÑÑеÑМÑе ЎаММÑе ÐŽÐ»Ñ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"клÑÑ ÐŽÐŸÑÑÑпа"</string>
<string name="password" msgid="6738570945182936667">"паÑПлÑ"</string>
<string name="passkeys" msgid="5733880786866559847">"клÑÑО ЎПÑÑÑпа"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐакÑÑÑÑ"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ÐÑпПлÑзПваÑÑ ÑПÑ
ÑаМеММÑй клÑÑ ÐŽÐŸÑÑÑпа ÐŽÐ»Ñ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÐÑпПлÑзПваÑÑ ÑПÑ
ÑаМеММÑй паÑÐŸÐ»Ñ ÐŽÐ»Ñ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ÐПйÑО в пÑОлПжеМОе \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" Ñ ÑÑОЌО ЎаММÑЌО?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"РазблПкОÑПваÑÑ Ð²Ð°ÑОаМÑÑ Ð²Ñ
ПЎа ÐŽÐ»Ñ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐÑбеÑОÑе ÑПÑ
ÑаМеММÑй клÑÑ ÐŽÐŸÑÑÑпа ÐŽÐ»Ñ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index ec47018..612083f 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à¶
à¶Žà· à¶žà·à¶»à¶Žà¶¯ à¶»à·à·à¶ à¶
à¶±à·à¶à¶à¶ºà¶à· à¶à¶»à· à¶à¶žà¶±à· à¶à¶»à¶± à·à·à¶§, à¶žà·à¶»à¶ºà¶à·à¶»à· à·à¶žà¶ à¶žà·à¶»à¶Žà¶¯ à¶à·à¶žà¶à· à¶Žà·à¶à·."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à¶à¶¶à· <xliff:g id="CREATETYPES">%1$s</xliff:g> à·à·à¶»à·à¶à·à¶º යà·à¶à· à·à·à¶®à·à¶±à¶º à¶à·à¶»à· à¶à¶±à·à¶±"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à¶à¶¶à· à¶à¶à· à·à·à¶»à·à¶à·à¶žà¶§ à·à· à¶žà·à·
à¶ à·à¶à·à·à· à·à·à¶à¶ºà·à¶±à· à¶Žà·à¶»à¶±à¶º à·à·à¶žà¶§ à¶žà·à¶»à¶Žà¶¯ à¶à·
à¶žà¶±à·à¶à¶»à·à·à·à¶à· à¶à·à¶»à¶±à·à¶±"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> à·à·à¶ à¶Žà·à¶»à¶±à¶º à·à·à¶žà¶§ à¶žà·à¶»à¶ºà¶à·à¶»à¶à· à¶à¶±à¶±à·à¶± ද?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> à·à·à¶ à¶Žà·à¶»à¶±à¶º à·à·à¶žà¶§ à¶žà·à¶»à¶Žà¶¯à¶º à·à·à¶»à¶à·à¶±à·à¶± ද?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à·à¶³à·à· à¶Žà·à¶»à¶±à¶º à·à·à¶žà· à¶à¶à· à·à·à¶»à¶à·à¶±à·à¶± ද?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"à¶žà·à¶»à¶ºà¶à·à¶»"</string>
<string name="password" msgid="6738570945182936667">"à¶žà·à¶»à¶Žà¶¯à¶º"</string>
<string name="passkeys" msgid="5733880786866559847">"à¶žà·à¶»à¶ºà¶à·à¶»à·"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"à¶
à·à· à¶à¶»à¶±à·à¶±"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> à·à¶³à·à· à¶à¶¶à· à·à·à¶»à·à¶à· à¶žà·à¶»à¶ºà¶à·à¶» à¶·à·à·à·à¶à· à¶à¶»à¶±à·à¶± ද?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> à·à¶³à·à· à¶à¶¶à· à·à·à¶»à·à¶à· à¶žà·à¶»à¶Žà¶¯à¶º à¶·à·à·à·à¶ à¶à¶»à¶±à·à¶± ද?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à·à¶³à·à· à¶à¶¶à· à¶Žà·à¶»à¶±à¶º à·à·à¶ž à¶·à·à·à·à¶à· à¶à¶»à¶±à·à¶± ද?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à·à¶³à·à· à¶Žà·à¶»à¶± à·à·à¶à¶œà·à¶Ž à¶
à¶à·à¶œà· à·à¶»à·à¶±à·à¶± ද?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à·à¶³à·à· à·à·à¶»à¶à·à¶± ගද à¶žà·à¶»à¶ºà¶à·à¶»à¶à· à¶à·à¶»à¶±à·à¶±"</string>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 7426c97..67d91c8 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"BlíÅŸime sa k budúcnosti bez hesiel, ale heslá budú popri prístupových kÄŸúÄoch stále k dispozícii."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Vyberte, kam sa majú ukladaÅ¥ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správcu hesiel, do ktorého sa budú ukladaÅ¥ vaše údaje, aby ste sa nabudúce mohli rýchlejšie prihlásiÅ¥"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Chcete vytvoriÅ¥ prístupový kÄŸúÄ na prihlasovanie do aplikácie <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Chcete uloÅŸiÅ¥ heslo na prihlasovanie do aplikácie <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Chcete uloÅŸiÅ¥ prihlasovacie údaje pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"prístupový kÄŸúÄ"</string>
<string name="password" msgid="6738570945182936667">"heslo"</string>
<string name="passkeys" msgid="5733880786866559847">"prístupové kÄŸúÄe"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Zavrieť"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> pouÅŸiÅ¥ uloÅŸený prístupový kÄŸúÄ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Chcete pouÅŸiÅ¥ uloÅŸené heslo aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Chcete pouÅŸiÅ¥ svoje prihlásenie pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Chcete odomknúÅ¥ moÅŸnosti prihlásenia pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Vyberte uloÅŸený prístupový kÄŸúÄ pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 8e08512..2c237ed 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Na poti v prihodnost brez gesel bodo poleg kljuÄev za dostop še vedno v uporabi tudi gesla."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Izbira mesta za shranjevanje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Izberite upravitelja gesel za shranjevanje podatkov za prijavo, da se boste naslednjiÄ lahko hitreje prijavili."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Åœelite ustvariti kljuÄ za dostop za prijavo v aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Åœelite shraniti geslo za prijavo v aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Åœelite shraniti podatke za prijavo za aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"kljuÄ za dostop"</string>
<string name="password" msgid="6738570945182936667">"geslo"</string>
<string name="passkeys" msgid="5733880786866559847">"kljuÄi za dostop"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Opusti"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Åœelite uporabiti shranjeni kljuÄ za dostop do aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Ali ÅŸelite uporabiti shranjeno geslo za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Åœelite uporabiti svojo prijavo za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Åœelite odkleniti moÅŸnosti prijave za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Izberite shranjeni kljuÄ za dostop za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index 96f1ff0..71fb2f5 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Teksa shkojmë drejt një të ardhmeje pa fjalëkalime, këto të fundit do të ofrohen ende së bashku me çelësat e kalimit."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Zgjidh se ku t\'i ruash <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Zgjidh një menaxher fjalëkalimesh për të ruajtur informacionet e tua dhe për t\'u identifikuar më shpejt herën tjetër"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Të krijohet një çelës kalimit për t\'u identifikuar në <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Të ruhet fjalëkalimi për t\'u identifikuar në <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Të ruhen informacionet e identifikimit për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"çelësin e kalimit"</string>
<string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>
<string name="passkeys" msgid="5733880786866559847">"çelësat e kalimit"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Hiq"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Të përdoret fjalëkalimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Të përdoret fjalëkalimi i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Të përdoret identifikimi yt për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Të shkyçen opsionet e identifikimit për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Zgjidh një çelës kalimi të ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index dae62bc..8cd0463 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÐакП Ñе кÑеÑеЌП ка бÑÐŽÑÑМПÑÑО без лПзОМкО, лПзОМке Ñе О ЎаÑе бОÑО ЎПÑÑÑпМе Ñз пÑОÑÑÑпМе кПЎПве."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÐЎабеÑОÑе гЎе ÑеÑе ÑаÑÑваÑО: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐзабеÑОÑе ЌеМаÑеÑа лПзОМкО Ўа бОÑÑе ÑаÑÑвалО пПЎаÑке О бÑже Ñе пÑОÑавОлО ÑлеЎеÑО пÑÑ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"ÐелОÑе Ўа МапÑавОÑе пÑОÑÑÑпМО кÑÑÑ ÐŽÐ° бОÑÑе Ñе пÑОÑавОлО Ñ <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÐелОÑе Ўа ÑаÑÑваÑе Ð»ÐŸÐ·ÐžÐœÐºÑ ÐŽÐ° бОÑÑе Ñе пÑОÑавОлО Ñ <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ÐелОÑе Ўа ÑаÑÑваÑе пПЎаÑке за пÑОÑавÑОваÑе за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"пÑОÑÑÑпМО кôÐŽ"</string>
<string name="password" msgid="6738570945182936667">"лПзОМка"</string>
<string name="passkeys" msgid="5733880786866559847">"пÑОÑÑÑпМО кПЎПвО"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐЎбаÑО"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ÐелОÑе Ўа кПÑОÑÑОÑе ÑаÑÑваМО пÑОÑÑÑпМО кôÐŽ за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÐелОÑе Ўа кПÑОÑÑОÑе ÑаÑÑÐ²Ð°ÐœÑ Ð»ÐŸÐ·ÐžÐœÐºÑ Ð·Ð°: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ÐелОÑе лО Ўа кПÑОÑÑОÑе ÑвПÑе пПЎаÑке за пÑОÑавÑОваÑе за аплОкаÑОÑÑ <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"ÐелОÑе Ўа ПÑкÑÑÑаÑе ПпÑОÑе пÑОÑавÑОваÑа за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐзабеÑОÑе ÑаÑÑваМ пÑОÑÑÑпМО кÑÑÑ Ð·Ð°: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index 2326497..bb6ae3f 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Medan vi beger oss mot en lösenordslös framtid kommer lösenord fortfarande att vara tillgängliga utöver nycklar."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Välj var du vill spara <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Välj en lösenordshanterare för att spara dina uppgifter och logga in snabbare nästa gång"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Vill du skapa en nyckel för att logga in i <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Vill du spara lösenordet för att logga in i <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vill du spara inloggningsuppgifterna för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"nyckel"</string>
<string name="password" msgid="6738570945182936667">"lösenord"</string>
<string name="passkeys" msgid="5733880786866559847">"nycklar"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Stäng"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vill du använda din sparade nyckel för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Vill du använda det sparade lösenordet för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Vill du använda din inloggning för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vill du låsa upp inloggningsalternativ för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Välj en sparad nyckel för <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index 6c39509..1a7a75e 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Tunavyoelekea katika enzi isiyo ya manenosiri, manenosiri yataendelea kupatikana pamoja na funguo za siri."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Chagua ambako unahifadhi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Chagua kidhibiti cha manenosiri ili uhifadhi taarifa zako na uingie kwenye akaunti kwa urahisi wakati mwingine"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Ungependa kuunda ufunguo wa siri ili uingie katika <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Ungependa kuhifadhi nenosiri ili uingie katika <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ungependa kuhifadhi maelezo ya kuingia katika akaunti kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>
<string name="password" msgid="6738570945182936667">"nenosiri"</string>
<string name="passkeys" msgid="5733880786866559847">"funguo za siri"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Ondoa"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ungependa kutumia ufunguo wa siri uliohifadhiwa wa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Je, ungependa kutumia nenosiri lako lililohifadhiwa kuingia katika <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Ungependa kutumia kitambulisho chako cha kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Je, ungependa kuona chaguo za kuingia katika <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Chagua ufunguo wa siri uliohifadhiwa ambao ungependa kutumia kuingia katika <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index 6feb66f..7a4ed5a 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à®à®à®µà¯à®à¯à®à¯à®²à¯à®²à®±à¯à®± à®à®€à®¿à®°à¯à®à®Ÿà®²à®€à¯à®€à¯ சà¯à®à¯à®à®¿ சடம௠பயணிà®à¯à®à®¿à®±à¯à®®à¯. à®à®à®µà¯à®à¯à®à®Ÿà®µà®¿à®à®³à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à¯à®®à¯ à®à®€à¯ வà¯à®³à¯à®¯à®¿à®²à¯ à®à®à®µà¯à®à¯à®à¯à®±à¯à®à®³à¯à®¯à¯à®®à¯ பயனà¯à®ªà®à¯à®€à¯à®€ à®®à¯à®à®¿à®¯à¯à®®à¯."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à®à®à¯à®à®³à¯ <xliff:g id="CREATETYPES">%1$s</xliff:g> à®à®à¯à®à¯ à®à¯à®®à®¿à®à¯à®à®ªà¯à®ªà® வà¯à®£à¯à®à¯à®®à¯ à®à®©à¯à®ªà®€à¯à®€à¯ ஀à¯à®°à¯à®µà¯à®à¯à®¯à¯à®¯à¯à®à¯à®à®³à¯"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à®à®à¯à®à®³à¯ ஀à®à®µà®²à¯à®à®³à¯à®à¯ à®à¯à®®à®¿à®€à¯à®€à¯ à®
à®à¯à®€à¯à®€ à®®à¯à®±à¯ விரà¯à®µà®Ÿà® à®à®³à¯à®šà¯à®Žà¯à®¯ à®à®°à¯ à®à®à®µà¯à®à¯à®à¯à®²à¯ சிரà¯à®µà®Ÿà®à®¿à®¯à¯à®€à¯ ஀à¯à®°à¯à®µà¯à®à¯à®¯à¯à®¯à¯à®à¯à®à®³à¯"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> à®à®ªà¯à®žà®¿à®²à¯ à®à®³à¯à®šà¯à®Žà¯à®¯ à®à®à®µà¯à®à¯à®à®Ÿà®µà®¿à®¯à¯ à®à®°à¯à®µà®Ÿà®à¯à®à®µà®Ÿ?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> à®à®ªà¯à®žà®¿à®²à¯ à®à®³à¯à®šà¯à®Žà¯à®¯ à®à®à®µà¯à®à¯à®à¯à®²à¯à®²à¯à®à¯ à®à¯à®®à®¿à®à¯à®à®µà®Ÿ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à®Ÿà®© à®à®³à¯à®šà¯à®Žà¯à®µà¯ விவரà®à¯à®à®³à¯à®à¯ à®à¯à®®à®¿à®à¯à®à®µà®Ÿ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"à®à®à®µà¯à®à¯à®à®Ÿà®µà®¿"</string>
<string name="password" msgid="6738570945182936667">"à®à®à®µà¯à®à¯à®à¯à®²à¯"</string>
<string name="passkeys" msgid="5733880786866559847">"à®à®à®µà¯à®à¯à®à®Ÿà®µà®¿à®à®³à¯"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"சிரடà®à®°à®¿à®à¯à®à¯à®®à¯"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à¯ à®à®±à¯à®à¯à®©à®µà¯ à®à¯à®®à®¿à®à¯à®à®ªà¯à®ªà®à¯à® à®à®à®µà¯à®à¯à®à¯à®±à®¿à®¯à¯à®à¯à®à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à®µà®Ÿ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à¯à®à¯ à®à¯à®®à®¿à®€à¯à®€ à®à®à®µà¯à®à¯à®à¯à®²à¯à®²à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à®µà®Ÿ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à¯ à®à®à¯à®à®³à¯ à®à®³à¯à®šà¯à®Žà¯à®µà¯ விவரà®à¯à®à®³à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à®µà®Ÿ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à®Ÿà®© à®à®³à¯à®šà¯à®Žà¯à®µà¯ விரà¯à®ªà¯à®ªà®à¯à®à®³à¯ à®
னà¯à®²à®Ÿà®à¯ à®à¯à®¯à¯à®¯à®µà®Ÿ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à®à®ªà¯à®žà¯à®à¯à®à®Ÿà®© à®à¯à®®à®¿à®à¯à®à®ªà¯à®ªà®à¯à® à®à®à®µà¯à®à¯à®à®Ÿà®µà®¿à®¯à¯à®€à¯ ஀à¯à®°à¯à®šà¯à®€à¯à®à¯à®à¯à®à®³à¯"</string>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index bf3c1e0..f2493c0 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"మచఠà°à°µà°¿à°·à±à°¯à°€à±à°€à±à°²à± పటఞà±à°µà°°à±à°¡à± రహిఀ à°à±à°à±à°šà°Ÿà°²à°à±à°šà°¿ à°à°ªà°¯à±à°à°¿à°à°à°¿à°šà°Ÿ, పటఞà±à°à±à°²à°€à± పటà°à± పటఞà±à°µà°°à±à°¡à±à°²à± à°à±à°¡à°Ÿ à°
à°à°Šà±à°¬à°Ÿà°à±à°²à± à°à°à°à°Ÿà°¯à°¿."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"మౠ<xliff:g id="CREATETYPES">%1$s</xliff:g> à°à°à±à°à°¡ à°žà±à°µà± à°à±à°¯à°Ÿà°²à± à°à°à°à±à°à±à°à°¡à°¿"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ఀరà±à°µà°Ÿà°€à°¿à°žà°Ÿà°°à°¿ మరిà°à°€ à°µà±à°à°à°à°Ÿ à°žà±à°šà± à°à°šà± à°à±à°žà±à°à°Šà±à°à± à°µà±à°²à±à°à°Ÿ మౠఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ à°žà±à°µà± à°à±à°¯à°¡à° à°à±à°žà° à°à° పటఞà±à°µà°°à±à°¡à± à°®à±à°šà±à°à°°à±à°šà± à°à°à°à±à°à±à°à°¡à°¿"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g>à°à± à°žà±à°šà± à°à°šà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ పటఞà±-à°à±à°šà°¿ à°à±à°°à°¿à°¯à±à°à± à°à±à°¯à°Ÿà°²à°Ÿ?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g>à°à± à°žà±à°šà± à°à°šà± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ పటఞà±à°µà°°à±à°¡à±à°šà± à°žà±à°µà± à°à±à°¯à°Ÿà°²à°Ÿ?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> à°à±à°žà° à°žà±à°šà± à°à°šà± ఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ à°žà±à°µà± à°à±à°¯à°Ÿà°²à°Ÿ?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"పటఞà±-à°à±"</string>
<string name="password" msgid="6738570945182936667">"పటఞà±à°µà°°à±à°¡à±"</string>
<string name="passkeys" msgid="5733880786866559847">"పటఞà±-à°à±à°²à±"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"విఞà±à°®à°°à°¿à°à°à°à°¡à°¿"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> à°à±à°žà° మౠఞà±à°µà± à°à±à°žà°¿à°š పటఞà±-à°à±à°šà°¿ à°à°ªà°¯à±à°à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> à°à±à°žà° మౠఞà±à°µà± à°à±à°žà°¿à°š పటఞà±à°µà°°à±à°¡à±à°šà± à°à°ªà°¯à±à°à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> à°à±à°žà° మౠఞà±à°šà± à°à°šà± వివరటలచౠà°à°ªà°¯à±à°à°¿à°à°à°Ÿà°²à°Ÿ?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> à°à±à°žà° à°žà±à°šà± à°à°šà± à°à°ªà±à°·à°šà±à°²à°šà± à°
à°šà±à°²à°Ÿà°à± à°à±à°¯à°Ÿà°²à°Ÿ?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> à°à±à°žà° à°žà±à°µà± à°à±à°žà°¿à°š పటఞà±-à°à±à°šà°¿ à°à°à°à±à°à±à°à°¡à°¿"</string>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index 4fc8ba0e..1e08088 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"à¹àžàžàžàž°àžàžµà¹à¹àž£àž²àžà¹àž²àž§à¹àžàžªàž¹à¹àžàžàž²àžàžàžàžµà¹à¹àž¡à¹àžà¹àžàžà¹àžà¹àž£àž«àž±àžªàžà¹àž²àžàžàž±à¹àž àž£àž«àž±àžªàžà¹àž²àžàžàž°àž¢àž±àžàžàžà¹àžà¹à¹àžà¹àžàž¢àž¹à¹àžàž§àžàžàž¹à¹à¹àžàžàž±àžàžàž²àž£à¹àžàž¥àžµà¹àž¢àžà¹àžà¹àžà¹àžàž²àžªàžàžµàž¢à¹"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"à¹àž¥àž·àžàžàž§à¹àž²àžà¹àžàžàžàž²àž£àžàž±àžàžàž¶àž<xliff:g id="CREATETYPES">%1$s</xliff:g>à¹àž§à¹àžàžµà¹à¹àž"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"à¹àž¥àž·àžàžà¹àžàž£àž·à¹àžàžàž¡àž·àžàžàž±àžàžàž²àž£àž£àž«àž±àžªàžà¹àž²àžà¹àžàž·à¹àžàžàž±àžàžàž¶àžàžà¹àžàž¡àž¹àž¥à¹àž¥àž°àž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹à¹àž£à¹àž§àžàž¶à¹àžà¹àžàžàž£àž±à¹àžàžàž±àžà¹àž"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"àžªàž£à¹àž²àžàžàž²àžªàžàžµàž¢à¹à¹àžàž·à¹àžàž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹ <xliff:g id="APPNAME">%1$s</xliff:g> à¹àž«àž¡"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"àžàž±àžàžàž¶àžàž£àž«àž±àžªàžà¹àž²àžà¹àžàž·à¹àžàž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹ <xliff:g id="APPNAME">%1$s</xliff:g> à¹àž«àž¡"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"àžàž±àžàžàž¶àžàžà¹àžàž¡àž¹àž¥àžàž²àž£àž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹àžªàž³àž«àž£àž±àž <xliff:g id="APPNAME">%1$s</xliff:g> à¹àž«àž¡"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"àžàž²àžªàžàžµàž¢à¹"</string>
<string name="password" msgid="6738570945182936667">"àž£àž«àž±àžªàžà¹àž²àž"</string>
<string name="passkeys" msgid="5733880786866559847">"àžàž²àžªàžàžµàž¢à¹"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"àžàžŽàž"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"à¹àžà¹àžàž²àžªàžàžµàž¢à¹àžàžµà¹àžàž±àžàžàž¶àžà¹àž§à¹àžªàž³àž«àž£àž±àž <xliff:g id="APP_NAME">%1$s</xliff:g> à¹àžà¹à¹àž«àž¡"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"à¹àžà¹àž£àž«àž±àžªàžà¹àž²àžàžàžµà¹àžàž±àžàžàž¶àžà¹àž§à¹àžªàž³àž«àž£àž±àž <xliff:g id="APP_NAME">%1$s</xliff:g> à¹àžà¹à¹àž«àž¡"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"à¹àžà¹àžàž²àž£àž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹àžªàž³àž«àž£àž±àž <xliff:g id="APP_NAME">%1$s</xliff:g> à¹àžà¹à¹àž«àž¡"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"àžàž¥àžàž¥à¹àžàžàžàž±àž§à¹àž¥àž·àžàžàžàž²àž£àž¥àžàžàž·à¹àžà¹àžà¹àž²à¹àžà¹àžªàž³àž«àž£àž±àž <xliff:g id="APP_NAME">%1$s</xliff:g> à¹àžà¹à¹àž«àž¡"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"à¹àž¥àž·àžàžàžàž²àžªàžàžµàž¢à¹àžàžµà¹àžàž±àžàžàž¶àžà¹àž§à¹àžªàž³àž«àž£àž±àž <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index e6bcadd..a3bdc8f 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Habang lumalayo tayo sa mga password, magiging available pa rin ang mga password kasama ng mga passkey."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Piliin kung saan mo ise-save ang iyong <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Pumili ng password manager para ma-save ang iyong impormasyon at makapag-sign in nang mas mabilis sa susunod na pagkakataon"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Gumawa ng passkey para mag-sign in sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"I-save ang password para mag-sign in sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"I-save ang impormasyon sa pag-sign in para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"passkey"</string>
<string name="password" msgid="6738570945182936667">"password"</string>
<string name="passkeys" msgid="5733880786866559847">"mga passkey"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"I-dismiss"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gamitin ang iyong naka-save na passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Gamitin ang iyong naka-save na password para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Gamitin ang iyong sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"I-unlock ang mga opsyon sa pag-sign in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Pumili ng naka-save na passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index f9455e7..9a05d2a 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Åifresiz bir geleceÄe doÄru ilerlerken Åifreler, geçiÅ anahtarlarıyla birlikte kullanılmaya devam edecektir."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> kaydedileceÄi yeri seçin"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Bilgilerinizi kaydedip bir dahaki sefere daha hızlı oturum açmak için bir Åifre yöneticisi seçin"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasında oturum açmak için geçiÅ anahtarı oluÅturulsun mu?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasında oturum açmak için Åifre kaydedilsin mi?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> için oturum açma bilgileri kaydedilsin mi?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"GeçiÅ anahtarı"</string>
<string name="password" msgid="6738570945182936667">"Åifre"</string>
<string name="passkeys" msgid="5733880786866559847">"GeçiÅ anahtarlarınızın"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Kapat"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı geçiÅ anahtarınız kullanılsın mı?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı Åifreniz kullanılsın mı?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> için oturum açma bilgileriniz kullanılsın mı?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> için oturum açma seçeneklerine izin verilsin mi?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı bir geçiÅ anahtarı kullanın"</string>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index e804777..9781020 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Ðа ÑлÑÑ
Ñ ÐŽÐŸ безпаÑПлÑМПгП ЌайбÑÑМÑПгП паÑÐŸÐ»Ñ Ð¹ ÐœÐ°ÐŽÐ°Ð»Ñ Ð±ÑÐŽÑÑÑ Ð²ÐžÐºÐŸÑОÑÑПвÑваÑОÑÑ Ð¿Ð°ÑалелÑМП з клÑÑаЌО ЎПÑÑÑпÑ."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"ÐОбеÑÑÑÑ, Ўе збеÑÑгаÑО <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"ÐОбеÑÑÑÑ ÐŒÐµÐœÐµÐŽÐ¶ÐµÑ Ð¿Ð°ÑПлÑв, ÑПб збеÑÑгаÑО ÑÐ²ÐŸÑ ÐŽÐ°ÐœÑ Ð¹ ÐœÐ°ÐŽÐ°Ð»Ñ Ð²Ñ
ПЎОÑО в ПблÑÐºÐŸÐ²Ñ Ð·Ð°Ð¿ÐžÑО ÑвОЎÑе"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"СÑвПÑОÑО клÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ Ð²Ñ
ÐŸÐŽÑ Ð² ЎПЎаÑПк <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"ÐбеÑегÑО паÑÐŸÐ»Ñ ÐŽÐ»Ñ Ð²Ñ
ÐŸÐŽÑ Ð² ЎПЎаÑПк <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ÐбеÑегÑО ÐŽÐ°ÐœÑ ÐŽÐ»Ñ Ð²Ñ
ÐŸÐŽÑ ÐŽÐ»Ñ ÐŽÐŸÐŽÐ°Ñка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"клÑÑ ÐŽÐŸÑÑÑпÑ"</string>
<string name="password" msgid="6738570945182936667">"паÑПлÑ"</string>
<string name="passkeys" msgid="5733880786866559847">"клÑÑÑ ÐŽÐŸÑÑÑпÑ"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ÐакÑОÑО"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ÐОкПÑОÑÑаÑО збеÑежеМОй клÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ ÐŽÐŸÐŽÐ°Ñка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"ÐОкПÑОÑÑаÑО Ð²Ð°Ñ Ð·Ð±ÐµÑежеМОй паÑÐŸÐ»Ñ ÐŽÐ»Ñ ÐŽÐŸÐŽÐ°Ñка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"ÐОкПÑОÑÑПвÑваÑО ваÑÑ ÐŽÐ°ÐœÑ ÐŽÐ»Ñ Ð²Ñ
ÐŸÐŽÑ Ð² ЎПЎаÑПк <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"РПзблПкÑваÑО ПпÑÑÑ Ð²Ñ
ÐŸÐŽÑ ÐŽÐ»Ñ ÐŽÐŸÐŽÐ°Ñка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"ÐОбеÑÑÑÑ Ð·Ð±ÐµÑежеМОй клÑÑ ÐŽÐŸÑÑÑÐ¿Ñ ÐŽÐ»Ñ ÐŽÐŸÐŽÐ°Ñка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index 9562fdf..b4e19bf 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"ÚÙÙÚ©Û ÛÙ
ØšØºÛØ± ٟاس ÙØ±Ú ÙØ§ÙÛ Ù
Ø³ØªÙØšÙ Ú©Û Ø·Ø±Ù Ø¬Ø§ رÛÛ ÛÛÚº اس Ú©Û ØšØ§ÙØ¬Ùد ٟاس ÙØ±Úز ٟاس Ú©ÛØ² Ú©Û Ø³Ø§ØªÚŸ ÛÛ Ø¯Ø³ØªÛØ§Øš ÛÙÚº Ú¯ÛÛ"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Ù
ÙØªØ®Øš کرÛÚº Ú©Û Ø¢ÙŸ Ú©Û <xliff:g id="CREATETYPES">%1$s</xliff:g> Ú©Ù Ú©ÛØ§Úº Ù
ØÙÙØž Ú©Ø±ÙØ§ ÛÛ"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"اٟÙÛ Ù
عÙÙÙ
ات Ú©Ù Ù
ØÙÙØž کرÙÛ Ø§ÙØ± اگÙÛ ØšØ§Ø± ØªÛØ²Û Ø³Û Ø³Ø§ØŠÙ Ø§Ù Ú©Ø±ÙÛ Ú©Û ÙÛÛ ÙŸØ§Ø³ ÙØ±Ú Ù
ÛÙÛØ¬Ø± Ù
ÙØªØ®Øš کرÛÚº"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> Ù
ÛÚº سا؊٠ا٠کرÙÛ Ú©ÛÙØŠÛ ٟاس Ú©Û ØªØ®ÙÛ٠کرÛÚºØ"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> Ù
ÛÚº سا؊٠ا٠کرÙÛ Ú©ÛÙØŠÛ ٟاس ÙØ±Ú Ù
ØÙÙØž کرÛÚºØ"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø³Ø§ØŠÙ Ø§Ù Ú©Û Ù
عÙÙÙ
ات Ù
ØÙÙØž کرÛÚºØ"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ٟاس Ú©Û"</string>
<string name="password" msgid="6738570945182936667">"ٟاس ÙØ±Ú"</string>
<string name="passkeys" msgid="5733880786866559847">"ٟاس Ú©ÛØ²"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"ؚرخاست کرÛÚº"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø§ÙŸÙÛ Ù
ØÙÙØž Ú©Ø±Ø¯Û ÙŸØ§Ø³ Ú©Û Ø§Ø³ØªØ¹Ù
ا٠کرÛÚºØ"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø¢ÙŸ کا Ù
ØÙÙØž Ú©Ø±Ø¯Û ÙŸØ§Ø³ ÙØ±Ú استعÙ
ا٠کرÛÚºØ"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø¢ÙŸ Ú©Û Ø³Ø§ØŠÙ Ø§Ù ØªÙØµÛÙØ§Øª استعÙ
ا٠کرÛÚºØ"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø³Ø§ØŠÙ Ø§Ù Ú©Û Ø§Ø®ØªÛØ§Ø±Ø§Øª Ú©Ù ØºÛØ± Ù
ÙÙ٠کرÛÚºØ"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> Ú©Û ÙÛÛ Ø§ÛÚ© Ù
ØÙÙØž Ú©Ø±Ø¯Û ÙŸØ§Ø³ Ú©Û Ù
ÙØªØ®Øš کرÛÚº"</string>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index 8b9cecd..0811e14 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Parolsiz kelajak sari harakatlanar ekanmiz, parollar kalitlar bilan birga ishlatilishda davom etadi."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Bu <xliff:g id="CREATETYPES">%1$s</xliff:g> qayerga saqlanishini tanlang"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"MaÊŒlumotlaringizni saqlash va keyingi safar tez kirish uchun parollar menejerini tanlang"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasiga kirish uchun kirish kaliti yaratilsinmi?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasiga kirish uchun parol saqlansinmi?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun kirish maÊŒlumoti saqlansinmi?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"kalit"</string>
<string name="password" msgid="6738570945182936667">"parol"</string>
<string name="passkeys" msgid="5733880786866559847">"kalitlar"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Yopish"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan kalit ishlatilsinmi?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan parol ishlatilsinmi?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bu maÊŒlumotlar bilan kirilsinmi?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun kirish usullari ochilsinmi?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan kalitni tanlang"</string>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index c774b93..2550c06 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Trong quá trình chúng tôi hưá»ng Äến tương lai không dùng máºt khẩu, bạn vẫn sẜ dùng ÄÆ°á»£c máºt khẩu cùng vá»i khoá truy cáºp."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Chá»n vá» trí lưu <xliff:g id="CREATETYPES">%1$s</xliff:g> cá»§a bạn"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Hãy chá»n má»t trình quản lý máºt khẩu Äá» lưu thông tin cá»§a bạn và ÄÄng nháºp nhanh hÆ¡n vào lần tá»i"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Tạo khoá truy cáºp Äá» ÄÄng nháºp vào <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Lưu máºt khẩu Äá» ÄÄng nháºp vào <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Lưu thông tin ÄÄng nháºp cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"khoá ÄÄng nháºp"</string>
<string name="password" msgid="6738570945182936667">"máºt khẩu"</string>
<string name="passkeys" msgid="5733880786866559847">"khoá truy cáºp"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Äóng"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Dùng khoá ÄÄng nháºp bạn Äã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Sá» dụng máºt khẩu bạn Äã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Dùng thông tin ÄÄng nháºp cá»§a bạn cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Má» khoá các tuỳ chá»n ÄÄng nháºp cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Chá»n khoá truy cáºp Äã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 11448e9..5cbdf90 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"åšæä»¬åæ å¯ç æªæ¥è¿è¿çè¿çšäžïŒå¯ç ä»äŒäžéè¡å¯é¥å¹¶è¡äœ¿çšã"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"éæ©ä¿å<xliff:g id="CREATETYPES">%1$s</xliff:g>çäœçœ®"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"è¯·éæ©äžæ¬Ÿå¯ç 管çå·¥å
·æ¥ä¿åæšçä¿¡æ¯ïŒä»¥äŸ¿äžæ¬¡æŽå¿«å°ç»åœ"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"èŠå建éè¡å¯é¥ä»¥äŸ¿ç»åœ <xliff:g id="APPNAME">%1$s</xliff:g> åïŒ"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"èŠä¿åå¯ç 以䟿ç»åœ <xliff:g id="APPNAME">%1$s</xliff:g> åïŒ"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"èŠä¿å“<xliff:g id="APPNAME">%1$s</xliff:g>”çç»åœä¿¡æ¯åïŒ"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"éè¡å¯é¥"</string>
<string name="password" msgid="6738570945182936667">"å¯ç "</string>
<string name="passkeys" msgid="5733880786866559847">"éè¡å¯é¥"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"応ç¥"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"èŠäœ¿çšæšäžº“<xliff:g id="APP_NAME">%1$s</xliff:g>”ä¿åçéè¡å¯é¥åïŒ"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"èŠäœ¿çšå·²ä¿åçå¯ç ç»åœ“<xliff:g id="APP_NAME">%1$s</xliff:g>”åïŒ"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"æ¯åŠäœ¿çšæšç<xliff:g id="APP_NAME">%1$s</xliff:g>ç»åœåæ®ç»§ç»ïŒ"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"èŠè§£é“<xliff:g id="APP_NAME">%1$s</xliff:g>”çç»åœé项åïŒ"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"éæ©äžäžªå·²ä¿åçéè¡å¯é¥æ¥ç»åœ“<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index 8f69643..1a8eea7f 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"æåå°ææ¹çšç¡å¯ç¢Œæè¡ïŒèå¯ç¢Œä»å¯èå¯é°äžŠè¡äœ¿çšã"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"éžæå²å<xliff:g id="CREATETYPES">%1$s</xliff:g>çäœçœ®"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"éžåå¯ç¢Œç®¡çå·¥å
·å³å¯å²åèªå·±çè³æïŒçž®çäžæ¬¡ç»å
¥çæé"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"èŠå»ºç«å¯é°ä»¥ç»å
¥ã<xliff:g id="APPNAME">%1$s</xliff:g>ãåïŒ"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"èŠå²åå¯ç¢Œä»¥ç»å
¥ã<xliff:g id="APPNAME">%1$s</xliff:g>ãåïŒ"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"èŠå²åã<xliff:g id="APPNAME">%1$s</xliff:g>ãçç»å
¥è³æåïŒ"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"å¯é°"</string>
<string name="password" msgid="6738570945182936667">"å¯ç¢Œ"</string>
<string name="passkeys" msgid="5733880786866559847">"å¯é°"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"éé"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"èŠäœ¿çšå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯é°åïŒ"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"èŠäœ¿çšå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯ç¢ŒåïŒ"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"èŠä»¥æ€ç»å
¥æ¹åŒäœ¿çšã<xliff:g id="APP_NAME">%1$s</xliff:g>ãåïŒ"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"èŠè§£éã<xliff:g id="APP_NAME">%1$s</xliff:g>ãçç»å
¥éžé
åïŒ"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"éžæå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯é°"</string>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index b5fa62c..a1f353f 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"æåæ¥åŸå°æ¹æ¡ç¡å¯ç¢Œæè¡ïŒå¯ç¢Œä»å¯èå¯ç¢Œéé°äžŠè¡äœ¿çšã"</string>
<string name="choose_provider_title" msgid="8870795677024868108">"éžæèŠå°<xliff:g id="CREATETYPES">%1$s</xliff:g>ååšåªè£¡"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"éžåå¯ç¢Œç®¡çå·¥å
·äžŠå²åè³èšïŒäžæ¬¡å°±èœæŽå¿«ç»å
¥"</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"èŠå»ºç«å¯ç¢Œéé°ä»¥ç»å
¥ã<xliff:g id="APPNAME">%1$s</xliff:g>ãåïŒ"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"èŠå²åå¯ç¢Œä»¥ç»å
¥ã<xliff:g id="APPNAME">%1$s</xliff:g>ãåïŒ"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"èŠå²åã<xliff:g id="APPNAME">%1$s</xliff:g>ãçç»å
¥è³èšåïŒ"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"å¯ç¢Œéé°"</string>
<string name="password" msgid="6738570945182936667">"å¯ç¢Œ"</string>
<string name="passkeys" msgid="5733880786866559847">"å¯ç¢Œéé°"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"éé"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"èŠäœ¿çšå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯ç¢Œéé°åïŒ"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"èŠäœ¿çšå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯ç¢ŒåïŒ"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"èŠäœ¿çšäœ çæèç»å
¥ã<xliff:g id="APP_NAME">%1$s</xliff:g>ãåïŒ"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"èŠè§£éã<xliff:g id="APP_NAME">%1$s</xliff:g>ãçç»å
¥éžé
åïŒ"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"éžæå·²å²åçã<xliff:g id="APP_NAME">%1$s</xliff:g>ãå¯ç¢Œéé°"</string>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index 5915a73..68b98a7 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -39,9 +39,12 @@
<string name="seamless_transition_detail" msgid="4475509237171739843">"Njengoba sibhekela kwikusasa elingenaphasiwedi, amagama ayimfihlo asazotholakala eceleni kokhiye bokudlula."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Khetha lapho ongagcina khona i-<xliff:g id="CREATETYPES">%1$s</xliff:g> yakho"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Khetha isiphathi sephasiwedi ukuze ulondoloze ulwazi lwakho futhi ungene ngemvume ngokushesha ngesikhathi esizayo."</string>
- <string name="choose_create_option_passkey_title" msgid="7980430650778623135">"Sungula ukhiye wokudlula ukuze ungene ngemvume ku-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_password_title" msgid="6238446571944651980">"Londoloza iphasiwedi ukuze ungene ngemvume ku-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Londoloza ulwazi lokungena lwe-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for choose_create_option_passkey_title (8762295821604276511) -->
+ <skip />
+ <!-- no translation found for choose_create_option_password_title (4481366993598649224) -->
+ <skip />
+ <!-- no translation found for choose_create_option_sign_in_title (7092914088455358079) -->
+ <skip />
<string name="passkey" msgid="632353688396759522">"ukhiye wokudlula"</string>
<string name="password" msgid="6738570945182936667">"iphasiwedi"</string>
<string name="passkeys" msgid="5733880786866559847">"okhiye bokudlula"</string>
@@ -70,6 +73,8 @@
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Chitha"</string>
<string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Sebenzisa ukhiye wakho wokungena olondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Sebenzisa iphasiwedi yakho elondoloziwe ye-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <!-- no translation found for get_dialog_title_single_tap_for (2057945648748859483) -->
+ <skip />
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Sebenzisa ukungena kwakho ngemvume ku-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Vula ukungena ngemvume okukhethwa kukho kwe-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Khetha ukhiye wokudlula olondoloziwe we-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 527701c..bc35a85 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -63,11 +63,11 @@
<!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
<string name="choose_provider_body">Select a password manager to save your info and sign in faster next time</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is passkey. [CHAR LIMIT=200] -->
- <string name="choose_create_option_passkey_title">Create passkey to sign in to <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
+ <string name="choose_create_option_passkey_title">Create passkey to sign in to <xliff:g id="app_name" example="Tribank">%1$s</xliff:g>?</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is password. [CHAR LIMIT=200] -->
- <string name="choose_create_option_password_title">Save password to sign in to <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
+ <string name="choose_create_option_password_title">Save password to sign in to <xliff:g id="app_name" example="Tribank">%1$s</xliff:g>?</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is others. [CHAR LIMIT=200] -->
- <string name="choose_create_option_sign_in_title">Save sign-in info for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
+ <string name="choose_create_option_sign_in_title">Save sign-in info for <xliff:g id="app_name" example="Tribank">%1$s</xliff:g>?</string>
<!-- Types which are inserted as a placeholder as credentialTypes for other strings. [CHAR LIMIT=200] -->
<string name="passkey">passkey</string>
<string name="password">password</string>
@@ -122,6 +122,8 @@
<string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved password to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_password_for">Use your saved password for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
+ <!-- This appears as a description of the modal bottom sheet when the single tap sign in flow is used for the get flow. [CHAR LIMIT=200] -->
+ <string name="get_dialog_title_single_tap_for">Use your screen lock to sign in to <xliff:g id="app_name" example="Shrine">%1$s</xliff:g> with <xliff:g id="username" example="beckett-bakery@gmail.com">%2$s</xliff:g></string>
<!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user confirmation to unlock / authenticate (e.g. via fingerprint, faceId, passcode etc.) so that we can retrieve their sign-in options. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/shared/AndroidManifest.xml b/packages/CredentialManager/shared/AndroidManifest.xml
index a460887..51c7fb6 100644
--- a/packages/CredentialManager/shared/AndroidManifest.xml
+++ b/packages/CredentialManager/shared/AndroidManifest.xml
@@ -17,6 +17,6 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.credentialmanager">
+ package="com.android.credentialmanager.shared">
</manifest>
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index 892eabf..f2c252e 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -40,14 +40,15 @@
import androidx.credentials.provider.PublicKeyCredentialEntry
import androidx.credentials.provider.RemoteEntry
import com.android.credentialmanager.IS_AUTO_SELECTED_KEY
-import com.android.credentialmanager.R
import com.android.credentialmanager.model.get.ActionEntryInfo
import com.android.credentialmanager.model.get.AuthenticationEntryInfo
import com.android.credentialmanager.model.get.CredentialEntryInfo
import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.model.get.RemoteEntryInfo
+import com.android.credentialmanager.shared.R
import com.android.credentialmanager.TAG
+import com.android.credentialmanager.model.BiometricRequestInfo
import com.android.credentialmanager.model.EntryInfo
fun EntryInfo.getIntentSenderRequest(
@@ -139,6 +140,7 @@
isDefaultIconPreferredAsSingleProvider =
credentialEntry.isDefaultIconPreferredAsSingleProvider,
affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
+ biometricRequest = predetermineAndValidateBiometricFlow(it),
)
)
}
@@ -167,6 +169,7 @@
isDefaultIconPreferredAsSingleProvider =
credentialEntry.isDefaultIconPreferredAsSingleProvider,
affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
+ biometricRequest = predetermineAndValidateBiometricFlow(it),
)
)
}
@@ -194,6 +197,7 @@
isDefaultIconPreferredAsSingleProvider =
credentialEntry.isDefaultIconPreferredAsSingleProvider,
affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
+ biometricRequest = predetermineAndValidateBiometricFlow(it),
)
)
}
@@ -205,6 +209,36 @@
}
return result
}
+
+/**
+ * This validates if this is a biometric flow or not, and if it is, this returns the expected
+ * [BiometricRequestInfo]. Namely, the biometric flow must have at least the
+ * ALLOWED_AUTHENTICATORS bit passed from Jetpack.
+ * Note that the required values, such as the provider info's icon or display name, or the entries
+ * credential type or userName, and finally the display info's app name, are non-null and must
+ * exist to run through the flow.
+ * // TODO(b/326243754) : Presently, due to dependencies, the opId bit is parsed but is never
+ * // expected to be used. When it is added, it should be lightly validated.
+ */
+private fun predetermineAndValidateBiometricFlow(
+ it: Entry
+): BiometricRequestInfo? {
+ // TODO(b/326243754) : When available, use the official jetpack structured type
+ val allowedAuthenticators: Int? = it.slice.items.firstOrNull {
+ it.hasHint("androidx.credentials." +
+ "provider.credentialEntry.SLICE_HINT_ALLOWED_AUTHENTICATORS")
+ }?.int
+
+ // This is optional and does not affect validating the biometric flow in any case
+ val opId: Int? = it.slice.items.firstOrNull {
+ it.hasHint("androidx.credentials.provider.credentialEntry.SLICE_HINT_CRYPTO_OP_ID")
+ }?.int
+ if (allowedAuthenticators != null) {
+ return BiometricRequestInfo(opId = opId, allowedAuthenticators = allowedAuthenticators)
+ }
+ return null
+}
+
val Slice.credentialEntry: CredentialEntry?
get() =
try {
@@ -221,7 +255,6 @@
CustomCredentialEntry.fromSlice(this)
}
-
/**
* Note: caller required handle empty list due to parsing error.
*/
@@ -386,4 +419,4 @@
PackageManager.PackageInfoFlags.of(
(packageManagerFlags).toLong())
)
-}
\ No newline at end of file
+}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/BiometricRequestInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/BiometricRequestInfo.kt
new file mode 100644
index 0000000..486cfe7
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/BiometricRequestInfo.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.credentialmanager.model
+
+/**
+ * This allows reading the data from the request, and holding that state around the framework.
+ * The [opId] bit is required for some authentication flows where CryptoObjects are used.
+ * The [allowedAuthenticators] is needed for all flows, and our flow ensures this value is never
+ * null.
+ */
+data class BiometricRequestInfo(
+ val opId: Int? = null,
+ val allowedAuthenticators: Int
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt
index d6189eb..fe02e5b 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/creation/CreateOptionInfo.kt
@@ -19,6 +19,7 @@
import android.app.PendingIntent
import android.content.Intent
import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.BiometricRequestInfo
import com.android.credentialmanager.model.EntryInfo
import java.time.Instant
@@ -36,6 +37,7 @@
val lastUsedTime: Instant,
val footerDescription: String?,
val allowAutoSelect: Boolean,
+ val biometricRequest: BiometricRequestInfo? = null,
) : EntryInfo(
providerId,
entryKey,
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
index a657e97..8913397 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
@@ -19,6 +19,7 @@
import android.app.PendingIntent
import android.content.Intent
import android.graphics.drawable.Drawable
+import com.android.credentialmanager.model.BiometricRequestInfo
import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.EntryInfo
import java.time.Instant
@@ -49,6 +50,7 @@
// "For <value-of-entryGroupId>" on the more-option screen.
val isDefaultIconPreferredAsSingleProvider: Boolean,
val affiliatedDomain: String?,
+ val biometricRequest: BiometricRequestInfo? = null,
) : EntryInfo(
providerId,
entryKey,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 879d64c..b17a98b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -40,6 +40,7 @@
import com.android.credentialmanager.getflow.findAutoSelectEntry
import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.createflow.isFlowAutoSelectable
+import com.android.credentialmanager.getflow.findBiometricFlowEntry
/**
* Client for interacting with Credential Manager. Also holds data inputs from it.
@@ -148,10 +149,17 @@
)
}
RequestInfo.TYPE_GET -> {
- val getCredentialInitialUiState = getCredentialInitialUiState(originName,
+ var getCredentialInitialUiState = getCredentialInitialUiState(originName,
isReqForAllOptions)!!
val autoSelectEntry =
findAutoSelectEntry(getCredentialInitialUiState.providerDisplayInfo)
+ val biometricEntry = findBiometricFlowEntry(
+ getCredentialInitialUiState.providerDisplayInfo,
+ autoSelectEntry != null)
+ if (biometricEntry != null) {
+ getCredentialInitialUiState = getCredentialInitialUiState.copy(
+ activeEntry = biometricEntry)
+ }
UiState(
createCredentialUiState = null,
getCredentialUiState = getCredentialInitialUiState,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 1f2fa20..28c4047 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -17,6 +17,7 @@
package com.android.credentialmanager
import android.app.Activity
+import android.hardware.biometrics.BiometricPrompt
import android.os.IBinder
import android.text.TextUtils
import android.util.Log
@@ -28,6 +29,8 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
+import com.android.credentialmanager.common.BiometricResult
+import com.android.credentialmanager.common.BiometricState
import com.android.credentialmanager.model.EntryInfo
import com.android.credentialmanager.common.Constants
import com.android.credentialmanager.common.DialogState
@@ -54,6 +57,7 @@
val isAutoSelectFlow: Boolean = false,
val cancelRequestState: CancelUiRequestState?,
val isInitialRender: Boolean,
+ val biometricState: BiometricState = BiometricState()
)
data class CancelUiRequestState(
@@ -113,12 +117,21 @@
launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
val entry = uiState.selectedEntry
+ val biometricState = uiState.biometricState
val pendingIntent = entry?.pendingIntent
if (pendingIntent != null) {
Log.d(Constants.LOG_TAG, "Launching provider activity")
uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
val entryIntent = entry.fillInIntent
entryIntent?.putExtra(Constants.IS_AUTO_SELECTED_KEY, uiState.isAutoSelectFlow)
+ if (biometricState.biometricResult != null) {
+ if (uiState.isAutoSelectFlow) {
+ Log.w(Constants.LOG_TAG, "Unexpected biometric result exists when " +
+ "autoSelect is preferred.")
+ }
+ entryIntent?.putExtra(Constants.BIOMETRIC_AUTH_TYPE,
+ biometricState.biometricResult.biometricAuthenticationResult.authenticationType)
+ }
val intentSenderRequest = IntentSenderRequest.Builder(pendingIntent)
.setFillInIntent(entryIntent).build()
try {
@@ -200,13 +213,20 @@
/**************************************************************************/
/***** Get Flow Callbacks *****/
/**************************************************************************/
- fun getFlowOnEntrySelected(entry: EntryInfo) {
+ fun getFlowOnEntrySelected(
+ entry: EntryInfo,
+ authResult: BiometricPrompt.AuthenticationResult? = null
+ ) {
Log.d(Constants.LOG_TAG, "credential selected: {provider=${entry.providerId}" +
", key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
uiState = if (entry.pendingIntent != null) {
uiState.copy(
selectedEntry = entry,
providerActivityState = ProviderActivityState.READY_TO_LAUNCH,
+ biometricState = if (authResult == null) uiState.biometricState else uiState
+ .biometricState.copy(biometricResult = BiometricResult(
+ biometricAuthenticationResult = authResult)
+ )
)
} else {
credManRepo.onOptionSelected(entry.providerId, entry.entryKey, entry.entrySubkey)
@@ -347,4 +367,9 @@
fun logUiEvent(uiEventEnum: UiEventEnum) {
this.uiMetrics.log(uiEventEnum, credManRepo.requestInfo?.packageName)
}
+
+ companion object {
+ // TODO(b/326243754) : Replace/remove once all failure flows added in
+ const val TEMPORARY_FAILURE_CODE = Integer.MIN_VALUE
+ }
}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 6a1998a..fd6fc6a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -503,6 +503,8 @@
it.hasHint("androidx.credentials.provider.createEntry.SLICE_HINT_AUTO_" +
"SELECT_ALLOWED")
}?.text == "true",
+ // TODO(b/326243754) : Handle this when the create flow is added; for now the
+ // create flow does not support biometric values
)
)
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt
new file mode 100644
index 0000000..db5ab56
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt
@@ -0,0 +1,374 @@
+/*
+ * 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.credentialmanager.common
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricPrompt
+import android.os.CancellationSignal
+import android.util.Log
+import androidx.core.content.ContextCompat.getMainExecutor
+import androidx.core.graphics.drawable.toBitmap
+import com.android.credentialmanager.R
+import com.android.credentialmanager.createflow.EnabledProviderInfo
+import com.android.credentialmanager.getflow.ProviderDisplayInfo
+import com.android.credentialmanager.getflow.RequestDisplayInfo
+import com.android.credentialmanager.getflow.generateDisplayTitleTextResCode
+import com.android.credentialmanager.model.BiometricRequestInfo
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.ProviderInfo
+import java.lang.Exception
+
+/**
+ * Aggregates common display information used for the Biometric Flow.
+ * Namely, this adds the ability to encapsulate the [providerIcon], the providers icon, the
+ * [providerName], which represents the name of the provider, the [displayTitleText] which is
+ * the large text displaying the flow in progress, and the [descriptionAboveBiometricButton], which
+ * describes details of where the credential is being saved, and how.
+ */
+data class BiometricDisplayInfo(
+ val providerIcon: Bitmap,
+ val providerName: String,
+ val displayTitleText: String,
+ val descriptionAboveBiometricButton: String,
+ val biometricRequestInfo: BiometricRequestInfo,
+)
+
+/**
+ * Sets up generic state used by the create and get flows to hold the holistic states for the flow.
+ * These match all the present callback values from [BiometricPrompt], and may be extended to hold
+ * additional states that may improve the flow.
+ */
+data class BiometricState(
+ val biometricResult: BiometricResult? = null,
+ val biometricError: BiometricError? = null,
+ val biometricHelp: BiometricHelp? = null,
+ val biometricAcquireInfo: Int? = null,
+)
+
+/**
+ * When a result exists, it must be retrievable. This encapsulates the result
+ * so that should this object exist, the result will be retrievable.
+ */
+data class BiometricResult(
+ val biometricAuthenticationResult: BiometricPrompt.AuthenticationResult
+)
+
+/**
+ * Encapsulates the error callback results to easily manage biometric error states in the flow.
+ */
+data class BiometricError(
+ val errorCode: Int,
+ val errString: CharSequence? = null
+)
+
+/**
+ * Encapsulates the help callback results to easily manage biometric help states in the flow.
+ * To specify, this allows us to parse the onAuthenticationHelp method in the [BiometricPrompt].
+ */
+data class BiometricHelp(
+ val helpCode: Int,
+ var helpString: CharSequence? = null
+)
+
+/**
+ * This will handle the logic for integrating credential manager with the biometric prompt for the
+ * single account biometric experience. This simultaneously handles both the get and create flows,
+ * by retrieving all the data from credential manager, and properly parsing that data into the
+ * biometric prompt.
+ */
+fun runBiometricFlow(
+ biometricEntry: EntryInfo,
+ context: Context,
+ openMoreOptionsPage: () -> Unit,
+ sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,
+ onCancelFlowAndFinish: (String) -> Unit,
+ getRequestDisplayInfo: RequestDisplayInfo? = null,
+ getProviderInfoList: List<ProviderInfo>? = null,
+ getProviderDisplayInfo: ProviderDisplayInfo? = null,
+ onBiometricFailureFallback: () -> Unit,
+ createRequestDisplayInfo: com.android.credentialmanager.createflow
+ .RequestDisplayInfo? = null,
+ createProviderInfo: EnabledProviderInfo? = null,
+) {
+ var biometricDisplayInfo: BiometricDisplayInfo? = null
+ if (getRequestDisplayInfo != null) {
+ biometricDisplayInfo = validateAndRetrieveBiometricGetDisplayInfo(getRequestDisplayInfo,
+ getProviderInfoList,
+ getProviderDisplayInfo,
+ context, biometricEntry)
+ } else if (createRequestDisplayInfo != null) {
+ // TODO(b/326243754) : Create Flow to be implemented in follow up
+ biometricDisplayInfo = validateBiometricCreateFlow(
+ createRequestDisplayInfo,
+ createProviderInfo
+ )
+ }
+
+ if (biometricDisplayInfo == null) {
+ onBiometricFailureFallback()
+ return
+ }
+
+ val biometricPrompt = setupBiometricPrompt(context, biometricDisplayInfo, openMoreOptionsPage,
+ biometricDisplayInfo.biometricRequestInfo.allowedAuthenticators)
+
+ val callback: BiometricPrompt.AuthenticationCallback =
+ setupBiometricAuthenticationCallback(sendDataToProvider, biometricEntry,
+ onCancelFlowAndFinish)
+
+ val cancellationSignal = CancellationSignal()
+ cancellationSignal.setOnCancelListener {
+ Log.d(TAG, "Your cancellation signal was called.")
+ // TODO(b/326243754) : Migrate towards passing along the developer cancellation signal
+ // or validate the necessity for this
+ }
+
+ val executor = getMainExecutor(context)
+
+ try {
+ biometricPrompt.authenticate(cancellationSignal, executor, callback)
+ } catch (e: IllegalArgumentException) {
+ Log.w(TAG, "Calling the biometric prompt API failed with: /n${e.localizedMessage}\n")
+ onBiometricFailureFallback()
+ }
+}
+
+/**
+ * Sets up the biometric prompt with the UI specific bits.
+ * // TODO(b/326243754) : Pass in opId once dependency is confirmed via CryptoObject
+ * // TODO(b/326243754) : Given fallbacks aren't allowed, for now we validate that device creds
+ * // are NOT allowed to be passed in to avoid throwing an error. Later, however, once target
+ * // alignments occur, we should add the bit back properly.
+ */
+private fun setupBiometricPrompt(
+ context: Context,
+ biometricDisplayInfo: BiometricDisplayInfo,
+ openMoreOptionsPage: () -> Unit,
+ requestAllowedAuthenticators: Int,
+): BiometricPrompt {
+ val finalAuthenticators = removeDeviceCredential(requestAllowedAuthenticators)
+
+ val biometricPrompt = BiometricPrompt.Builder(context)
+ .setTitle(biometricDisplayInfo.displayTitleText)
+ // TODO(b/326243754) : Migrate to using new methods recently aligned upon
+ .setNegativeButton(context.getString(R.string
+ .dropdown_presentation_more_sign_in_options_text),
+ getMainExecutor(context)) { _, _ ->
+ openMoreOptionsPage()
+ }
+ .setAllowedAuthenticators(finalAuthenticators)
+ .setConfirmationRequired(true)
+ // TODO(b/326243754) : Add logo back once new permission privileges sorted out
+ .setDescription(biometricDisplayInfo.descriptionAboveBiometricButton)
+ .build()
+
+ return biometricPrompt
+}
+
+// TODO(b/326243754) : Remove after larger level alignments made on fallback negative button
+// For the time being, we do not support the pin fallback until UX is decided.
+private fun removeDeviceCredential(requestAllowedAuthenticators: Int): Int {
+ var finalAuthenticators = requestAllowedAuthenticators
+
+ if (requestAllowedAuthenticators == (BiometricManager.Authenticators.DEVICE_CREDENTIAL or
+ BiometricManager.Authenticators.BIOMETRIC_WEAK)) {
+ finalAuthenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ }
+
+ if (requestAllowedAuthenticators == (BiometricManager.Authenticators.DEVICE_CREDENTIAL or
+ BiometricManager.Authenticators.BIOMETRIC_STRONG)) {
+ finalAuthenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ }
+
+ if (requestAllowedAuthenticators == (BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
+ finalAuthenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ }
+
+ return finalAuthenticators
+}
+
+/**
+ * Sets up the biometric authentication callback.
+ */
+private fun setupBiometricAuthenticationCallback(
+ sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,
+ selectedEntry: EntryInfo,
+ onCancelFlowAndFinish: (String) -> Unit
+): BiometricPrompt.AuthenticationCallback {
+ val callback: BiometricPrompt.AuthenticationCallback =
+ object : BiometricPrompt.AuthenticationCallback() {
+ // TODO(b/326243754) : Validate remaining callbacks
+ override fun onAuthenticationSucceeded(
+ authResult: BiometricPrompt.AuthenticationResult?
+ ) {
+ super.onAuthenticationSucceeded(authResult)
+ try {
+ if (authResult != null) {
+ sendDataToProvider(selectedEntry, authResult)
+ } else {
+ onCancelFlowAndFinish("The biometric flow succeeded but unexpectedly " +
+ "returned a null value.")
+ // TODO(b/326243754) : Propagate to provider
+ }
+ } catch (e: Exception) {
+ onCancelFlowAndFinish("The biometric flow succeeded but failed on handling " +
+ "the result. See: \n$e\n")
+ // TODO(b/326243754) : Propagate to provider
+ }
+ }
+
+ override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence?) {
+ super.onAuthenticationHelp(helpCode, helpString)
+ Log.d(TAG, "Authentication help discovered: $helpCode and $helpString")
+ // TODO(b/326243754) : Decide on strategy with provider (a simple log probably
+ // suffices here)
+ }
+
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
+ super.onAuthenticationError(errorCode, errString)
+ Log.d(TAG, "Authentication error-ed out: $errorCode and $errString")
+ // TODO(b/326243754) : Propagate to provider
+ }
+
+ override fun onAuthenticationFailed() {
+ super.onAuthenticationFailed()
+ Log.d(TAG, "Authentication failed.")
+ // TODO(b/326243754) : Propagate to provider
+ }
+ }
+ return callback
+}
+
+/**
+ * Creates the [BiometricDisplayInfo] for get flows, and early handles conditional
+ * checking between the two. Note that while this method's main purpose is to retrieve the info
+ * required to display the biometric prompt, it acts as a secondary validator to handle any null
+ * checks at the beginning of the biometric flow and supports a quick fallback.
+ * While it's not expected for the flow to be triggered if values are
+ * missing, some values are by default nullable when they are pulled, such as entries. Thus, this
+ * acts as a final validation failsafe, without requiring null checks or null forcing around the
+ * codebase.
+ */
+private fun validateAndRetrieveBiometricGetDisplayInfo(
+ getRequestDisplayInfo: RequestDisplayInfo?,
+ getProviderInfoList: List<ProviderInfo>?,
+ getProviderDisplayInfo: ProviderDisplayInfo?,
+ context: Context,
+ selectedEntry: EntryInfo
+): BiometricDisplayInfo? {
+ if (getRequestDisplayInfo != null && getProviderInfoList != null &&
+ getProviderDisplayInfo != null) {
+ if (selectedEntry !is CredentialEntryInfo) { return null }
+ return getBiometricDisplayValues(getProviderInfoList,
+ context, getRequestDisplayInfo, selectedEntry)
+ }
+ return null
+}
+
+/**
+ * Creates the [BiometricDisplayInfo] for create flows, and early handles conditional
+ * checking between the two. The reason for this method matches the logic for the
+ * [validateBiometricGetFlow] with the only difference being that this is for the create flow.
+ */
+private fun validateBiometricCreateFlow(
+ createRequestDisplayInfo: com.android.credentialmanager.createflow.RequestDisplayInfo?,
+ createProviderInfo: EnabledProviderInfo?,
+): BiometricDisplayInfo? {
+ if (createRequestDisplayInfo != null && createProviderInfo != null) {
+ } else if (createRequestDisplayInfo != null && createProviderInfo != null) {
+ // TODO(b/326243754) : Create Flow to be implemented in follow up
+ return createFlowDisplayValues()
+ }
+ return null
+}
+
+/**
+ * Handles the biometric sign in via the 'get credentials' flow.
+ * If any expected value is not present, the flow is considered unreachable and we will fallback
+ * to the original selector. Note that these redundant checks are just failsafe; the original
+ * flow should never reach here with invalid params.
+ */
+private fun getBiometricDisplayValues(
+ getProviderInfoList: List<ProviderInfo>,
+ context: Context,
+ getRequestDisplayInfo: RequestDisplayInfo,
+ selectedEntry: CredentialEntryInfo,
+): BiometricDisplayInfo? {
+ var icon: Bitmap? = null
+ var providerName: String? = null
+ var displayTitleText: String? = null
+ var descriptionText: String? = null
+ val primaryAccountsProviderInfo = retrievePrimaryAccountProviderInfo(selectedEntry.providerId,
+ getProviderInfoList)
+ icon = primaryAccountsProviderInfo?.icon?.toBitmap()
+ providerName = primaryAccountsProviderInfo?.displayName
+ if (icon == null || providerName == null) {
+ Log.d(TAG, "Unexpectedly found invalid provider information.")
+ return null
+ }
+ if (selectedEntry.biometricRequest == null) {
+ Log.d(TAG, "Unexpectedly in biometric flow without a biometric request.")
+ return null
+ }
+ val singleEntryType = selectedEntry.credentialType
+ val username = selectedEntry.userName
+ displayTitleText = context.getString(
+ generateDisplayTitleTextResCode(singleEntryType),
+ getRequestDisplayInfo.appName
+ )
+ descriptionText = context.getString(
+ R.string.get_dialog_title_single_tap_for,
+ getRequestDisplayInfo.appName,
+ username
+ )
+ return BiometricDisplayInfo(providerIcon = icon, providerName = providerName,
+ displayTitleText = displayTitleText, descriptionAboveBiometricButton = descriptionText,
+ biometricRequestInfo = selectedEntry.biometricRequest as BiometricRequestInfo)
+}
+
+/**
+ * Handles the biometric sign in via the 'create credentials' flow, or early validates this flow
+ * needs to fallback.
+ */
+private fun createFlowDisplayValues(): BiometricDisplayInfo? {
+ // TODO(b/326243754) : Create Flow to be implemented in follow up
+ return null
+}
+
+/**
+ * During a get flow with single tap sign in enabled, this will match the credentialEntry that
+ * will single tap with the correct provider info. Namely, it's the first provider info that
+ * contains a matching providerId to the selected entry.
+ */
+private fun retrievePrimaryAccountProviderInfo(
+ providerId: String,
+ getProviderInfoList: List<ProviderInfo>
+): ProviderInfo? {
+ var discoveredProviderInfo: ProviderInfo? = null
+ getProviderInfoList.forEach { provider ->
+ if (provider.id == providerId) {
+ discoveredProviderInfo = provider
+ return@forEach
+ }
+ }
+ return discoveredProviderInfo
+}
+
+const val TAG = "BiometricHandler"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt
index 51ca597..7e7a74f 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt
@@ -22,5 +22,7 @@
const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
"androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED"
const val IS_AUTO_SELECTED_KEY = "IS_AUTO_SELECTED"
+ const val BIOMETRIC_AUTH_TYPE = "BIOMETRIC_AUTH_TYPE"
+ const val BIOMETRIC_AUTH_FAILURE = "BIOMETRIC_AUTH_FAILURE"
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index 99a9409..d13d86f 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -305,10 +305,14 @@
modifier = Modifier.fillMaxWidth()
) {
if (leftButton != null) {
- leftButton()
+ Box(modifier = Modifier.wrapContentSize().weight(1f, fill = false)) {
+ leftButton()
+ }
}
if (rightButton != null) {
- rightButton()
+ Box(modifier = Modifier.wrapContentSize().weight(1f, fill = false)) {
+ rightButton()
+ }
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index a46e358..3fb91522 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -17,7 +17,6 @@
package com.android.credentialmanager.common.ui
import android.content.Context
-import android.content.res.Configuration
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import com.android.credentialmanager.model.get.CredentialEntryInfo
@@ -27,10 +26,12 @@
class RemoteViewsFactory {
companion object {
- private const val setAdjustViewBoundsMethodName = "setAdjustViewBounds"
- private const val setMaxHeightMethodName = "setMaxHeight"
- private const val setBackgroundResourceMethodName = "setBackgroundResource"
- private const val bulletPoint = "\u2022"
+ private const val SET_ADJUST_VIEW_BOUNDS_METHOD_NAME = "setAdjustViewBounds"
+ private const val SET_MAX_HEIGHT_METHOD_NAME = "setMaxHeight"
+ private const val SET_BACKGROUND_RESOURCE_METHOD_NAME = "setBackgroundResource"
+ private const val BULLET_POINT = "\u2022"
+ // TODO(jbabs): RemoteViews#setViewPadding renders this as 8dp on the display. Debug why.
+ private const val END_ITEMS_PADDING = 28
fun createDropdownPresentation(
context: Context,
@@ -50,18 +51,18 @@
val secondaryText =
if (credentialEntryInfo.displayName != null
&& (credentialEntryInfo.displayName != credentialEntryInfo.userName))
- (credentialEntryInfo.userName + " " + bulletPoint + " "
+ (credentialEntryInfo.userName + " " + BULLET_POINT + " "
+ credentialEntryInfo.credentialTypeDisplayName
- + " " + bulletPoint + " " + credentialEntryInfo.providerDisplayName)
- else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
+ + " " + BULLET_POINT + " " + credentialEntryInfo.providerDisplayName)
+ else (credentialEntryInfo.credentialTypeDisplayName + " " + BULLET_POINT + " "
+ credentialEntryInfo.providerDisplayName)
remoteViews.setTextViewText(android.R.id.text2, secondaryText)
remoteViews.setImageViewIcon(android.R.id.icon1, icon);
remoteViews.setBoolean(
- android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+ android.R.id.icon1, SET_ADJUST_VIEW_BOUNDS_METHOD_NAME, true);
remoteViews.setInt(
android.R.id.icon1,
- setMaxHeightMethodName,
+ SET_MAX_HEIGHT_METHOD_NAME,
context.resources.getDimensionPixelSize(
com.android.credentialmanager.R.dimen.autofill_icon_size));
remoteViews.setContentDescription(android.R.id.icon1, credentialEntryInfo
@@ -71,11 +72,11 @@
com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one else
com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_middle
remoteViews.setInt(
- android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ android.R.id.content, SET_BACKGROUND_RESOURCE_METHOD_NAME, drawableId);
if (isFirstEntry) remoteViews.setViewPadding(
com.android.credentialmanager.R.id.credential_card,
/* left=*/0,
- /* top=*/8,
+ /* top=*/END_ITEMS_PADDING,
/* right=*/0,
/* bottom=*/0)
if (isLastEntry) remoteViews.setViewPadding(
@@ -83,7 +84,7 @@
/*left=*/0,
/* top=*/0,
/* right=*/0,
- /* bottom=*/8)
+ /* bottom=*/END_ITEMS_PADDING)
return remoteViews
}
@@ -95,16 +96,16 @@
com.android.credentialmanager
.R.string.dropdown_presentation_more_sign_in_options_text))
remoteViews.setBoolean(
- android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+ android.R.id.icon1, SET_ADJUST_VIEW_BOUNDS_METHOD_NAME, true);
remoteViews.setInt(
android.R.id.icon1,
- setMaxHeightMethodName,
+ SET_MAX_HEIGHT_METHOD_NAME,
context.resources.getDimensionPixelSize(
com.android.credentialmanager.R.dimen.autofill_icon_size));
val drawableId =
com.android.credentialmanager.R.drawable.more_options_list_item
remoteViews.setInt(
- android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ android.R.id.content, SET_BACKGROUND_RESOURCE_METHOD_NAME, drawableId);
return remoteViews
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index b9c9d89..b59ccc2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -16,8 +16,10 @@
package com.android.credentialmanager.getflow
+import android.credentials.flags.Flags.credmanBiometricApiEnabled
import android.credentials.flags.Flags.selectorUiImprovementsEnabled
import android.graphics.drawable.Drawable
+import android.hardware.biometrics.BiometricPrompt
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
import androidx.activity.result.IntentSenderRequest
@@ -41,6 +43,7 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextLayoutResult
@@ -49,30 +52,31 @@
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.CredentialSelectorViewModel
import com.android.credentialmanager.R
-import com.android.credentialmanager.model.EntryInfo
-import com.android.credentialmanager.model.CredentialType
-import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
+import com.android.credentialmanager.common.runBiometricFlow
import com.android.credentialmanager.common.ui.ActionButton
import com.android.credentialmanager.common.ui.ActionEntry
import com.android.credentialmanager.common.ui.ConfirmButton
import com.android.credentialmanager.common.ui.CredentialContainerCard
+import com.android.credentialmanager.common.ui.CredentialListSectionHeader
import com.android.credentialmanager.common.ui.CtaButtonRow
import com.android.credentialmanager.common.ui.Entry
+import com.android.credentialmanager.common.ui.HeadlineIcon
+import com.android.credentialmanager.common.ui.HeadlineText
+import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.ModalBottomSheet
import com.android.credentialmanager.common.ui.MoreOptionTopAppBar
import com.android.credentialmanager.common.ui.SheetContainerCard
-import com.android.credentialmanager.common.ui.SnackbarActionText
-import com.android.credentialmanager.common.ui.HeadlineText
-import com.android.credentialmanager.common.ui.CredentialListSectionHeader
-import com.android.credentialmanager.common.ui.HeadlineIcon
-import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.Snackbar
+import com.android.credentialmanager.common.ui.SnackbarActionText
import com.android.credentialmanager.logging.GetCredentialEvent
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.EntryInfo
import com.android.credentialmanager.model.get.ActionEntryInfo
import com.android.credentialmanager.model.get.AuthenticationEntryInfo
import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.model.get.RemoteEntryInfo
import com.android.credentialmanager.userAndDisplayNameForPasskey
import com.android.internal.logging.UiEventLogger.UiEventEnum
@@ -82,7 +86,7 @@
fun GetCredentialScreen(
viewModel: CredentialSelectorViewModel,
getCredentialUiState: GetCredentialUiState,
- providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+ providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>,
) {
if (getCredentialUiState.currentScreenState == GetScreenState.REMOTE_ONLY) {
RemoteCredentialSnackBarScreen(
@@ -137,6 +141,22 @@
}
viewModel.uiMetrics.log(GetCredentialEvent
.CREDMAN_GET_CRED_SCREEN_PRIMARY_SELECTION)
+ } else if (credmanBiometricApiEnabled() && getCredentialUiState
+ .currentScreenState == GetScreenState.BIOMETRIC_SELECTION) {
+ BiometricSelectionPage(
+ // TODO(b/326243754) : Utilize expected entry for this flow, confirm
+ // activeEntry will always be what represents the single tap flow
+ biometricEntry = getCredentialUiState.activeEntry,
+ onMoreOptionSelected = viewModel::getFlowOnMoreOptionSelected,
+ onCancelFlowAndFinish = viewModel::onIllegalUiState,
+ requestDisplayInfo = getCredentialUiState.requestDisplayInfo,
+ providerInfoList = getCredentialUiState.providerInfoList,
+ providerDisplayInfo = getCredentialUiState.providerDisplayInfo,
+ onBiometricEntrySelected =
+ viewModel::getFlowOnEntrySelected,
+ fallbackToOriginalFlow =
+ viewModel::getFlowOnBackToPrimarySelectionScreen,
+ )
} else {
AllSignInOptionCard(
providerInfoList = getCredentialUiState.providerInfoList,
@@ -189,6 +209,34 @@
}
}
+@Composable
+internal fun BiometricSelectionPage(
+ biometricEntry: EntryInfo?,
+ onCancelFlowAndFinish: (String) -> Unit,
+ onMoreOptionSelected: () -> Unit,
+ requestDisplayInfo: RequestDisplayInfo,
+ providerInfoList: List<ProviderInfo>,
+ providerDisplayInfo: ProviderDisplayInfo,
+ onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult?) -> Unit,
+ fallbackToOriginalFlow: () -> Unit,
+) {
+ if (biometricEntry == null) {
+ fallbackToOriginalFlow()
+ return
+ }
+ runBiometricFlow(
+ biometricEntry = biometricEntry,
+ context = LocalContext.current,
+ openMoreOptionsPage = onMoreOptionSelected,
+ sendDataToProvider = onBiometricEntrySelected,
+ onCancelFlowAndFinish = onCancelFlowAndFinish,
+ getRequestDisplayInfo = requestDisplayInfo,
+ getProviderInfoList = providerInfoList,
+ getProviderDisplayInfo = providerDisplayInfo,
+ onBiometricFailureFallback = fallbackToOriginalFlow
+ )
+}
+
/** Draws the primary credential selection page, used in Android U. */
// TODO(b/327518384) - remove after flag selectorUiImprovementsEnabled is enabled.
@Composable
@@ -256,13 +304,8 @@
if (hasSingleEntry) {
val singleEntryType = sortedUserNameToCredentialEntryList.firstOrNull()
?.sortedCredentialEntryList?.firstOrNull()?.credentialType
- if (singleEntryType == CredentialType.PASSKEY)
- R.string.get_dialog_title_use_passkey_for
- else if (singleEntryType == CredentialType.PASSWORD)
- R.string.get_dialog_title_use_password_for
- else if (authenticationEntryList.isNotEmpty())
- R.string.get_dialog_title_unlock_options_for
- else R.string.get_dialog_title_use_sign_in_for
+ generateDisplayTitleTextResCode(singleEntryType!!,
+ authenticationEntryList)
} else {
if (authenticationEntryList.isNotEmpty() ||
sortedUserNameToCredentialEntryList.any { perNameEntryList ->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index e35acae..6d5b52a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -17,8 +17,11 @@
package com.android.credentialmanager.getflow
import android.credentials.flags.Flags.selectorUiImprovementsEnabled
+import android.credentials.flags.Flags.credmanBiometricApiEnabled
import android.graphics.drawable.Drawable
import androidx.credentials.PriorityHints
+import com.android.credentialmanager.R
+import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.model.EntryInfo
import com.android.credentialmanager.model.get.AuthenticationEntryInfo
@@ -39,6 +42,59 @@
val isNoAccount: Boolean = false,
)
+/**
+ * Checks if this get flow is a biometric selection flow by ensuring that the first account has a
+ * single credential entry to display. The presently agreed upon condition validates this flow for
+ * a single account. In the case when there's a single credential, this flow matches the auto
+ * select criteria, but with the possibility that the two flows (autoselect and biometric) may
+ * collide. In those collision cases, the auto select flow is supported over the biometric flow.
+ * If there is a single account but more than one credential, and the first ranked credential has
+ * the biometric bit flipped on, we will use the biometric flow. If all conditions are valid, this
+ * responds with the entry utilized by the biometricFlow, or null otherwise.
+ */
+internal fun findBiometricFlowEntry(
+ providerDisplayInfo: ProviderDisplayInfo,
+ isAutoSelectFlow: Boolean
+): CredentialEntryInfo? {
+ if (!credmanBiometricApiEnabled()) {
+ return null
+ }
+ if (isAutoSelectFlow) {
+ // For this to be true, it must be the case that there is a single entry and a single
+ // account. If that is the case, and auto-select is enabled along side the one-tap flow, we
+ // always favor that over the one tap flow.
+ return null
+ }
+ // The flow through an authentication entry, even if only a singular entry exists, is deemed
+ // as not being eligible for the single tap flow given that it adds any number of credentials
+ // once unlocked; essentially, this entry contains additional complexities behind it, making it
+ // invalid.
+ if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) {
+ return null
+ }
+ val singleAccountEntryList = getCredentialEntryListIffSingleAccount(
+ providerDisplayInfo.sortedUserNameToCredentialEntryList) ?: return null
+
+ val firstEntry = singleAccountEntryList.firstOrNull()
+ return if (firstEntry?.biometricRequest != null) firstEntry else null
+}
+
+/**
+ * A utility method that will procure the credential entry list if and only if the credential entry
+ * list is for a singular account use case. This can be used for various flows that condition on
+ * a singular account.
+ */
+internal fun getCredentialEntryListIffSingleAccount(
+ sortedUserNameToCredentialEntryList: List<PerUserNameCredentialEntryList>
+): List<CredentialEntryInfo>? {
+ if (sortedUserNameToCredentialEntryList.size != 1) {
+ return null
+ }
+ val entryList = sortedUserNameToCredentialEntryList.firstOrNull() ?: return null
+ val sortedEntryList = entryList.sortedCredentialEntryList
+ return sortedEntryList
+}
+
internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean {
return state.providerDisplayInfo.sortedUserNameToCredentialEntryList.isNotEmpty() ||
state.providerDisplayInfo.authenticationEntryList.isNotEmpty() ||
@@ -50,15 +106,14 @@
if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) {
return null
}
- if (providerDisplayInfo.sortedUserNameToCredentialEntryList.size == 1) {
- val entryList = providerDisplayInfo.sortedUserNameToCredentialEntryList.firstOrNull()
- ?: return null
- if (entryList.sortedCredentialEntryList.size == 1) {
- val entry = entryList.sortedCredentialEntryList.firstOrNull() ?: return null
- if (entry.isAutoSelectable) {
- return entry
- }
- }
+ val entryList = getCredentialEntryListIffSingleAccount(
+ providerDisplayInfo.sortedUserNameToCredentialEntryList) ?: return null
+ if (entryList.size != 1) {
+ return null
+ }
+ val entry = entryList.firstOrNull() ?: return null
+ if (entry.isAutoSelectable) {
+ return entry
}
return null
}
@@ -105,6 +160,9 @@
/** The primary credential selection page. */
PRIMARY_SELECTION,
+ /** The single tap biometric selection page. */
+ BIOMETRIC_SELECTION,
+
/** The secondary credential selection page, where all sign-in options are listed. */
ALL_SIGN_IN_OPTIONS,
@@ -177,6 +235,22 @@
)
}
+/**
+ * This generates the res code for the large display title text for the selector. For example, it
+ * retrieves the resource for strings like: "Use your saved passkey for *rpName*".
+ */
+internal fun generateDisplayTitleTextResCode(
+ singleEntryType: CredentialType,
+ authenticationEntryList: List<AuthenticationEntryInfo> = emptyList()
+): Int =
+ if (singleEntryType == CredentialType.PASSKEY)
+ R.string.get_dialog_title_use_passkey_for
+ else if (singleEntryType == CredentialType.PASSWORD)
+ R.string.get_dialog_title_use_password_for
+ else if (authenticationEntryList.isNotEmpty())
+ R.string.get_dialog_title_unlock_options_for
+ else R.string.get_dialog_title_use_sign_in_for
+
fun toActiveEntry(
providerDisplayInfo: ProviderDisplayInfo,
): EntryInfo? {
@@ -211,9 +285,18 @@
GetScreenState.REMOTE_ONLY
else if (isRequestForAllOptions)
GetScreenState.ALL_SIGN_IN_OPTIONS
+ else if (isBiometricFlow(providerDisplayInfo))
+ GetScreenState.BIOMETRIC_SELECTION
else GetScreenState.PRIMARY_SELECTION
}
+/**
+ * Determines if the flow is a biometric flow by taking into account autoselect criteria.
+ */
+internal fun isBiometricFlow(providerDisplayInfo: ProviderDisplayInfo) =
+ findBiometricFlowEntry(providerDisplayInfo,
+ findAutoSelectEntry(providerDisplayInfo) != null) != null
+
internal class CredentialEntryInfoComparatorByTypeThenTimestamp(
val typePriorityMap: Map<String, Int>,
) : Comparator<CredentialEntryInfo> {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
index 3f5e894..f2843ed 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
@@ -18,6 +18,8 @@
type OVERLAY
+map key 86 PLUS
+
### ROW 1
key GRAVE {
@@ -42,13 +44,14 @@
key 3 {
label: '3'
base: '3'
- shift: '\u2166'
+ shift: '\u2116'
}
key 4 {
label: '4'
base: '4'
shift: ';'
+ ralt: '\u20bc'
}
key 5 {
@@ -61,14 +64,12 @@
label: '6'
base: '6'
shift: ':'
- shift+ralt: '^'
}
key 7 {
label: '7'
base: '7'
shift: '?'
- ralt: '&'
}
key 8 {
@@ -176,21 +177,21 @@
key LEFT_BRACKET {
label: '\u00d6'
base: '\u00f6'
- shift: '\u00d6'
+ shift, capslock: '\u00d6'
shift+capslock: '\u00f6'
}
key RIGHT_BRACKET {
label: '\u011e'
base: '\u011f'
- shift: '\u011e'
+ shift, capslock: '\u011e'
shift+capslock: '\u011f'
}
key BACKSLASH {
label: '\\'
base: '\\'
- shift: '|'
+ shift: '/'
}
### ROW 3
@@ -261,19 +262,25 @@
key SEMICOLON {
label: 'I'
base: '\u0131'
- shift: 'I'
+ shift, capslock: 'I'
shift+capslock: '\u0131'
}
key APOSTROPHE {
label: '\u018f'
base: '\u0259'
- shift: '\u018f'
+ shift, capslock: '\u018f'
shift+capslock: '\u0259'
}
### ROW 4
+key PLUS {
+ label: '\\'
+ base: '\\'
+ shift: '/'
+}
+
key Z {
label: 'Z'
base: 'z'
@@ -326,14 +333,14 @@
key COMMA {
label: '\u00c7'
base: '\u00e7'
- shift: '\u00c7'
+ shift, capslock: '\u00c7'
shift+capslock: '\u00e7'
}
key PERIOD {
label: '\u015e'
base: '\u015f'
- shift: '\u015e'
+ shift, capslock: '\u015e'
shift+capslock: '\u015f'
}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
index 071f9f4..854c2fd 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
@@ -23,8 +23,8 @@
### ROW 1
key GRAVE {
- label: '`'
- base: '`'
+ label: '\u0300'
+ base: '\u0300'
shift: '\u00AC'
ralt: '\u00A6'
}
@@ -39,6 +39,7 @@
label: '2'
base: '2'
shift: '"'
+ ralt: '\u0308'
}
key 3 {
@@ -64,6 +65,7 @@
label: '6'
base: '6'
shift: '^'
+ ralt: '\u0302'
}
key 7 {
@@ -202,6 +204,7 @@
label: ']'
base: ']'
shift: '}'
+ shift+ralt: '|'
}
### ROW 3
@@ -282,14 +285,16 @@
label: '\''
base: '\''
shift: '@'
+ ralt: '\u0301'
+ shift+ralt: '`'
}
key POUND {
label: '#'
base: '#'
shift: '~'
- ralt: '\\'
- shift+ralt: '|'
+ ralt: '\u0303'
+ shift+ralt: '\\'
}
### ROW 4
diff --git a/packages/InputDevices/res/raw/keyboard_layout_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
index 23ccc9a..fbb9bb6 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
@@ -101,6 +101,7 @@
key SLASH {
label: '\u00df'
base: '\u00df'
+ capslock: '\u1e9e'
shift: '?'
ralt: '\\'
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index ef418a5..a4c6ac7 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -28,6 +28,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.net.Uri;
@@ -38,7 +39,6 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.packageinstaller.v2.ui.InstallLaunch;
import java.util.Arrays;
@@ -51,6 +51,7 @@
private static final String TAG = InstallStart.class.getSimpleName();
private PackageManager mPackageManager;
+ private PackageInstaller mPackageInstaller;
private UserManager mUserManager;
private boolean mAbortInstall = false;
private boolean mShouldFinish = true;
@@ -66,7 +67,7 @@
Log.i(TAG, "Using Pia V2");
Intent piaV2 = new Intent(getIntent());
- piaV2.putExtra(InstallLaunch.EXTRA_CALLING_PKG_NAME, getCallingPackage());
+ piaV2.putExtra(InstallLaunch.EXTRA_CALLING_PKG_NAME, getLaunchedFromPackage());
piaV2.putExtra(InstallLaunch.EXTRA_CALLING_PKG_UID, getLaunchedFromUid());
piaV2.setClass(this, InstallLaunch.class);
piaV2.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -75,10 +76,11 @@
return;
}
mPackageManager = getPackageManager();
+ mPackageInstaller = mPackageManager.getPackageInstaller();
mUserManager = getSystemService(UserManager.class);
Intent intent = getIntent();
- String callingPackage = getCallingPackage();
+ String callingPackage = getLaunchedFromPackage();
String callingAttributionTag = null;
// Uid of the source package, coming from ActivityManager
@@ -87,31 +89,33 @@
Log.w(TAG, "Could not determine the launching uid.");
}
+ // The UID of the origin of the installation. Note that it can be different than the
+ // "installer" of the session. For instance, if a 3P caller launched PIA with an ACTION_VIEW
+ // intent, the originatingUid is the 3P caller, but the "installer" in this case would
+ // be PIA.
+ int originatingUid = callingUid;
+
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL.equals(intent.getAction())
|| PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
- // If the activity was started via a PackageInstaller session, we retrieve the calling
- // package from that session
+ // If the activity was started via a PackageInstaller session, we retrieve the originating
+ // UID from that session
final int sessionId = (isSessionInstall
- ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
- : -1);
- int originatingUidFromSession = callingUid;
- if (callingPackage == null && sessionId != -1) {
- PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
- PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
+ ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, SessionInfo.INVALID_ID)
+ : SessionInfo.INVALID_ID);
+ if (sessionId != SessionInfo.INVALID_ID) {
+ PackageInstaller.SessionInfo sessionInfo = mPackageInstaller.getSessionInfo(sessionId);
if (sessionInfo != null) {
- callingPackage = sessionInfo.getInstallerPackageName();
callingAttributionTag = sessionInfo.getInstallerAttributionTag();
- originatingUidFromSession = sessionInfo.getOriginatingUid();
+ if (sessionInfo.getOriginatingUid() != Process.INVALID_UID) {
+ originatingUid = sessionInfo.getOriginatingUid();
+ }
}
}
final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
- // Uid of the source package, with a preference to uid from ApplicationInfo
- final int originatingUid = sourceInfo != null ? sourceInfo.uid : callingUid;
-
if (callingUid == Process.INVALID_UID && sourceInfo == null) {
Log.e(TAG, "Cannot determine caller since UID is invalid and sourceInfo is null");
mAbortInstall = true;
@@ -124,28 +128,28 @@
boolean isTrustedSource = false;
if (sourceInfo != null && sourceInfo.isPrivilegedApp()) {
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false) || (
- originatingUid != Process.INVALID_UID && checkPermission(
- Manifest.permission.INSTALL_PACKAGES, -1 /* pid */, originatingUid)
- == PackageManager.PERMISSION_GRANTED);
+ callingUid != Process.INVALID_UID && checkPermission(
+ Manifest.permission.INSTALL_PACKAGES, -1 /* pid */, callingUid)
+ == PackageManager.PERMISSION_GRANTED);
}
if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager
- && originatingUid != Process.INVALID_UID) {
- final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
+ && callingUid != Process.INVALID_UID) {
+ final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, callingUid);
if (targetSdkVersion < 0) {
- Log.e(TAG, "Cannot get target sdk version for uid " + originatingUid);
+ Log.e(TAG, "Cannot get target sdk version for uid " + callingUid);
// Invalid originating uid supplied. Abort install.
mAbortInstall = true;
} else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission(
- originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
- Log.e(TAG, "Requesting uid " + originatingUid + " needs to declare permission "
+ callingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
+ Log.e(TAG, "Requesting uid " + callingUid + " needs to declare permission "
+ Manifest.permission.REQUEST_INSTALL_PACKAGES);
mAbortInstall = true;
}
}
- if (sessionId != -1 && !isCallerSessionOwner(originatingUid, sessionId)) {
- Log.e(TAG, "UID " + originatingUid + " is not the owner of session " +
+ if (sessionId != -1 && !isCallerSessionOwner(callingUid, sessionId)) {
+ Log.e(TAG, "CallingUid " + callingUid + " is not the owner of session " +
sessionId);
mAbortInstall = true;
}
@@ -155,10 +159,9 @@
final String installerPackageNameFromIntent = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (installerPackageNameFromIntent != null) {
- final String callingPkgName = getLaunchedFromPackage();
- if (!TextUtils.equals(installerPackageNameFromIntent, callingPkgName)
+ if (!TextUtils.equals(installerPackageNameFromIntent, callingPackage)
&& mPackageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
- callingPkgName) != PackageManager.PERMISSION_GRANTED) {
+ callingPackage) != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "The given installer package name " + installerPackageNameFromIntent
+ " is invalid. Remove it.");
EventLog.writeEvent(0x534e4554, "236687884", getLaunchedFromUid(),
@@ -186,8 +189,7 @@
callingAttributionTag);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
- nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINATING_UID_FROM_SESSION_INFO,
- originatingUidFromSession);
+ nextActivity.putExtra(PackageInstallerActivity.EXTRA_IS_TRUSTED_SOURCE, isTrustedSource);
if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
@@ -257,7 +259,7 @@
private ApplicationInfo getSourceInfo(@Nullable String callingPackage) {
if (callingPackage != null) {
try {
- return getPackageManager().getApplicationInfo(callingPackage, 0);
+ return mPackageManager.getApplicationInfo(callingPackage, 0);
} catch (PackageManager.NameNotFoundException ex) {
// ignore
}
@@ -265,8 +267,6 @@
return null;
}
-
- @NonNull
private boolean canPackageQuery(int callingUid, Uri packageUri) {
ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(),
PackageManager.ComponentInfoFlags.of(0));
@@ -291,17 +291,16 @@
return false;
}
- private boolean isCallerSessionOwner(int originatingUid, int sessionId) {
- if (originatingUid == Process.ROOT_UID) {
+ private boolean isCallerSessionOwner(int callingUid, int sessionId) {
+ if (callingUid == Process.ROOT_UID) {
return true;
}
- PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
- PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
+ PackageInstaller.SessionInfo sessionInfo = mPackageInstaller.getSessionInfo(sessionId);
if (sessionInfo == null) {
return false;
}
int installerUid = sessionInfo.getInstallerUid();
- return originatingUid == installerUid;
+ return callingUid == installerUid;
}
private void checkDevicePolicyRestrictions() {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 45bfe54..8bed945 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -84,8 +84,7 @@
static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO";
static final String EXTRA_STAGED_SESSION_ID = "EXTRA_STAGED_SESSION_ID";
static final String EXTRA_APP_SNIPPET = "EXTRA_APP_SNIPPET";
- static final String EXTRA_ORIGINATING_UID_FROM_SESSION_INFO =
- "EXTRA_ORIGINATING_UID_FROM_SESSION_INFO";
+ static final String EXTRA_IS_TRUSTED_SOURCE = "EXTRA_IS_TRUSTED_SOURCE";
private static final String ALLOW_UNKNOWN_SOURCES_KEY =
PackageInstallerActivity.class.getName() + "ALLOW_UNKNOWN_SOURCES_KEY";
@@ -98,10 +97,6 @@
* The package name corresponding to #mOriginatingUid
*/
private String mOriginatingPackage;
- /**
- * The package name corresponding to the app updater in the update-ownership confirmation dialog
- */
- private String mOriginatingPackageFromSessionInfo;
private int mActivityResultCode = Activity.RESULT_CANCELED;
private int mPendingUserActionReason = -1;
@@ -154,8 +149,7 @@
viewToEnable = mDialog.requireViewById(R.id.install_confirm_question_update);
final CharSequence existingUpdateOwnerLabel = getExistingUpdateOwnerLabel();
- final CharSequence requestedUpdateOwnerLabel =
- getApplicationLabel(mOriginatingPackageFromSessionInfo);
+ final CharSequence requestedUpdateOwnerLabel = getApplicationLabel(mOriginatingPackage);
if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
&& mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP) {
String updateOwnerString =
@@ -304,21 +298,6 @@
return packagesForUid[0];
}
- private boolean isInstallRequestFromUnknownSource(Intent intent) {
- if (mCallingPackage != null && intent.getBooleanExtra(
- Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
- if (mSourceInfo != null && mSourceInfo.isPrivilegedApp()) {
- // Privileged apps can bypass unknown sources check if they want.
- return false;
- }
- }
- if (mSourceInfo != null && checkPermission(Manifest.permission.INSTALL_PACKAGES,
- -1 /* pid */, mSourceInfo.uid) == PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- return true;
- }
-
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
@@ -384,15 +363,9 @@
mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
mCallingAttributionTag = intent.getStringExtra(EXTRA_CALLING_ATTRIBUTION_TAG);
mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
- mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
- Process.INVALID_UID);
+ mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID);
mOriginatingPackage = (mOriginatingUid != Process.INVALID_UID)
? getPackageNameForUid(mOriginatingUid) : null;
- int originatingUidFromSessionInfo =
- intent.getIntExtra(EXTRA_ORIGINATING_UID_FROM_SESSION_INFO, Process.INVALID_UID);
- mOriginatingPackageFromSessionInfo = (originatingUidFromSessionInfo != Process.INVALID_UID)
- ? getPackageNameForUid(originatingUidFromSessionInfo) : mCallingPackage;
-
final Object packageSource;
if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(action)) {
@@ -557,7 +530,7 @@
* Check if it is allowed to install the package and initiate install if allowed.
*/
private void checkIfAllowedAndInitiateInstall() {
- if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
+ if (mAllowUnknownSources || getIntent().getBooleanExtra(EXTRA_IS_TRUSTED_SOURCE, false)) {
if (mLocalLOGV) Log.i(TAG, "install allowed");
initiateInstall();
} else {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
index 32795e4..08028b1 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -96,6 +96,7 @@
var stagedSessionId = SessionInfo.INVALID_ID
private set
private var callingUid = Process.INVALID_UID
+ private var originatingUid = Process.INVALID_UID
private var callingPackage: String? = null
private var sessionStager: SessionStager? = null
private lateinit var intent: Intent
@@ -135,7 +136,7 @@
callingPackage = callerInfo.packageName
- if (callingPackage == null && sessionId != SessionInfo.INVALID_ID) {
+ if (sessionId != SessionInfo.INVALID_ID) {
val sessionInfo: SessionInfo? = packageInstaller.getSessionInfo(sessionId)
callingPackage = sessionInfo?.getInstallerPackageName()
callingAttributionTag = sessionInfo?.getInstallerAttributionTag()
@@ -148,7 +149,7 @@
}
val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
// Uid of the source package, with a preference to uid from ApplicationInfo
- val originatingUid = sourceInfo?.uid ?: callingUid
+ originatingUid = sourceInfo?.uid ?: callingUid
appOpRequestInfo = AppOpRequestInfo(
getPackageNameForUid(context, originatingUid, callingPackage),
originatingUid, callingAttributionTag
@@ -282,7 +283,7 @@
context.contentResolver.openAssetFileDescriptor(uri, "r").use { afd ->
val pfd: ParcelFileDescriptor? = afd?.parcelFileDescriptor
val params: SessionParams =
- createSessionParams(intent, pfd, uri.toString())
+ createSessionParams(originatingUid, intent, pfd, uri.toString())
stagedSessionId = packageInstaller.createSession(params)
}
} catch (e: Exception) {
@@ -338,6 +339,7 @@
}
private fun createSessionParams(
+ originatingUid: Int,
intent: Intent,
pfd: ParcelFileDescriptor?,
debugPathName: String,
@@ -354,9 +356,7 @@
params.setOriginatingUri(
intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI, Uri::class.java)
)
- params.setOriginatingUid(
- intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID)
- )
+ params.setOriginatingUid(originatingUid)
params.setInstallerPackageName(intent.getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME))
params.setInstallReason(PackageManager.INSTALL_REASON_USER)
// Disable full screen intent usage by for sideloads.
diff --git a/packages/SettingsLib/ProfileSelector/Android.bp b/packages/SettingsLib/ProfileSelector/Android.bp
index 6dc07b2..4aa67c1 100644
--- a/packages/SettingsLib/ProfileSelector/Android.bp
+++ b/packages/SettingsLib/ProfileSelector/Android.bp
@@ -20,6 +20,7 @@
static_libs: [
"com.google.android.material_material",
"SettingsLibSettingsTheme",
+ "android.os.flags-aconfig-java-export",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/ProfileSelector/AndroidManifest.xml b/packages/SettingsLib/ProfileSelector/AndroidManifest.xml
index 80f6b76..303e20c 100644
--- a/packages/SettingsLib/ProfileSelector/AndroidManifest.xml
+++ b/packages/SettingsLib/ProfileSelector/AndroidManifest.xml
@@ -18,5 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.widget.profileselector">
- <uses-sdk android:minSdkVersion="23" />
+ <uses-sdk android:minSdkVersion="29" />
</manifest>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml
index 8055736..5d5b675 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Persoonlik"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Werk"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-am/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-am/strings.xml
index 3b3f019..fb0f36c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-am/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-am/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ášáá"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"á¥á«"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
index cae1f00..62b4a11 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"؎خصÙ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÙÙØ¹Ù
Ù"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml
index 9ac55bbe..ca3ea81 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"àŠ¬à§àНàŠà§àŠ€àŠ¿àŠàŠ€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àŠà§°à§àŠ®àŠžà§àŠ¥àŠŸàŠš"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml
index 5e9d3fb..f1412a9 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÅÉxsi"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"İÅ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml
index 7f9cf21..144fb48 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"LiÄno"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Posao"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml
index b7774de..f7d8200 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐÑабÑÑÑÑÑ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÐÑаÑПÑМÑÑ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml
index f1ca6b2..4ecff11 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐОÑМО"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"СлÑжебМО"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml
index 385a901..e22e399 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"àŠ¬à§àНàŠà§àŠ€àŠ¿àŠàŠ€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àŠ
àŠ«àŠ¿àŠž"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml
index 19390c2..e3b6339 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"LiÄno"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Poslovno"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml
index 0190b91..1d79a7d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Feina"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml
index d5f920a..85e8432 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Osobní"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Prácovní"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml
index 9d41b9c..770fdbc 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personlig"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Arbejde"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-de/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-de/strings.xml
index d61ff96..37c05c4 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-de/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-de/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Privat"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Dienstlich"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml
index 0832eab..10056bb 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Προσωπικά"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Εργασία"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml
index 478e603..5bc205d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rCA/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rCA/strings.xml
index 478e603..d67912f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-en-rCA/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Private"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml
index 478e603..5bc205d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml
index 478e603..5bc205d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rXC/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rXC/strings.xml
index 89b7183..187a4e7 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-en-rXC/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Private"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml
index b73026a..73cb0f8 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabajo"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml
index b73026a..73cb0f8 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabajo"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml
index e8fc44b..3328b47 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Isiklik"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Töö"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privaatne"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml
index c22f4da..5110b45 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pertsonala"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Lanekoa"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml
index 6eaf057..03b8ba1 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"؎خصÛ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Ù
ØÙ کار"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml
index 8d0b9bf..2c9126c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Henkilökohtainen"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Työ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-fr-rCA/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fr-rCA/strings.xml
index 43e4a59..8ab5238 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-fr-rCA/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personnel"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Professionnel"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml
index 43e4a59..8ab5238 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personnel"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Professionnel"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-gl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-gl/strings.xml
index 364f15c..37759e7 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-gl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-gl/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Persoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Traballo"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml
index 4aba6db..1a8f09a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"વà«àª¯àªà«àª€àª¿àªàª€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àªàª«àª¿àªž"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
index dc7818f..eda9af1 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"à€šà€¿à€à¥ à€à€ªà¥à€²à€¿à€à¥à€¶à€š"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à€µà€°à¥à€"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml
index cb434a8..b6188ef 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Osobno"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Posao"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml
index 0127717..10fa94f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Személyes"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Munkahelyi"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
index 353a6d3..eaf21de 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Ô±Õ¶Õ±Õ¶Õ¡Õ¯Õ¡Õ¶"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Ô±Õ·ÕÕ¡Õ¿Õ¡Õ¶ÖÕ¡ÕµÕ«Õ¶"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml
index 173d56f..d8de292 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pribadi"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Kerja"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml
index cc3bdd5..b4ecc12 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Persónulegt"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Vinna"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml
index 1d1e70e..eed793d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personale"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Lavoro"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml
index 4245145..cbf58b7 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"׀ך××€×× ××ש×"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"׀ך××€×× ×¢××××"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml
index f52d803..8af4d8b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"å人çš"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ä»äºçš"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml
index e93adff..5dac3d8 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ááá ááá"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"á¡ááá¡áá®á£á á"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml
index 94eab4d..2250a8c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Ðеке"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÐұЌÑÑ ÑÑÑейÑÑМ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml
index 40fe4ff..119e89a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"áááá¶ááááááœá"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"áá¶ááá¶á"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml
index 41b70e8..7ad03c3 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ವà³à²¯à²à³à²€à²¿à²"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à²à³à²²à²ž"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml
index 3577efc..105b437 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ê°ìž"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ì
묎"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml
index a65965c..58e52d2 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Ðеке"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÐÑÐŒÑÑ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
index 1e47347..a2cedbc 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ສà»àº§àºàºàº»àº§"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àºà»àºàºà»àº®àº±àºàº§àºœàº"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml
index 3ea9004..96cc949 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"AsmeninÄ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Darbo"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml
index 528deeb..6e1166f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personīgais"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Darba"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml
index 773b3f1..40d1714c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐОÑМО"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"РабПÑа"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml
index 6ae94cc..43b916f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"àŽµàµàޝàŽàµàŽ€àŽ¿àŽªàŽ°àŽ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àŽàŽŠàµàޝàµàŽàŽ¿àŽàŽ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml
index e2361b7..5a60d6a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Ð¥ÑвОйМ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÐжОл"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml
index 0a48d0f..dfde95a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"à€µà¥à€¯à€à¥à€€à€¿à€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à€à€«à€¿à€ž"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml
index 607a290..49f957b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Peribadi"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Kerja"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml
index a6f8d23..ec98763 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ááá¯ááºáá±ážááá¯ááºáá¬"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"á¡áá¯ááº"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml
index 0a6ff7d..98ac66d 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personlig"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Jobb"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
index 7c0d9e6..8385a5a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"à€µà¥à€¯à€à¥à€€à€¿à€à€€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à€à€Ÿà€®à€žà€®à¥à€¬à€šà¥à€§à¥"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml
index 932057f..aee9f4b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Persoonlijk"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Werk"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml
index eea4177..21d28a4 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ବààà¬à଀ିà¬à¬€"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à±à¬Ÿà¬°àà¬"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml
index 48d915e..b591c04 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"àššàš¿à©±àšà©"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àšàšŸàš°àš"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
index 8300df8..ac1f07b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Osobiste"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"SÅuÅŒbowe"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Prywatny"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
index 6e98dc9..4afb4471 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml
index a89bb04..f1ee0cd 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Profissional"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
index 6e98dc9..4afb4471 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml
index 317b4e3..44cec967 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Serviciu"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml
index 165fda1..ce6df63 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐОÑМÑй пÑПÑОлÑ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"РабПÑОй пÑПÑОлÑ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml
index 746e6e7..e937726 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"à¶Žà·à¶¯à·à¶à¶œà·à¶"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"à¶à·à¶»à·à¶º"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
index 5e882b5..bce4983 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Osobné"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Pracovné"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml
index d239f44..097a833 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Osebno"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Delo"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml
index 84ce281..22d6c7b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personale"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Puna"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml
index 70b4793..a0db83f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐОÑМП"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"ÐПÑаП"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml
index 8d1c657..78fe78e 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Privat"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Arbete"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml
index 63d150c..854b0e8 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Binafsi"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Kazini"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ta/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ta/strings.xml
index ab360a9..4718055 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ta/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ta/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"஀னிபà¯à®ªà®à¯à®à®µà¯"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"பணி"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml
index 9a44dcf..a96403c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"à°µà±à°¯à°à±à°€à°¿à°à°€à°"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"వరà±à°à±"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml
index f35e8fc..b7ef3e5 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"àžªà¹àž§àžàžàž±àž§"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"àžàž²àž"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml
index 92b6f16..8e4e0d4 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabaho"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml
index 680ebfe..3a34ad8 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"KiÅisel"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"İÅ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml
index 953e72c..5cde1b0 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ÐÑПбОÑÑÑ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"РПбПÑÑ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml
index 336a7e0..908b872 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"ذاتÛ"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"کاÙ
"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml
index 5c1e4c0..ea57a3a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Shaxsiy"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Ish"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml
index 7e04838..4a4c13a 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Cá nhân"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Công viá»c"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml
index d5a1c03..f36778f 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"䞪人"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"å·¥äœ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml
index ec247c9..823ce80 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"å人"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"å·¥äœ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml
index ec247c9..823ce80 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml
@@ -19,4 +19,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"å人"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"å·¥äœ"</string>
+ <!-- no translation found for settingslib_category_private (5039276873477591386) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml
index c53aba8..ebf4f89 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml
@@ -19,4 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Okomuntu siqu"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Umsebenzi"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Okuyimfihlo"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values/strings.xml b/packages/SettingsLib/ProfileSelector/res/values/strings.xml
index 68d4047..76ccb65 100644
--- a/packages/SettingsLib/ProfileSelector/res/values/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values/strings.xml
@@ -21,4 +21,6 @@
<string name="settingslib_category_personal">Personal</string>
<!-- Header for items under the work user [CHAR LIMIT=30] -->
<string name="settingslib_category_work">Work</string>
+ <!-- Header for items under the private profile user [CHAR LIMIT=30] -->
+ <string name="settingslib_category_private">Private</string>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
index be5753be..c52386b 100644
--- a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
@@ -16,31 +16,77 @@
package com.android.settingslib.widget;
+import android.annotation.TargetApi;
import android.app.Activity;
+import android.content.Context;
+import android.content.pm.UserProperties;
+import android.os.Build;
import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArrayMap;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.core.os.BuildCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
+import com.android.settingslib.widget.profileselector.R;
+
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
-import com.android.settingslib.widget.profileselector.R;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Base fragment class for profile settings.
*/
public abstract class ProfileSelectFragment extends Fragment {
+ private static final String TAG = "ProfileSelectFragment";
+ // UserHandle#USER_NULL is a @TestApi so is not accessible.
+ private static final int USER_NULL = -10000;
+ private static final int DEFAULT_POSITION = 0;
/**
- * Personal or Work profile tab of {@link ProfileSelectFragment}
- * <p>0: Personal tab.
- * <p>1: Work profile tab.
+ * The type of profile tab of {@link ProfileSelectFragment} to show
+ * <ul>
+ * <li>0: Personal tab.
+ * <li>1: Work profile tab.
+ * </ul>
+ *
+ * <p> Please note that this is supported for legacy reasons. Please use
+ * {@link #EXTRA_SHOW_FRAGMENT_USER_ID} instead.
*/
- public static final String EXTRA_SHOW_FRAGMENT_TAB =
- ":settings:show_fragment_tab";
+ public static final String EXTRA_SHOW_FRAGMENT_TAB = ":settings:show_fragment_tab";
+
+ /**
+ * An {@link ArrayList} of users to show. The supported users are: System user, the managed
+ * profile user, and the private profile user. A client should pass all the user ids that need
+ * to be shown in this list. Note that if this list is not provided then, for legacy reasons
+ * see {@link #EXTRA_SHOW_FRAGMENT_TAB}, an attempt will be made to show two tabs: one for the
+ * System user and one for the managed profile user.
+ *
+ * <p>Please note that this MUST be used in conjunction with
+ * {@link #EXTRA_SHOW_FRAGMENT_USER_ID}
+ */
+ public static final String EXTRA_LIST_OF_USER_IDS = ":settings:list_user_ids";
+
+ /**
+ * The user id of the user to be show in {@link ProfileSelectFragment}. Only the below user
+ * types are supported:
+ * <ul>
+ * <li> System user.
+ * <li> Managed profile user.
+ * <li> Private profile user.
+ * </ul>
+ *
+ * <p>Please note that this MUST be used in conjunction with {@link #EXTRA_LIST_OF_USER_IDS}.
+ */
+ public static final String EXTRA_SHOW_FRAGMENT_USER_ID = ":settings:show_fragment_user_id";
/**
* Used in fragment argument with Extra key EXTRA_SHOW_FRAGMENT_TAB
@@ -48,13 +94,23 @@
public static final int PERSONAL_TAB = 0;
/**
- * Used in fragment argument with Extra key EXTRA_SHOW_FRAGMENT_TAB
+ * Used in fragment argument with Extra key EXTRA_SHOW_FRAGMENT_TAB for the managed profile
*/
public static final int WORK_TAB = 1;
+ /**
+ * Please note that private profile is available from API LEVEL
+ * {@link Build.VERSION_CODES.VANILLA_ICE_CREAM} only, therefore PRIVATE_TAB MUST be
+ * passed in {@link #EXTRA_SHOW_FRAGMENT_TAB} and {@link #EXTRA_LIST_OF_PROFILE_TABS} for
+ * {@link Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher API Levels only.
+ */
+ private static final int PRIVATE_TAB = 2;
+
private ViewGroup mContentView;
private ViewPager2 mViewPager;
+ private final ArrayMap<UserHandle, Integer> mProfileTabsByUsers = new ArrayMap<>();
+ private boolean mUsingUserIds = false;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -67,7 +123,7 @@
if (titleResId > 0) {
activity.setTitle(titleResId);
}
- final int selectedTab = getTabId(activity, getArguments());
+ initProfileTabsToShow();
final View tabContainer = mContentView.findViewById(R.id.tab_container);
mViewPager = tabContainer.findViewById(R.id.view_pager);
@@ -78,16 +134,14 @@
).attach();
tabContainer.setVisibility(View.VISIBLE);
- final TabLayout.Tab tab = tabs.getTabAt(selectedTab);
+ final TabLayout.Tab tab = tabs.getTabAt(getSelectedTabPosition(activity, getArguments()));
tab.select();
return mContentView;
}
/**
- * create Personal or Work profile fragment
- * <p>0: Personal profile.
- * <p>1: Work profile.
+ * Create Personal or Work or Private profile fragment. See {@link #EXTRA_SHOW_FRAGMENT_USER_ID}
*/
public abstract Fragment createFragment(int position);
@@ -99,21 +153,90 @@
return 0;
}
- int getTabId(Activity activity, Bundle bundle) {
+ int getSelectedTabPosition(Activity activity, Bundle bundle) {
if (bundle != null) {
+ final int extraUserId = bundle.getInt(EXTRA_SHOW_FRAGMENT_USER_ID, USER_NULL);
+ if (extraUserId != USER_NULL) {
+ return mProfileTabsByUsers.indexOfKey(UserHandle.of(extraUserId));
+ }
final int extraTab = bundle.getInt(EXTRA_SHOW_FRAGMENT_TAB, -1);
if (extraTab != -1) {
return extraTab;
}
}
- return PERSONAL_TAB;
+ return DEFAULT_POSITION;
+ }
+
+ int getTabCount() {
+ return mUsingUserIds ? mProfileTabsByUsers.size() : 2;
+ }
+
+ void initProfileTabsToShow() {
+ Bundle bundle = getArguments();
+ if (bundle != null) {
+ ArrayList<Integer> userIdsToShow =
+ bundle.getIntegerArrayList(EXTRA_LIST_OF_USER_IDS);
+ if (userIdsToShow != null && !userIdsToShow.isEmpty()) {
+ mUsingUserIds = true;
+ UserManager userManager = getContext().getSystemService(UserManager.class);
+ List<UserHandle> userHandles = userManager.getUserProfiles();
+ for (UserHandle userHandle : userHandles) {
+ if (!userIdsToShow.contains(userHandle.getIdentifier())) {
+ continue;
+ }
+ if (userHandle.isSystem()) {
+ mProfileTabsByUsers.put(userHandle, PERSONAL_TAB);
+ } else if (userManager.isManagedProfile(userHandle.getIdentifier())) {
+ mProfileTabsByUsers.put(userHandle, WORK_TAB);
+ } else if (shouldShowPrivateProfileIfItsOne(userHandle)) {
+ mProfileTabsByUsers.put(userHandle, PRIVATE_TAB);
+ }
+ }
+ }
+ }
+ }
+
+ private int getProfileTabForPosition(int position) {
+ return mUsingUserIds ? mProfileTabsByUsers.valueAt(position) : position;
+ }
+
+ int getUserIdForPosition(int position) {
+ return mUsingUserIds ? mProfileTabsByUsers.keyAt(position).getIdentifier() : position;
}
private CharSequence getPageTitle(int position) {
- if (position == WORK_TAB) {
+ int tab = getProfileTabForPosition(position);
+ if (tab == WORK_TAB) {
return getContext().getString(R.string.settingslib_category_work);
+ } else if (tab == PRIVATE_TAB) {
+ return getContext().getString(R.string.settingslib_category_private);
}
return getString(R.string.settingslib_category_personal);
}
+
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private boolean shouldShowUserInQuietMode(UserHandle userHandle, UserManager userManager) {
+ UserProperties userProperties = userManager.getUserProperties(userHandle);
+ return !userManager.isQuietModeEnabled(userHandle)
+ || userProperties.getShowInQuietMode() != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN;
+ }
+
+ // It's sufficient to have this method marked with the appropriate API level because we expect
+ // to be here only for this API level - when then private profile was introduced.
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private boolean shouldShowPrivateProfileIfItsOne(UserHandle userHandle) {
+ if (!BuildCompat.isAtLeastV() || !android.os.Flags.allowPrivateProfile()) {
+ return false;
+ }
+ try {
+ Context userContext = getContext().createContextAsUser(userHandle, /* flags= */ 0);
+ UserManager userManager = userContext.getSystemService(UserManager.class);
+ return userManager.isPrivateProfile()
+ && shouldShowUserInQuietMode(userHandle, userManager);
+ } catch (IllegalStateException exception) {
+ Log.i(TAG, "Ignoring this user as the calling package not available in this user.");
+ }
+ return false;
+ }
}
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java
index f5ab647..37f4f27 100644
--- a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java
@@ -18,7 +18,6 @@
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
-import com.android.settingslib.widget.profileselector.R;
/**
* ViewPager Adapter to handle between TabLayout and ViewPager2
@@ -34,11 +33,11 @@
@Override
public Fragment createFragment(int position) {
- return mParentFragments.createFragment(position);
+ return mParentFragments.createFragment(mParentFragments.getUserIdForPosition(position));
}
@Override
public int getItemCount() {
- return 2;
+ return mParentFragments.getTabCount();
}
}
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_arrow_drop_down.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_arrow_drop_down.xml
new file mode 100644
index 0000000..77979f0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_arrow_drop_down.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="18"
+ android:viewportHeight="18"
+ android:width="24dp"
+ android:height="24dp">
+ <path
+ android:pathData="M7 10l5 5 5 -5z"
+ android:fillColor="@color/settingslib_materialColorOnPrimaryContainer"/>
+</vector>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_background.xml
new file mode 100644
index 0000000..20ee381
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_background.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<ripple
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/settingslib_ripple_color">
+
+ <item android:id="@android:id/background">
+ <layer-list
+ android:paddingMode="stack"
+ android:paddingStart="0dp"
+ android:paddingEnd="24dp">
+ <item
+ android:top="8dp"
+ android:bottom="8dp">
+
+ <shape>
+ <corners android:radius="28dp"/>
+ <solid android:color="@color/settingslib_materialColorPrimaryContainer"/>
+ <size android:height="@dimen/settingslib_spinner_height"/>
+ </shape>
+ </item>
+
+ <item
+ android:gravity="center|end"
+ android:width="18dp"
+ android:height="18dp"
+ android:end="12dp"
+ android:drawable="@drawable/settingslib_arrow_drop_down"/>
+ </layer-list>
+ </item>
+</ripple>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_dropdown_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_dropdown_background.xml
new file mode 100644
index 0000000..b287c3b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_spinner_dropdown_background.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<ripple
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/settingslib_ripple_color">
+
+ <item android:id="@android:id/background">
+ <layer-list
+ android:paddingMode="stack"
+ android:paddingStart="0dp"
+ android:paddingEnd="12dp">
+
+ <item>
+ <shape>
+ <corners android:radius="10dp"/>
+ <solid android:color="@color/settingslib_materialColorSecondaryContainer"/>
+ </shape>
+ </item>
+ </layer-list>
+ </item>
+</ripple>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml
index e3645b5..beed90e 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml
@@ -37,4 +37,8 @@
<!-- Material next track off color-->
<color name="settingslib_track_off_color">@android:color/system_surface_container_highest_dark
</color>
+
+ <color name="settingslib_text_color_primary_device_default">@android:color/system_on_surface_dark</color>
+
+ <color name="settingslib_text_color_secondary_device_default">@android:color/system_on_surface_variant_dark</color>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
new file mode 100644
index 0000000..229d9e3
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<resources>
+ <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_dark</color>
+ <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_dark</color>
+ <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_dark</color>
+ <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color>
+ <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color>
+ <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color>
+ <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_light</color>
+ <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color>
+ <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color>
+ <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_light</color>
+ <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_light</color>
+ <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color>
+ <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color>
+ <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color>
+ <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_dark</color>
+ <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_dark</color>
+ <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_dark</color>
+ <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_dark</color>
+ <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_dark</color>
+ <color name="settingslib_materialColorOnError">@android:color/system_on_error_dark</color>
+ <color name="settingslib_materialColorSurface">@android:color/system_surface_dark</color>
+ <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_dark</color>
+ <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_dark</color>
+ <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_dark</color>
+ <color name="settingslib_materialColorOutline">@android:color/system_outline_dark</color>
+ <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_dark</color>
+ <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_dark</color>
+ <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_dark</color>
+ <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_dark</color>
+ <color name="settingslib_materialColorPrimary">@android:color/system_primary_dark</color>
+ <color name="settingslib_materialColorSecondary">@android:color/system_secondary_dark</color>
+ <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_dark</color>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml
index fdd96ec..3709b5d 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml
@@ -39,4 +39,8 @@
<!-- Material next track outline color-->
<color name="settingslib_track_online_color">@color/settingslib_switch_track_outline_color</color>
+
+ <color name="settingslib_text_color_primary_device_default">@android:color/system_on_surface_light</color>
+
+ <color name="settingslib_text_color_secondary_device_default">@android:color/system_on_surface_variant_light</color>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
new file mode 100644
index 0000000..2691344
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<resources>
+ <!-- The text color of spinner title -->
+ <color name="settingslib_spinner_title_color">@color/settingslib_materialColorOnPrimaryContainer</color>
+ <!-- The text color of dropdown item title -->
+ <color name="settingslib_spinner_dropdown_color">@color/settingslib_materialColorOnPrimaryContainer</color>
+
+
+ <color name="settingslib_materialColorOnSecondaryFixedVariant">@android:color/system_on_secondary_fixed_variant</color>
+ <color name="settingslib_materialColorOnTertiaryFixedVariant">@android:color/system_on_tertiary_fixed_variant</color>
+ <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_light</color>
+ <color name="settingslib_materialColorOnPrimaryFixedVariant">@android:color/system_on_primary_fixed_variant</color>
+ <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_light</color>
+ <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_light</color>
+ <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_light</color>
+ <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_light</color>
+ <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color>
+ <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color>
+ <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color>
+ <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_dark</color>
+ <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color>
+ <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color>
+ <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color>
+ <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color>
+ <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color>
+ <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color>
+ <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_dark</color>
+ <color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color>
+ <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_dark</color>
+ <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color>
+ <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color>
+ <color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color>
+ <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_light</color>
+ <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_light</color>
+ <color name="settingslib_materialColorPrimaryFixed">@android:color/system_primary_fixed</color>
+ <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_light</color>
+ <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_light</color>
+ <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_light</color>
+ <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_light</color>
+ <color name="settingslib_materialColorOnError">@android:color/system_on_error_light</color>
+ <color name="settingslib_materialColorSurface">@android:color/system_surface_light</color>
+ <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_light</color>
+ <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_light</color>
+ <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_light</color>
+ <color name="settingslib_materialColorOutline">@android:color/system_outline_light</color>
+ <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_light</color>
+ <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_light</color>
+ <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_light</color>
+ <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_light</color>
+ <color name="settingslib_materialColorPrimary">@android:color/system_primary_light</color>
+ <color name="settingslib_materialColorSecondary">@android:color/system_secondary_light</color>
+ <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_light</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
index 5dfecb0..87cd2b8 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceModel.kt
@@ -70,26 +70,26 @@
is BlockedByAdmin -> {
Box(
Modifier
- .clickable(
- role = Role.Switch,
- onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() },
- )
- .semantics {
- this.toggleableState = ToggleableState(checked())
- },
+ .clickable(
+ role = Role.Switch,
+ onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() },
+ )
+ .semantics {
+ this.toggleableState = ToggleableState(checked())
+ },
) { content() }
}
is BlockedByEcm -> {
Box(
Modifier
- .clickable(
- role = Role.Switch,
- onClick = { restrictedMode.showRestrictedSettingsDetails() },
- )
- .semantics {
- this.toggleableState = ToggleableState(checked())
- },
+ .clickable(
+ role = Role.Switch,
+ onClick = { restrictedMode.showRestrictedSettingsDetails() },
+ )
+ .semantics {
+ this.toggleableState = ToggleableState(checked())
+ },
) { content() }
}
@@ -113,7 +113,7 @@
content: @Composable (SwitchPreferenceModel) -> Unit,
) {
val context = LocalContext.current
- val restrictedSwitchPreferenceModel = remember(restrictedMode) {
+ val restrictedSwitchPreferenceModel = remember(restrictedMode, model.title) {
RestrictedSwitchPreferenceModel(context, model, restrictedMode)
}
restrictedSwitchPreferenceModel.RestrictionWrapper {
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
index f812f95..5a6c0a1 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
@@ -27,9 +27,8 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.delay
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -72,12 +71,13 @@
DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {}
}
}
+ composeTestRule.delay()
assertThat(registeredBroadcastReceiver).isNotNull()
}
@Test
- fun broadcastReceiver_isCalledOnReceive() = runBlocking {
+ fun broadcastReceiver_isCalledOnReceive() {
var onReceiveIsCalled = false
composeTestRule.setContent {
CompositionLocalProvider(
@@ -91,7 +91,7 @@
}
registeredBroadcastReceiver!!.onReceive(context, Intent())
- delay(100)
+ composeTestRule.delay()
assertThat(onReceiveIsCalled).isTrue()
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
index 2e6a396..c1d298d 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
@@ -48,18 +48,7 @@
}
@Test
- fun settingsGlobalChangeFlow_collectAfterValueChanged_onlyKeepLatest() = runBlocking {
- var value by context.settingsGlobalBoolean(TEST_NAME)
- value = false
-
- val flow = context.settingsGlobalChangeFlow(TEST_NAME)
- value = true
-
- assertThat(flow.toListWithTimeout()).hasSize(1)
- }
-
- @Test
- fun settingsGlobalChangeFlow_collectBeforeValueChanged_getBoth() = runBlocking {
+ fun settingsGlobalChangeFlow_changed() = runBlocking {
var value by context.settingsGlobalBoolean(TEST_NAME)
value = false
@@ -69,7 +58,7 @@
delay(100)
value = true
- assertThat(listDeferred.await()).hasSize(2)
+ assertThat(listDeferred.await().size).isAtLeast(2)
}
private companion object {
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 5301985..9b98e55fa 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Kon nie \'n nuwe gebruiker skep nie"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Kon nie ’n nuwe gas skep nie"</string>
<string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Die naam en prent wat jy kies sal sigbaar wees vir enigiemand wat hierdie toestel gebruik."</string>
<string name="user_add_user" msgid="7876449291500212468">"Voeg gebruiker by"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index c5c5cdd..bfcdab4 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"á á²áµ á°á ááá ááá á á áá°á³á«á"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"á á²áµ á¥ááá³ ááá á á áá°á³á«á"</string>
<string name="user_nickname" msgid="262624187455825083">"á
áœá áµá"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ášáášá¡áµ áµá á¥á ááµá áá
á áá£áªá« ááá áá áááááá á°á ášáá³á ááááá¢"</string>
<string name="user_add_user" msgid="7876449291500212468">"á°á ááá á áá"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"á¥ááá³á á áá"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"á¥ááá³á á áµáááµ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 4fda845..68a19fc 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ØªØ¹Ø°ÙØ± Ø¥ÙØŽØ§Ø¡ Ù
ستخدÙ
Ø¬Ø¯ÙØ¯."</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ØªØ¹Ø°ÙØ± Ø¥ÙØŽØ§Ø¡ Ø¬ÙØ³Ø© ضÙÙ Ø¬Ø¯ÙØ¯Ø©."</string>
<string name="user_nickname" msgid="262624187455825083">"اÙÙÙØš"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ø³ÙØžÙر Ø§ÙØ§Ø³Ù
ÙØ§ÙØµÙØ±Ø© اÙÙØ°Ù٠تختارÙÙ
ا ÙØ£Ù ؎خص ÙØ³ØªØ®Ø¯Ù
ÙØ°Ø§ Ø§ÙØ¬Ùاز."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ø¥Ø¶Ø§ÙØ© Ù
ستخدÙ
"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ø¥Ø¶Ø§ÙØ© ضÙÙ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ø¥Ø²Ø§ÙØ© Ø¬ÙØ³Ø© Ø§ÙØ¶ÙÙ"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 2d14a82..e8caf32 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"àŠšàŠ€à§àŠš àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§°àŠàŠŸà§°à§ àŠžà§àŠ·à§àŠàŠ¿ àŠà§°àŠ¿àŠ¬ àŠªà§°àŠŸ àŠšàŠ’àŠ²"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"àŠšàŠ€à§àŠš àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠžà§àŠ·à§àŠàŠ¿ àŠà§°àŠ¿àŠ¬ àŠªà§°àŠŸ àŠšàŠ’àŠ²"</string>
<string name="user_nickname" msgid="262624187455825083">"àŠàŠªàŠšàŠŸàŠ®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àŠàŠ àŠ¡àŠ¿àŠàŠŸàŠàŠàŠà§ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠŸ àŠ¯àŠ¿àŠà§àŠšà§ àŠ²à§àŠà§ àŠàŠªà§àŠšàŠ¿ àŠ¬àŠŸàŠàŠšàŠ¿ àŠà§°àŠŸ àŠšàŠŸàŠ® àŠà§°à§ àŠàŠ¿àŠ€à§à§°àŠàŠš àŠŠà§àŠàŠŸ àŠªàŠŸàŠ¬à¥€"</string>
<string name="user_add_user" msgid="7876449291500212468">"àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§°àŠàŠŸà§°à§ àŠ¯à§àŠ àŠŠàŠ¿àŠ¯àŠŒàŠ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠ¯à§àŠ àŠŠàŠ¿àŠ¯àŠŒàŠ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠàŠàŠ€à§°àŠŸàŠàŠ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 0e3e99a..d37aaf1 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yeni istifadÉçi yaratmaq alınmadı"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yeni qonaq yaratmaq alınmadı"</string>
<string name="user_nickname" msgid="262624187455825083">"LÉqÉb"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Seçdiyiniz ad vÉ ÅÉkil bu cihazı istifadÉ edÉn hÉr kÉsÉ görünÉcÉk."</string>
<string name="user_add_user" msgid="7876449291500212468">"İstifadÉçi ÉlavÉ edin"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq ÉlavÉ edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"QonaÄı silin"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index c674a44..24a13cc 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Pravljenje novog korisnika nije uspelo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Pravljenje novog gosta nije uspelo"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ime i sliku koje izaberete videÄe svako ko koristi ovaj ureÄaj."</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodaj korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 9fe0680..2fb2b4c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ðе ÑЎалПÑÑ ÑÑваÑÑÑÑ ÐœÐŸÐ²Ð°Ð³Ð° каÑÑÑÑалÑМÑка"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ðе ÑЎалПÑÑ ÑÑваÑÑÑÑ ÐœÐŸÐ²Ð°Ð³Ð° гПÑÑÑ"</string>
<string name="user_nickname" msgid="262624187455825083">"ÐÑеÑЎаМÑÐŒ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐÑбÑаМÑÑ Ð²Ð°ÐŒÑ ÑÐŒÑ Ñ ÑПÑа бÑÐŽÑÑÑ Ð±Ð°ÑÑÑÑ ÑÑе каÑÑÑÑалÑМÑÐºÑ Ð³ÑÑай пÑÑлаЎÑ."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐаЎаÑÑ ÐºÐ°ÑÑÑÑалÑМÑка"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐаЎаÑÑ Ð³ÐŸÑÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐÑЎалÑÑÑ Ð³ÐŸÑÑÑ"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index b79c0e9..247b45b 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÐеÑÑпеÑМП ÑÑзЎаваМе Ма МПв пПÑÑебОÑел"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"СÑзЎаваМеÑП Ма МПв гПÑÑ ÐœÐµ бе ÑÑпеÑМП"</string>
<string name="user_nickname" msgid="262624187455825083">"ÐÑевЎПМОЌ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐзбÑаМОÑе ÐŸÑ Ð²Ð°Ñ ÐžÐŒÐµ О ÑМОЌка Ñе бÑÐŽÐ°Ñ Ð²ÐžÐŽÐžÐŒÐž за вÑОÑкО, кПОÑП ÐžÐ·Ð¿ÐŸÐ»Ð·Ð²Ð°Ñ ÑПва ÑÑÑÑПйÑÑвП."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐПбавÑМе Ма пПÑÑебОÑел"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПбавÑМе Ма гПÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐÑеЌаÑ
ваМе Ма гПÑÑа"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 31f693b..e6822d9 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"àŠšàŠ€à§àŠš àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ°àŠàŠŸàŠ°à§ àŠ¯à§àŠ àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¯àŠŒàŠšàŠ¿"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"àŠšàŠ€à§àŠš àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠ€à§àŠ°àŠ¿ àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¯àŠŒàŠšàŠ¿"</string>
<string name="user_nickname" msgid="262624187455825083">"àŠ¬àŠ¿àŠ¶à§àŠ· àŠšàŠŸàŠ®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àŠàŠªàŠšàŠŸàŠ° àŠ¬à§àŠà§ àŠšà§àŠàŠ¯àŠŒàŠŸ àŠšàŠŸàŠ® àŠ àŠàŠ¬àŠ¿, àŠàŠ àŠ¡àŠ¿àŠàŠŸàŠàŠž àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàаà§àŠš àŠàŠ®àŠš àŠ¯à§àŠà§àŠ àŠŠà§àŠàŠ€à§ àŠªàŠŸàŠ¬à§àŠšà¥€"</string>
<string name="user_add_user" msgid="7876449291500212468">"àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ°àŠàŠŸàŠ°à§àа àŠ
à§àŠ¯àŠŸàŠàŠŸàŠàŠšà§àŠ àŠ¯à§àŠ àŠàаà§àŠš"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠ¯à§àŠ àŠàаà§àŠš"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àŠ
àŠ€àŠ¿àŠ¥àŠ¿ àŠžàŠ°àŠŸàŠš"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index db203d6e..7eff2f1 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Kreiranje novog korisnika nije uspjelo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Kreiranje novog gosta nije uspjelo"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ime i slika koje odaberete Äe biti vidljivi svima koji koriste ovaj ureÄaj."</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodavanje korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 262adba..2fbc044 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"No s\'ha pogut crear l\'usuari"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"No s\'ha pogut crear un convidat"</string>
<string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"El nom i la foto que triïs seran visibles per a qualsevol persona que faci servir aquest dispositiu."</string>
<string name="user_add_user" msgid="7876449291500212468">"Afegeix un usuari"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 3845e98..334abc7 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -300,7 +300,7 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"Kodek Bluetooth Audio LDAC: Kvalita pÅehrávání"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Spustit zvukový kodek Bluetooth LDAC\nVýbÄr kodeku: kvalita pÅehrávání"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Streamování: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Soukromé DNS"</string>
+ <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Soukromý DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Vyberte soukromý reÅŸim DNS"</string>
<string name="private_dns_mode_off" msgid="7065962499349997041">"Vypnuto"</string>
<string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automaticky"</string>
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nového uÅŸivatele se nepodaÅilo vytvoÅit"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"VytvoÅení nového hosta se nezdaÅilo"</string>
<string name="user_nickname" msgid="262624187455825083">"PÅezdívka"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Vybrané jméno a obrázek uvidí všichni, kdo toto zaÅízení pouÅŸívají."</string>
<string name="user_add_user" msgid="7876449291500212468">"PÅidat uÅŸivatele"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"PÅidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 97676ad..e102b7e 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Der kunne ikke oprettes en ny bruger"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Der kunne ikke oprettes en ny gæst"</string>
<string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Det navn og billede, du vælger, er synligt for alle, der bruger denne enhed."</string>
<string name="user_add_user" msgid="7876449291500212468">"Tilføj bruger"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 02fd0e0..245ff80 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nutzer konnte nicht erstellt werden"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Fehler beim Erstellen eines neuen Gasts"</string>
<string name="user_nickname" msgid="262624187455825083">"Alias"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Der gewählte Name und das gewählte Bild sind für jeden Nutzer dieses Geräts sichtbar."</string>
<string name="user_add_user" msgid="7876449291500212468">"Nutzer hinzufügen"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index ce81fb7..5e41992 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Η δημιουργία νÎου χρήστη απÎτυχε"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Αποτυχία δημιουργίας νÎου επισκÎπτη"</string>
<string name="user_nickname" msgid="262624187455825083">"ΨευδÏνυμο"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Το Ïνομα και η εικÏνα που θα επιλÎξετε θα είναι ορατά σε Ïλους Ïσους χρησιμοποιοÏν αυτή τη συσκευή."</string>
<string name="user_add_user" msgid="7876449291500212468">"Προσθήκη χρήστη"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκÎπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκÎπτη"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 78e5b61..253cbc5 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"The name and picture you choose will be visible to anyone who uses this device."</string>
<string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 920f7b1a..4a03f34 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"The name and picture you choose will be visible to anyone who uses this device."</string>
<string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 78e5b61..253cbc5 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"The name and picture you choose will be visible to anyone who uses this device."</string>
<string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 78e5b61..253cbc5 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"The name and picture you choose will be visible to anyone who uses this device."</string>
<string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index dd83259..b7e0cda 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"The name and picture you choose will be visible to anyone who uses this device."</string>
<string name="user_add_user" msgid="7876449291500212468">"Add user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index a221d11..b0dc37c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -36,7 +36,7 @@
<string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string>
<string name="wifi_security_wep" msgid="1413627788581122366">"WEP"</string>
<string name="wifi_security_wpa" msgid="1072450904799930636">"WPA-Personal"</string>
- <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2 Personal"</string>
+ <string name="wifi_security_wpa2" msgid="4038267581230425543">"WPA2-Personal"</string>
<string name="wifi_security_wpa_wpa2" msgid="946853615482465986">"WPA/WPA2-Personal"</string>
<string name="wifi_security_eap" msgid="6179633834446852269">"WPA/WPA2/WPA3-Enterprise"</string>
<string name="wifi_security_eap_wpa" msgid="6189023812330549957">"WPA-Enterprise"</string>
@@ -111,7 +111,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de archivos"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acceso a Internet"</string>
- <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Permitir acc. a hist. de llam. y cont."</string>
+ <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acceso a contactos e historial de llamadas"</string>
<string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Se usará la inf. para anuncios de llamadas y otras funciones"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartir conexión a Internet"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensajes de texto"</string>
@@ -169,7 +169,7 @@
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Aplicaciones eliminadas"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Aplicaciones y usuarios eliminados"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Actualizaciones del sistema"</string>
- <string name="tether_settings_title_usb" msgid="3728686573430917722">"Conexión a red por USB"</string>
+ <string name="tether_settings_title_usb" msgid="3728686573430917722">"Conexión mediante USB"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Hotspot portátil"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Conexión Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Compartir conexión"</string>
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"No se pudo crear el usuario nuevo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"No se pudo crear un nuevo invitado"</string>
<string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"El nombre y la imagen que uses será visible para todas las personas que utilicen este dispositivo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Agregar usuario"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f6beab9..9f88c4a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -257,7 +257,7 @@
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Emparejando dispositivo…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"No se ha podido emparejar el dispositivo. El código QR no era correcto o el dispositivo no estaba conectado a la misma red."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Dirección IP y puerto"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanea el código QR"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanear código QR"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Empareja un dispositivo mediante WiâFi escaneando un código QR"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a una red Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depuración, desarrollo"</string>
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"No se ha podido crear el usuario"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"No se ha podido crear un nuevo invitado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Cualquier persona que use este dispositivo podrá ver el nombre y la imagen que elijas."</string>
<string name="user_add_user" msgid="7876449291500212468">"Añadir usuario"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index b6b9132..fe62b37 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Uue kasutaja loomine ebaõnnestus"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Uue külalise loomine ei õnnestunud"</string>
<string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Nimi ja pilt, mille valite, on nähtavad kõigile, kes seda seadet kasutavad."</string>
<string name="user_add_user" msgid="7876449291500212468">"Lisa kasutaja"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index b61388d..7d288f0 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ezin izan da sortu erabiltzailea"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ezin izan da sortu beste gonbidatu bat"</string>
<string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Gailua erabiltzen duten guztiek ikusi ahal izango dituzte aukeratu dituzun izena eta irudia."</string>
<string name="user_add_user" msgid="7876449291500212468">"Gehitu erabiltzaile bat"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatu bat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 28826bf..5834982 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -153,13 +153,13 @@
<item msgid="1333279807604675720">"استرÛÙ"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item msgid="1241278021345116816">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª ØµÙØª (Û¹Û¹Û° Ú©ÛÙÙØšÛت در ثاÙÛÙ/Û¹Û°Û¹ Ú©ÛÙÙØšÛت در ثاÙÛÙ)"</item>
+ <item msgid="1241278021345116816">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª صدا (Û¹Û¹Û° Ú©ÛÙÙØšÛت درثاÙÛÙ/Û¹Û°Û¹ Ú©ÛÙÙØšÛت درثاÙÛÙ)"</item>
<item msgid="3523665555859696539">"Ú©ÛÙÛØª Ù
ØªØ¹Ø§Ø¯Ù ØµÙØª ٠اتصا٠(Û¶Û¶Û° Ú©ÛÙÙØšÛت در ثاÙÛÙ/Û¶Û°Û¶ Ú©ÛÙÙØšÛت در ثاÙÛÙ)"</item>
<item msgid="886408010459747589">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª اتصا٠(Û³Û³Û° Ú©ÛÙÙØšÛت در ثاÙÛÙ/Û³Û°Û³ Ú©ÛÙÙØšÛت در ثاÙÛÙ)"</item>
<item msgid="3808414041654351577">"ØšÙØªØ±ÛÙ ØØ§Ùت (ÙØ±Ø® ØšÛØª تطؚÛÙÛ)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
- <item msgid="804499336721569838">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª ØµÙØª"</item>
+ <item msgid="804499336721569838">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª صدا"</item>
<item msgid="7451422070435297462">"Ú©ÛÙÛØª Ù
ØªØ¹Ø§Ø¯Ù ØµÙØª ٠اتصاÙ"</item>
<item msgid="6173114545795428901">"ØšÙÛÙÙØŽØ¯Ù ØšØ±Ø§Û Ú©ÛÙÛØª اتصاÙ"</item>
<item msgid="4349908264188040530">"ØšÙØªØ±ÛÙ ØØ§Ùت (ÙØ±Ø® ØšÛØª تطؚÛÙÛ)"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7938bc6..3945050 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"کارؚر Ø¬Ø¯ÛØ¯ Ø§ÛØ¬Ø§Ø¯ ÙØŽØ¯"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ù
ÙÙ
Ø§Ù Ø¬Ø¯ÛØ¯ Ø§ÛØ¬Ø§Ø¯ ÙØŽØ¯"</string>
<string name="user_nickname" msgid="262624187455825083">"ÙØ§Ù
Ù
ستعار"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÙØ§Ù
٠تصÙÛØ±Û Ú©Ù Ø§ÙØªØ®Ø§Øš Ù
ÛÚ©ÙÛØ¯ ØšØ±Ø§Û ÙÙ
Ù Ø§ÙØ±Ø§Ø¯Û ک٠از اÛÙ Ø¯Ø³ØªÚ¯Ø§Ù Ø§Ø³ØªÙØ§Ø¯Ù Ù
ÛÚ©ÙÙØ¯ ÙØ§ØšÙÙ
ØŽØ§ÙØ¯Ù Ø®ÙØ§Ùد ØšÙØ¯."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ø§ÙØ²Ùد٠کارؚر"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ø§ÙØ²Ùد٠Ù
ÙÙ
اÙ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ØØ°Ù Ù
ÙÙ
اÙ"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3ee7dc1..6f9dabc 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Uuden käyttäjän luominen epäonnistui"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Uutta vierasta ei voitu luoda"</string>
<string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Valitsemasi nimi ja kuva näkyvät kaikille tämän laitteen käyttäjille."</string>
<string name="user_add_user" msgid="7876449291500212468">"Lisää käyttäjä"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 95a4e62..56e6900 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Impossible de créer un utilisateur"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un nouvel invité"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Le nom et l\'image que vous choisissez seront visibles par toute personne qui utilise cet appareil."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ajouter un utilisateur"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e26e8b0..b48f637 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Échec de la création d\'un utilisateur"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un profil invité"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Toute personne utilisant cet appareil pourra voir votre nom ainsi que votre photo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ajouter un utilisateur"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index 5d6ef37..e6d098f 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -153,13 +153,13 @@
<item msgid="1333279807604675720">"Estéreo"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item msgid="1241278021345116816">"Optimizado para a calidade do audio (990 kb/s ou 909 kb/s)"</item>
+ <item msgid="1241278021345116816">"Optimizado para a calidade de audio (990 kb/s ou 909 kb/s)"</item>
<item msgid="3523665555859696539">"Calidade equilibrada do audio e da conexión (660 kb/s ou 606 kb/s)"</item>
<item msgid="886408010459747589">"Optimizado para a calidade da conexión (330 kb/s ou 303 kb/s)"</item>
<item msgid="3808414041654351577">"Máxima (taxa de bits adaptable)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
- <item msgid="804499336721569838">"Optimizado para a calidade do audio"</item>
+ <item msgid="804499336721569838">"Optimizado para a calidade de audio"</item>
<item msgid="7451422070435297462">"Calidade equilibrada do audio e da conexión"</item>
<item msgid="6173114545795428901">"Optimizado para a calidade da conexión"</item>
<item msgid="4349908264188040530">"Máxima (taxa de bits adaptable)"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 53332bf..0fe4a40 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Non se puido crear un novo usuario"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Produciuse un erro ao crear o convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Calquera que use este dispositivo poderá ver o nome e a imaxe que selecciones."</string>
<string name="user_add_user" msgid="7876449291500212468">"Engadir usuario"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e792e9f..829171c 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ચવૠવપરટશàªàª°à«àª€àªŸ બચટવવટમટઠચિષà«àª«àª³"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ચવૠàª
઀િથિ બચટવવટમટઠચિષà«àª«àª³ રહà«àª¯àªŸàª"</string>
<string name="user_nickname" msgid="262624187455825083">"àªàªªàªšàªŸàª®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"઀મૠàªà« ચટમ àª
ચૠàªàª¿àª€à«àª° પઞàªàªŠ àªàª°à«, ઀à«àªšà« ઠડિવટàªàªžàªšà« àªàªªàª¯à«àª àªàª°àªšàªŸàª°à« àªà«àªàªªàª£ વà«àª¯àªà«àª€àª¿ àªà«àª શàªàª¶à«."</string>
<string name="user_add_user" msgid="7876449291500212468">"વપરટશàªàª°à«àª€àªŸ àªàª®à«àª°à«"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"àª
઀િથિ àªàª®à«àª°à«"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àª
઀િથિચૠàªàªŸàª¢à« ચટàªà«"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index ae9e29a..2ce8f9b 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"à€šà€¯à€Ÿ à€à€ªà€¯à¥à€à€à€°à¥à€€à€Ÿ à€à¥à€¡à€Œà€Ÿ à€šà€¹à¥à€ à€à€Ÿ à€žà€à€Ÿ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"à€šà€¯à€Ÿ à€®à¥à€¹à€®à€Ÿà€š à€à€Ÿà€€à€Ÿ à€šà€¹à¥à€ à€¬à€šà€Ÿà€¯à€Ÿ à€à€Ÿ à€žà€à€Ÿ"</string>
<string name="user_nickname" msgid="262624187455825083">"à€ªà¥à€°à€à€²à€¿à€€ à€šà€Ÿà€®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à€à€ªà€à¥ à€à¥à€šà¥ à€à€ à€«à€Œà¥à€à¥ à€à€° à€šà€Ÿà€®, à€à€š à€žà€à¥ à€²à¥à€à¥à€ à€à¥ à€Šà€¿à€à¥à€à€Ÿ à€à¥ à€à€ž à€¡à€¿à€µà€Ÿà€à€ž à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€€à¥ à€¹à¥à€."</string>
<string name="user_add_user" msgid="7876449291500212468">"à€à€ªà€¯à¥à€à€à€°à¥à€€à€Ÿ à€à¥à€¡à€Œà¥à€"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à€®à¥à€¹à€®à€Ÿà€š à€à¥à€¡à€Œà¥à€"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à€®à¥à€¹à€®à€Ÿà€š à€à¥ à€¹à€à€Ÿà€à€"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 1e12d96..9c0ef25 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Izrada novog korisnika nije uspjela"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Izrada novog gosta nije uspjela"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ime i slika koje odaberete bit Äe vidljivi svima koji koriste ovaj ureÄaj."</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodajte korisnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajte gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 0e5b1de..d2a959a 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Az új felhasználó létrehozása sikertelen"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Az új vendég létrehozása nem sikerült"</string>
<string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"A kiválasztott név és kép mindenki számára látható lesz, aki ezt az eszközt használja."</string>
<string name="user_add_user" msgid="7876449291500212468">"Felhasználó hozzáadása"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 6e0dd49..80ff58e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÕÕ°Õ¡Õ»ÕžÕ²ÕŸÕ¥Ö ÕœÕ¿Õ¥Õ²Õ®Õ¥Õ¬ Õ¶ÕžÖ Ö
Õ£Õ¿Õ¡Õ¿Õ¥Ö"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ÕÕ°Õ¡Õ»ÕžÕ²ÕŸÕ¥Ö Õ¶ÕžÖ Õ°ÕµÕžÖÖ ÕœÕ¿Õ¥Õ²Õ®Õ¥Õ¬"</string>
<string name="user_nickname" msgid="262624187455825083">"Ô¿Õ¥Õ²Õ®Õ¡Õ¶ÕžÖÕ¶"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÕÕ¥Ö ÕšÕ¶Õ¿ÖÕ¡Õ® Õ¡Õ¶ÕžÖÕ¶Õ¶ ÕžÖ Õ¶Õ¯Õ¡ÖÕš տե՜անելի Õ¯Õ¬Õ«Õ¶Õ¥Õ¶ Õ¡ÕµÕœ ՜աÖÖÕ¶ Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕžÕ² Õ¢ÕžÕ¬ÕžÖ ÕŽÕ¡ÖÕ€Õ¯Õ¡Õ¶ÖÖ"</string>
<string name="user_add_user" msgid="7876449291500212468">"Ô±ÕŸÕ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Ö
Õ£Õ¿Õ¡Õ¿Õ¥Ö"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ô±ÕŸÕ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ°ÕµÕžÖÖ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÕեՌաÖÕ¶Õ¥Õ¬ Õ°ÕµÕžÖÖÕ«Õ¶"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 8afffaa..d5ae5b8 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baru"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tamu baru"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Nama dan gambar yang Anda pilih dapat dilihat oleh siapa saja yang menggunakan perangkat ini."</string>
<string name="user_add_user" msgid="7876449291500212468">"Tambahkan pengguna"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b322665..91fcb4c 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ekki tókst að stofna nýjan notanda"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ekki tókst að búa til nýjan gest"</string>
<string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Allir sem nota þetta tæki geta séð nafnið og myndina sem þú velur."</string>
<string name="user_add_user" msgid="7876449291500212468">"Bæta notanda við"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 43aded0..865f451 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Creazione nuovo utente non riuscita"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Impossibile creare un nuovo ospite"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Il nome e l\'immagine che scegli saranno visibili a chiunque utilizzi questo dispositivo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Aggiungi utente"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 990d9ac..3064f68 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"×× × ××ª× ××× ××׊×ך ×שת×ש ××ש"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"×׊×ךת ×××š× ××ש × ×ש××"</string>
<string name="user_nickname" msgid="262624187455825083">"××× ××"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"××©× ××ת××× × ×©×××××š× ×××× ×××××× ××× ×× ×©×שת×ש ×××ש×ך ×××."</string>
<string name="user_add_user" msgid="7876449291500212468">"××ס׀ת ×שת×ש"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"××ס׀ת ××ך×"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"×סךת ××ך×"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7029f8c..f3cddd3 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"æ°ãããŠãŒã¶ãŒãäœæã§ããŸããã§ãã"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"æ°ããã²ã¹ããäœæã§ããŸããã§ãã"</string>
<string name="user_nickname" msgid="262624187455825083">"ããã¯ããŒã "</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"éžæããååãšåçã¯ããã®ããã€ã¹ã䜿çšããŠãããã¹ãŠã®ãŠãŒã¶ãŒãèŠãããšãã§ããŸãã"</string>
<string name="user_add_user" msgid="7876449291500212468">"ãŠãŒã¶ãŒã远å "</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ã²ã¹ãã远å "</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ã²ã¹ããåé€"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 461f211..3a40b8e 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"áá®ááá áááá®ááá ááááá¡ ášáá¥ááá ááá ááá®áá á®áá"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"áá®ááá á¡á¢á£áá áá¡ ášáá¥ááá ááá ááá®áá á®áá"</string>
<string name="user_nickname" msgid="262624187455825083">"ááá¢á¡áá®ááá"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"áá¥ááá áááá áá á©áá£áá á¡áá®ááá áá á¡á£á ááá áá ááá¬á§áááááááá ááá¡áá ááááá ááááá¡áááá á ááá áá¡áááá¡ áá¥áááá á®áááááá."</string>
<string name="user_add_user" msgid="7876449291500212468">"áááá®ááá ááááá¡ ááááá¢ááá"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"á¡á¢á£áá áá¡ ááááá¢ááá"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"á¡á¢á£áá áá¡ áááášáá"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 77d9f8b..856a51e 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ðаңа пайЎалаМÑÑÑ Ð¶Ð°ÑалЌаЎÑ."</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ðаңа ÒÐŸÐœÐ°Ò Ð¿ÑПÑÐžÐ»Ñ Ð¶Ð°ÑалЌаЎÑ."</string>
<string name="user_nickname" msgid="262624187455825083">"ÐаÒап аÑ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"СÑз ÑаңЎаÒаМ Ð°Ñ Ð¿ÐµÐœ ÑÑÑÐµÑ ÐŸÑÑ ÒÒ±ÑÑлÒÑÐœÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÐ°ÑÑМ кез келгеМ аЎаЌÒа көÑÑМеÑÑМ бПлаЎÑ."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐайЎалаМÑÑÑ ÒПÑÑ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÒÐŸÐœÐ°Ò ÒПÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÒПМаÒÑÑ Ð¶ÐŸÑ"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 7e57b15..719eed0 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"áá·áâá¢á¶á
âáááááŸáâá¢áááááááŸáááá¶áááááážâáá¶ááá"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"áá·áá¢á¶á
áááááŸáááááááááážáá¶ááá"</string>
<string name="user_nickname" msgid="262624187455825083">"áááááâá á
áááá
"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ááááá áá·áááŒááá¶ááááá¢áááááááŸáááŸááá¹áá¢á¶á
ááŸáááŸááááá¢áááááááááááá¶áááááááŸá§ááááááááá"</string>
<string name="user_add_user" msgid="7876449291500212468">"áááá
áŒáâá¢áááâááááŸáááá¶áá"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"áááá
áŒáâááááá"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"áááááááá
áá"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 6737cdc..aa69689 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ಹà³à²ž ಬಳà²à³à²Šà²Ÿà²°à²°à²šà³à²šà³ ರà²à²¿à²žà²²à³ ವಿಫಲವಟà²à²¿à²Šà³"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ಹà³à²ž à²
ಀಿಥಿಯಚà³à²šà³ ರà²à²¿à²žà²²à³ ವಿಫಲವಟà²à²¿à²Šà³"</string>
<string name="user_nickname" msgid="262624187455825083">"à²
ಡà³à²¡ ಹà³à²žà²°à³"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ಚà³à²µà³ à²à²¯à³à²à³à²®à²Ÿà²¡à²¿à²Š ಹà³à²žà²°à³ ಮಀà³à²€à³ à²à²¿à²€à³à²°à²µà²šà³à²šà³ ಠಞಟಧಚವಚà³à²šà³ ಬಳಞà³à²µ ಯಟರಟಊರೠಚà³à²¡à²¬à²¹à³à²Šà³."</string>
<string name="user_add_user" msgid="7876449291500212468">"ಬಳà²à³à²Šà²Ÿà²°à²°à²šà³à²šà³ ಞà³à²°à²¿à²žà²¿"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à²
ಀಿಥಿಯಚà³à²šà³ ಞà³à²°à²¿à²žà²¿"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à²
ಀಿಥಿಯಚà³à²šà³ ಀà³à²à³à²Šà³à²¹à²Ÿà²à²¿"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index be472a1..79e119b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ì ì¬ì©ì륌 ë§ë€ì§ 못íš"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ì ê²ì€íž ìì± ì€íš"</string>
<string name="user_nickname" msgid="262624187455825083">"ëë€ì"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ì íí ìŽëŠê³Œ ì¬ì§ìŽ ìŽ êž°êž°ë¥Œ ì¬ì©íë 몚ë ì¬ì©ììê² íìë©ëë€."</string>
<string name="user_add_user" msgid="7876449291500212468">"ì¬ì©ì ì¶ê°"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ê²ì€íž ì¶ê°"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ê²ì€íž ìì "</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 94c0fd1..c547bb8b 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÐÐ°Ò£Ñ ÐºÐŸÐ»ÐŽÐŸÐœÑÑÑÑ Ñүзүлбөй калЎÑ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ÐÐ°Ò£Ñ ÐºÐŸÐœÐŸÐº ÑүзүлгөМ жПк"</string>
<string name="user_nickname" msgid="262624187455825083">"Ылакап аÑÑ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"СОз ÑаМЎагаМ аÑалÑÑ Ð¶Ð°ÐœÐ° ÑÒ¯ÑÓ©Ñ ÑÑÑл ÑүзЌөкÑÒ¯ кПлЎПМгПМЎПÑÐŽÑМ бааÑÑМа көÑүМөÑ."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐПлЎПМÑÑÑÑ ÐºÐŸÑÑÑ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПМПк кПÑÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐПМПкÑÑ Ó©ÑÒ¯ÑÒ¯Ò¯"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 0368898..c352c78 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ສà»àº²àºàºàº¹à»à»àºà»à»à»à»àºà»à»àºªàº³à»àº¥àº±àº"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ສà»àº²àºà»àºàºà»à»à»àºà»à»àºªàº³à»àº¥àº±àº"</string>
<string name="user_nickname" msgid="262624187455825083">"àºàº·à»àº«àºŒàºŽà»àº"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àºàºžàºàºàº»àºàºàºµà»à»àºà»àºàºžàºàº°àºàºàºàºàºµà»àºàº°à»àº«àº±àºàºàº·à» à»àº¥àº° ຮູàºàºàºµà»àºà»àº²àºà»àº¥àº·àºàº."</string>
<string name="user_add_user" msgid="7876449291500212468">"à»àºàºµà»àº¡àºàº¹à»à»àºà»"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à»àºàºµà»àº¡à»àºàº"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ລຶàºà»àºàºàºàºàº"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index de0add8..21cd1d8 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nepavyko sukurti naujo naudotojo"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Nepavyko sukurti naujo gesto"</string>
<string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Pasirinktas vardas ir nuotrauka bus matomi visiems šio įrenginio naudotojams."</string>
<string name="user_add_user" msgid="7876449291500212468">"PridÄti naudotojÄ
"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"PridÄti sveÄiÄ
"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti sveÄiÄ
"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 1d627f3..bcaaf2c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"NeizdevÄs izveidot jaunu lietotÄju"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"NeizdevÄs izveidot jaunu viesa profilu"</string>
<string name="user_nickname" msgid="262624187455825083">"SegvÄrds"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"JÅ«su izvÄlÄtais vÄrds un attÄls bÅ«s redzams visiem šÄ«s ierÄ«ces lietotÄjiem."</string>
<string name="user_add_user" msgid="7876449291500212468">"Pievienot lietotÄju"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"NoÅemt viesi"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 3bcabd6..4dc6be0 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ðе ÑÑпеа Ўа ÑПзЎаЎе МПв кПÑОÑМОк"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ðе ÑÑпеа ÑПзЎаваÑеÑП МПв гПÑÑОМ"</string>
<string name="user_nickname" msgid="262624187455825083">"ÐÑекаÑ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐЌеÑП О ÑлОкаÑа ÑÑП Ñе гО ОзбеÑеÑе Ñе Ð±ÐžÐŽÐ°Ñ Ð²ÐžÐŽÐ»ÐžÐ²Ðž за ÑÐµÐºÐŸÑ ÑÑП гП кПÑОÑÑО ÑÑеЎПв."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐПЎаÑÑе кПÑОÑМОк"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПЎаÑÑе гПÑÑОМ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐÑÑÑÑаМО гПÑÑОМ"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index b21d3cf..f92f7b0 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"àŽªàµàŽ€àŽ¿àŽ¯ àŽàŽªàŽ¯àµàŽàµàŽ€àŽŸàŽµàŽ¿àŽšàµ àŽžàµàŽ·àµàŽàŽ¿àŽàµàŽàŽŸàŽšàŽŸàŽ¯àŽ¿àŽ²àµà޲"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"àŽªàµàŽ€àŽ¿àŽ¯ àŽ
àŽ€àŽ¿àŽ¥àŽ¿àŽ¯àµ àŽžàµàŽ·àµàŽàŽ¿àŽàµàŽàŽŸàŽšàŽŸàŽ¯àŽ¿àŽ²àµà޲"</string>
<string name="user_nickname" msgid="262624187455825083">"àŽµàŽ¿àŽ³àŽ¿àŽªàµàŽªàµàްàµ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àŽšàŽ¿àŽàµàŽàµŸ àŽ€àŽ¿àŽ°àŽàµàŽàµàŽàµàŽ€àµàŽ€ àŽªàµàްàµàŽ àŽàŽ¿àŽ€àµàŽ°àŽµàµàŽ àŽ àŽàŽªàŽàŽ°àŽ£àŽ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµàŽšàµàŽš àŽà޲àµàŽ²àŽŸàŽµàµŒàŽàµàŽàµàŽ àŽŠàµà޶àµàŽ¯àŽ®àŽŸàŽàµàŽ."</string>
<string name="user_add_user" msgid="7876449291500212468">"àŽàŽªàŽ¯àµàŽàµàŽ€àŽŸàŽµàŽ¿àŽšàµ àŽàµàµŒàŽàµàŽàµàŽ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"àŽ
àŽ€àŽ¿àŽ¥àŽ¿àŽ¯àµ àŽàµàµŒàŽàµàŽàµàŽ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àŽ
àŽ€àŽ¿àŽ¥àŽ¿àŽ¯àµ àŽšàµàŽàµàŽàŽ àŽàµàޝàµàޝàµàŽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index dbdb694..237f6a7 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÐšÐžÐœÑ Ñ
ÑÑÑглÑÐ³Ñ Ò¯Ò¯ÑгÑж ÑаЎÑаМгүй"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ÐšÐžÐœÑ Ð·ÐŸÑОМ Ò¯Ò¯ÑгÑж ÑаЎÑаМгүй"</string>
<string name="user_nickname" msgid="262624187455825083">"ХПÑ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ð¢Ð°ÐœÑ ÑПМгПÑПМ МÑÑ Ð±ÐŸÐ»ÐŸÐœ зÑÑаг ÑÐœÑ ÑÓ©Ñ
Ó©Ó©ÑөЌжОйг аÑОглаЎаг Ñ
үМ бүÑÐŽ Ñ
аÑагЎаМа."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ð¥ÑÑÑглÑÐ³Ñ ÐœÑÐŒÑÑ
"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПÑОМ МÑÐŒÑÑ
"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐПÑОМ Ñ
аÑаÑ
"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index b270f41..9edfd53 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"à€šà€µà¥à€š à€µà€Ÿà€ªà€°à€à€°à¥à€€à€Ÿ à€€à€¯à€Ÿà€° à€à€°à€€à€Ÿ à€à€²à€Ÿ à€šà€Ÿà€¹à¥"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"à€šà€µà¥à€š à€
à€€à€¿à€¥à¥ à€€à€¯à€Ÿà€° à€à€°à€€à€Ÿ à€à€²à€Ÿ à€šà€Ÿà€¹à¥"</string>
<string name="user_nickname" msgid="262624187455825083">"à€à¥à€ªà€£à€šà€Ÿà€µ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à€¹à¥ à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž à€µà€Ÿà€ªà€°à€£à€Ÿà€±à¥à€¯à€Ÿ à€à¥à€£à€€à¥à€¯à€Ÿà€¹à¥ à€µà¥à€¯à€à¥à€€à¥à€²à€Ÿ à€€à¥à€®à¥à€¹à¥ à€šà€¿à€µà€¡à€²à¥à€²à¥ à€šà€Ÿà€µ à€à€£à€¿ à€«à¥à€à¥ à€Šà€¿à€žà¥à€²."</string>
<string name="user_add_user" msgid="7876449291500212468">"à€µà€Ÿà€ªà€°à€à€°à¥à€€à€Ÿ à€à¥à€¡à€Ÿ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à€
à€€à€¿à€¥à¥ à€à¥à€¡à€Ÿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à€
à€€à€¿à€¥à¥ à€à€Ÿà€¢à¥à€š à€à€Ÿà€à€Ÿ"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 1bc0f20..c21c39a 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baharu"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tetamu baharu"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Nama dan gambar yang anda pilih akan dipaparkan kepada sesiapa sahaja yang menggunakan peranti ini."</string>
<string name="user_add_user" msgid="7876449291500212468">"Tambah pengguna"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2b9ae6d..5943d78 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"á¡áá¯á¶ážááŒá¯áá°á¡áá
ẠááŒá¯áá¯ááºááááá«"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"á§áá·áºáááºáá
ẠááŒá¯áá¯ááºááááá«"</string>
<string name="user_nickname" msgid="262624187455825083">"áá¬áááºááŒá±á¬ááº"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"áááºááœá±ážáá±á¬ á¡áááºááŸáá·áºáá¯á¶ááᯠá€á
ááºáá¯á¶ážáá° áááºáá°áááᯠááŒááºááá¯ááºáááºá"</string>
<string name="user_add_user" msgid="7876449291500212468">"á¡áá¯á¶ážááŒá¯áá° ááá·áºáááº"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"á§áá·áºááẠááá·áºáááº"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"á§áá·áºáááºááᯠáááºááŸá¬ážáááº"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 4a3363f..338623e 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Kunne ikke opprette noen ny bruker"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Kunne ikke opprette en ny gjest"</string>
<string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Navnet og bildet du velger, blir synlige for alle som bruker denne enheten."</string>
<string name="user_add_user" msgid="7876449291500212468">"Legg til bruker"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 7ba6ca0..c06e649 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"à€šà€¯à€Ÿà€ à€ªà¥à€°à€¯à¥à€à€à€°à¥à€€à€Ÿ à€žà€¿à€°à¥à€à€šà€Ÿ à€à€°à¥à€š à€žà€à€¿à€à€š"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"à€šà€¯à€Ÿà€ à€
à€€à€¿à€¥à€¿ à€¬à€šà€Ÿà€à€š à€žà€à€¿à€à€š"</string>
<string name="user_nickname" msgid="262624187455825083">"à€à€ªà€šà€Ÿà€®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à€¯à¥ à€¡à€¿à€à€Ÿà€à€ž à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€žà€¬à¥ à€à€šà€Ÿ à€€à€ªà€Ÿà€à€à€²à¥ à€à€šà¥à€ à€à€°à¥à€šà¥ à€šà€Ÿà€® à€° à€«à¥à€à¥ à€Šà¥à€à¥à€š à€žà€à¥à€šà¥ à€à€šà¥à¥€"</string>
<string name="user_add_user" msgid="7876449291500212468">"à€ªà¥à€°à€¯à¥à€à€à€°à¥à€€à€Ÿ à€à€šà¥à€à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à€
à€€à€¿à€¥à€¿ à€à€šà¥à€à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à€à¥à€žà¥à€ à€®à¥à€¡à€¬à€Ÿà€ à€¬à€Ÿà€¹à€¿à€° à€šà€¿à€žà¥à€à€¿à€¯à¥à€žà¥"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 79d918a..b405903 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -180,7 +180,7 @@
<string name="launch_defaults_some" msgid="3631650616557252926">"Enkele standaardwaarden ingesteld"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Geen standaardwaarden ingesteld"</string>
<string name="tts_settings" msgid="8130616705989351312">"Instellingen tekst-naar-spraak"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"Tekst-naar-spraakuitvoer"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"Tekst-naar-spraak-uitvoer"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Spreeksnelheid"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Snelheid waarmee de tekst wordt gesproken"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Toonhoogte"</string>
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Kan geen nieuwe gebruiker maken"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Kan geen nieuwe gast maken"</string>
<string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"De naam en afbeelding die je kiest, zijn zichtbaar voor iedereen die dit apparaat gebruikt."</string>
<string name="user_add_user" msgid="7876449291500212468">"Gebruiker toevoegen"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 9ab80d0..3b28783 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ଚàଠà¬à¬ªà¬¯àà¬à¬à¬°à଀à଀ଟ ଀ିà¬à¬°à¬¿ à¬à¬°à¬¿à¬¬à¬Ÿà¬à ବିଫଳ ହàଲଟ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"à¬à¬£à ଚàଠà¬
଀ିଥି ଀ିà¬à¬°à¬¿ à¬à¬°à¬¿à¬¬à¬Ÿà¬°à ବିଫଳ ହàà¬à¬à¬¿"</string>
<string name="user_nickname" msgid="262624187455825083">"ଡଟà¬à¬šà¬Ÿà¬®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à¬à¬ªà¬£ ବଟà¬à¬¿à¬¥à¬¿à¬¬à¬Ÿ ଚଟମ à¬à¬¬à¬ à¬à¬¬à¬¿ à¬à¬¹à¬¿ ଡିà¬à¬Ÿà¬à¬ž ବààବହଟର à¬à¬°àଥିବଟ ଯà à¬àଣଞି ବààà¬à଀ିà¬àà¬à ଊàà¬à¬Ÿà¬¯à¬¿à¬¬à¥€"</string>
<string name="user_add_user" msgid="7876449291500212468">"ààà¬à¬° ଯàଠà¬à¬°à¬šà଀à"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à¬
଀ିଥି ଯàଠà¬à¬°à¬šà଀à"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à¬
଀ିଥିà¬àà¬à à¬à¬Ÿà¬¢à¬Œà¬¿ ଊିà¬
ଚà଀à"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 2932338..41de824 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"àššàšµàšŸàš àšµàš°àš€à©àšàšàšŸàš° àš¬àš£àšŸàšàš£àšŸ àš
àšžàš«àš² àš°àš¿àš¹àšŸ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"àššàšµàšŸàš àš®àš¹àš¿àš®àšŸàšš àšªà©àš°à©àš«àšŸàšàš² àš¬àš£àšŸàšàš£àšŸ àš
àšžàš«àš² àš°àš¿àš¹àšŸ"</string>
<string name="user_nickname" msgid="262624187455825083">"àšàšªàššàšŸàš®"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àš€à©àš¹àšŸàš¡à© àšµà©±àš²à©àš àšà©àš£àš¿àš àšàš¿àš àššàšŸàš® àš
àš€à© àš€àšžàšµà©àš° àšàšž àš¡à©àšµàšŸàšàšž àšŠà© àšµàš°àš€à©àš àšàš°àšš àšµàšŸàš²à© àšàš¿àšžà© àšµà© àšµàš¿àš
àšàš€à© àššà©à©° àšŠàš¿àšàšŸàš àšŠà©àšµà©àšà©à¥€"</string>
<string name="user_add_user" msgid="7876449291500212468">"àšµàš°àš€à©àšàšàšŸàš° àššà©à©° àšžàšŒàšŸàš®àš² àšàš°à©"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"àš®àš¹àš¿àš®àšŸàšš àšžàšŒàšŸàš®àš² àšàš°à©"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àš®àš¹àš¿àš®àšŸàšš àš¹àšàšŸàš"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a7d59cf..0c2d71b 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -257,7 +257,7 @@
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"ParujÄ urzÄ
dzenie…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Nie udaÅo siÄ sparowaÄ z urzÄ
dzeniem. Kod QR jest nieprawidÅowy albo urzÄ
dzenie nie jest podÅÄ
czone do tej samej sieci."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adres IP i port"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skaner kodów QR"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Zeskanuj kod QR"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sparuj urzÄ
dzenia przez Wi-Fi, skanujÄ
c kod QR"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"PoÅÄ
cz siÄ z sieciÄ
Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nie udaÅo siÄ utworzyÄ nowego uÅŒytkownika"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Nie udaÅo siÄ utworzyÄ nowego goÅcia"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Nazwa i zdjÄcie, które wybierzesz, bÄdÄ
widoczne dla kaÅŒdego, kto uÅŒywa tego urzÄ
dzenia."</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodaj uÅŒytkownika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj goÅcia"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"UsuÅ goÅcia"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index bb83c2b..aea8666 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"O nome e a foto escolhidos ficarão visíveis para qualquer pessoa que usar este dispositivo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Adicionar usuário"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar visitante"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover visitante"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 4554f85..e0fd5e7 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo utilizador"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Alcunha"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"O nome e a imagem que escolher ficam visíveis para qualquer pessoa que use este dispositivo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Adicionar utilizador"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index bb83c2b..aea8666 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"O nome e a foto escolhidos ficarão visíveis para qualquer pessoa que usar este dispositivo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Adicionar usuário"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar visitante"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover visitante"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 1482ee5..92eeb2f 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nu s-a creat noul utilizator"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Nu s-a putut crea un invitat nou"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ToatÄ lumea care foloseÈte dispozitivul va vedea numele Èi fotografia pe care le-ai ales."</string>
<string name="user_add_user" msgid="7876449291500212468">"AdaugÄ un utilizator"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"AdaugÄ un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Èterge invitatul"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 7fa3f18..c78bdec 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ðе ÑЎалПÑÑ ÑПзЎаÑÑ Ð¿ÐŸÐ»ÑзПваÑелÑ"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ðе ÑЎалПÑÑ ÑПзЎаÑÑ Ð³ÐŸÑÑÑ."</string>
<string name="user_nickname" msgid="262624187455825083">"ÐÑевЎПМОЌ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐÑбÑаММÑе ваЌО ÐžÐŒÑ Ð¿ÐŸÐ»ÑзПваÑÐµÐ»Ñ Ðž ÑПÑП пÑПÑÐžÐ»Ñ Ð±ÑÐŽÑÑ Ð²ÐžÐŽÐœÑ Ð²ÑеЌ, кÑП ОÑпПлÑзÑÐµÑ ÑÑП ÑÑÑÑПйÑÑвП."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐПбавОÑÑ Ð¿ÐŸÐ»ÑзПваÑелÑ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПбавОÑÑ Ð³ÐŸÑÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"УЎалОÑÑ Ð°ÐºÐºÐ°ÑÐœÑ Ð³ÐŸÑÑÑ"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index ec40926..9239237 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"න෠ඎරà·à·à·à¶œà¶à¶ºà·à¶à· à¶à·à¶±à·à¶žà¶§ à¶
à·à¶žà¶à· à·à·à¶º"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"න෠à¶
à¶žà·à¶à·à¶à¶à· à¶à·à¶±à·à¶ž à¶
à·à·à¶»à·à¶®à¶ à·à·à¶º"</string>
<string name="user_nickname" msgid="262624187455825083">"à¶
à¶Žà¶±à·à¶žà¶º"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à¶à¶¶ à¶à·à¶»à· à¶à¶±à·à¶±à· නඞ à·à· à¶Žà·à¶±à·à¶à·à¶»à¶º à¶žà·à¶ž à¶à¶Žà·à¶à¶à¶º à¶·à·à·à·à¶à· à¶à¶»à¶± à¶à¶±à·à¶ž à¶à·à¶±à·à¶à·à¶§ දà·à·à·à¶ºà¶žà·à¶± à·à¶±à· à¶à¶."</string>
<string name="user_add_user" msgid="7876449291500212468">"à¶Žà¶»à·à·à·à¶œà¶à¶ºà· à¶à¶à· à¶à¶»à¶±à·à¶±"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à¶
à¶žà·à¶à·à¶à· à¶à¶à· à¶à¶»à¶±à·à¶±"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à¶
à¶žà·à¶à·à¶à· à¶à·à¶à· à¶à¶»à¶±à·à¶±"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 4b90a91..2778f8d 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Nového pouÅŸív. sa nepodarilo vytvoriÅ¥"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Nového hosÅ¥a sa nepodarilo vytvoriÅ¥"</string>
<string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Názov a obrázok, ktorý vyberiete, budú vidieÅ¥ všetci pouÅŸívatelia tohto zariadenia."</string>
<string name="user_add_user" msgid="7876449291500212468">"PridaÅ¥ pouÅŸívateÄŸa"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index f04e839..b1ca328 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ustvarjanje novega uporabnika ni uspelo."</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ustvarjanje novega gosta ni uspelo."</string>
<string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Ime in slika, ki ju izberete, bosta vidna za vse, ki uporabljajo to napravo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Dodaj uporabnika"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstrani gosta"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 6721987..e46a4d8 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Krijimi i një përdoruesi të ri dështoi"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Profili i vizitorit të ri nuk u krijua"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Emri dhe fotografia që zgjedh ti do të jenë të dukshme për çdo person që përdor këtë pajisje."</string>
<string name="user_add_user" msgid="7876449291500212468">"Shto përdorues"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Shto vizitor"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq vizitorin"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 5497c6e..cc4cd5f 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÐÑавÑеÑе МПвПг кПÑОÑМОка МОÑе ÑÑпелП"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ÐÑавÑеÑе МПвПг гПÑÑа МОÑе ÑÑпелП"</string>
<string name="user_nickname" msgid="262624187455825083">"ÐаЎОЌак"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐЌе О ÑÐ»ÐžÐºÑ ÐºÐŸÑе ОзабеÑеÑе вОЎеÑе ÑвакП кП кПÑОÑÑО ÐŸÐ²Ð°Ñ ÑÑеÑаÑ."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐÐŸÐŽÐ°Ñ ÐºÐŸÑОÑМОка"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐÐŸÐŽÐ°Ñ Ð³ÐŸÑÑа"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"УклПМО гПÑÑа"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index a331bc6..f2a73c5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Det gick inte att skapa en ny användare"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Det gick inte att skapa en ny gäst"</string>
<string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Namnet och bilden du väljer visas för alla som använder den här enheten."</string>
<string name="user_add_user" msgid="7876449291500212468">"Lägg till användare"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 53481a2..ce28386 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Imeshindwa kuweka mtumiaji mpya"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Imeshindwa kuunda wasifu mpya wa mgeni"</string>
<string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Jina na picha unayochagua itaonwa na mtu yeyote anayetumia kifaa hiki."</string>
<string name="user_add_user" msgid="7876449291500212468">"Ongeza mtumiaji"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ongeza mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 204da0c..2936378 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"பà¯à®€à®¿à®¯ பயனர௠à®à®°à¯à®µà®Ÿà®à¯à® à®®à¯à®à®¿à®¯à®µà®¿à®²à¯à®²à¯"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"பà¯à®€à®¿à®¯ விரà¯à®šà¯à®€à®¿à®©à®°à¯ à®à®°à¯à®µà®Ÿà®à¯à® à®®à¯à®à®¿à®¯à®µà®¿à®²à¯à®²à¯"</string>
<string name="user_nickname" msgid="262624187455825083">"பà¯à®©à¯à®ªà¯à®ªà¯à®¯à®°à¯"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"சà¯à®à¯à®à®³à¯ ஀à¯à®°à¯à®µà¯à®à¯à®¯à¯à®¯à¯à®®à¯ பà¯à®¯à®°à¯à®¯à¯à®®à¯ பà®à®€à¯à®€à¯à®¯à¯à®®à¯ à®à®šà¯à®€à®à¯ à®à®Ÿà®€à®©à®€à¯à®€à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à¯à®®à¯ à®
னà¯à®µà®°à¯à®®à¯ படரà¯à®à¯à®à®²à®Ÿà®®à¯."</string>
<string name="user_add_user" msgid="7876449291500212468">"பயனரà¯à®à¯ à®à¯à®°à¯"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à®à¯à®žà¯à®à¯à®à¯à®à¯ à®à¯à®°à¯"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à®à¯à®žà¯à®à¯à®à¯ à®
à®à®±à¯à®±à¯"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f576c8d..a80976d 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"à°à±à°€à±à°€ à°¯à±à°à°°à±à°šà± à°à±à°°à°¿à°¯à±à°à± à°à±à°¯à°¡à° విఫలమà±à°à°Šà°¿"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"à°à±à°€à±à°€ à°
ఀిథిచి à°à±à°°à°¿à°¯à±à°à± à°à±à°¯à°¡à° విఫలమà±à°à°Šà°¿"</string>
<string name="user_nickname" msgid="262624187455825083">"మటరà±à°ªà±à°°à±"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"à°®à±à°°à± à°à°à°à±à°à±à°šà±à°š à°ªà±à°°à±, à°à°®à±à°à± ఠపరిà°à°°à°Ÿà°šà±à°šà°¿ à°à°ªà°¯à±à°à°¿à°à°à± à°à°µà°°à°¿à°à±à°šà°Ÿ à°à°šà°¿à°ªà°¿à°žà±à°€à°Ÿà°¯à°¿."</string>
<string name="user_add_user" msgid="7876449291500212468">"à°¯à±à°à°°à±à°šà± à°à±à°¡à°¿à°à°à°à°¡à°¿"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à°à±à°žà±à°à±à°šà± à°à±à°¡à°¿à°à°à°à°¡à°¿"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"à°à±à°žà±à°à±à°šà± à°€à±à°žà°¿à°µà±à°¯à°à°¡à°¿"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 42e6c05..cdba33d 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"àžªàž£à¹àž²àžàžàž¹à¹à¹àžà¹à¹àž«àž¡à¹à¹àž¡à¹à¹àžà¹"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"àžªàž£à¹àž²àžàžàž¹à¹à¹àžà¹àž²àž£à¹àž§àž¡à¹àž«àž¡à¹à¹àž¡à¹àžªàž³à¹àž£à¹àž"</string>
<string name="user_nickname" msgid="262624187455825083">"àžàž·à¹àžà¹àž¥à¹àž"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"àžàžžàžàžàžàžàžµà¹à¹àžà¹àžàžžàžàžàž£àžà¹à¹àžàž£àž·à¹àžàžàžàžµà¹àžàž°à¹àž«à¹àžàžàž·à¹àžà¹àž¥àž°àž£àž¹àžàž àž²àžàžàžµà¹àžàžžàžà¹àž¥àž·àžàž"</string>
<string name="user_add_user" msgid="7876449291500212468">"à¹àžàžŽà¹àž¡àžàž¹à¹à¹àžà¹"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"à¹àžàžŽà¹àž¡àžàž¹à¹à¹àžà¹àžàž±à¹àž§àžàž£àž²àž§"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"àžàž³àžàž¹à¹à¹àžà¹àžàž±à¹àž§àžàž£àž²àž§àžàžàž"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 73db0c5..e609b7d 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Hindi nakagawa ng bagong user"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Hindi nakagawa ng bagong guest"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Makikita ng sinumang gumagamit ng device na ito ang pangalan at larawang pipiliin mo."</string>
<string name="user_add_user" msgid="7876449291500212468">"Magdagdag ng user"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 98cfe35..c41ff1c 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yeni kullanıcı oluÅturulamadı"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yeni misafir oluÅturulamadı"</string>
<string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"SeçtiÄiniz ad ve resim bu cihazı kullanan herkese görünür."</string>
<string name="user_add_user" msgid="7876449291500212468">"Kullanıcı ekle"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 3321c78..d8cb368 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Ðе вЎалПÑÑ ÑÑвПÑОÑО кПÑОÑÑÑваÑа"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Ðе вЎалПÑÑ ÑÑвПÑОÑО гПÑÑÑ"</string>
<string name="user_nickname" msgid="262624187455825083">"ÐÑевЎПМÑÐŒ"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"ÐОбÑÐ°ÐœÑ Ð²Ð°ÐŒÐž ÑÐŒ’Ñ Ñ Ð·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐœÑ Ð±Ð°ÑОÑОЌÑÑÑ ÑÑÑ, Ñ
ÑП кПÑОÑÑÑÑÑÑÑÑ Ð²Ð°ÑОЌ пÑОÑÑÑПÑÐŒ."</string>
<string name="user_add_user" msgid="7876449291500212468">"ÐПЎаÑО âкПÑОÑÑÑваÑа"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ÐПЎаÑО гПÑÑÑ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ÐОЎалОÑО гПÑÑÑ"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index dadb9bc..7ba7b8b 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ÙÛØ§ ØµØ§Ø±Ù ØšÙØ§ÙÛ Ù
ÛÚº ÙØ§Ú©Ø§Ù
"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ÙÛØ§ Ù
ÛÙ
Ø§Ù ØšÙØ§ÙÛ Ù
ÛÚº ÙØ§Ú©Ø§Ù
"</string>
<string name="user_nickname" msgid="262624187455825083">"عرÙÛ ÙØ§Ù
"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"آٟ Ú©Û Ø¬Ø§ÙØš Ø³Û Ù
ÙØªØ®Øš Ú©Ø±Ø¯Û ÙØ§Ù
Ø§ÙØ± تصÙÛØ±Ø اس Ø¢ÙÛ Ú©Û Ø§Ø³ØªØ¹Ù
ا٠کرÙÛ ÙØ§ÙÛ ÛØ± ؎خص Ú©Ù ÙØžØ± Ø¢ØŠÛ Ú¯Ø§Û"</string>
<string name="user_add_user" msgid="7876449291500212468">"صار٠ک٠؎اÙ
٠کرÛÚº"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ù
ÛÙ
ا٠ک٠؎اÙ
٠کرÛÚº"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ù
ÛÙ
ا٠ک٠Ûٹا؊ÛÚº"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 2254132..9c37f41 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yangi foydalanuvchi yaratilmadi"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yangi mehmon yaratilmadi"</string>
<string name="user_nickname" msgid="262624187455825083">"Nik"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Tanlangan nom va rasm bu qurilmaning barcha foydalanuvchilariga koʻrinadi"</string>
<string name="user_add_user" msgid="7876449291500212468">"Foydalanuvchi kiritish"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index c98dcec..9a3663a 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Không tạo ÄÆ°á»£c ngưá»i dùng má»i"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Không tạo ÄÆ°á»£c khách má»i"</string>
<string name="user_nickname" msgid="262624187455825083">"Biá»t hiá»u"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Bất kỳ ai dùng thiết bá» này Äá»u sẜ nhìn thấy tên và hình ảnh bạn chá»n."</string>
<string name="user_add_user" msgid="7876449291500212468">"Thêm ngưá»i dùng"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa khách"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 136586d..b919972 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"æ æ³å建æ°çšæ·"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"æªèœå建æ°ç访客"</string>
<string name="user_nickname" msgid="262624187455825083">"æµç§°"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"äœ¿çšæ€è®Ÿå€çä»»äœçšæ·éœèœçå°æšéæ©çåç§°åç
§çã"</string>
<string name="user_add_user" msgid="7876449291500212468">"æ·»å çšæ·"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"æ·»å 访客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ç§»é€è®¿å®¢"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index a32e51e..340c7a4 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ç¡æ³å»ºç«æ°äœ¿çšè
"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ç¡æ³å»ºç«æ°èšªå®¢"</string>
<string name="user_nickname" msgid="262624187455825083">"æ±çš±"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"æ€è£çœ®çä»»äœäœ¿çšè
éœèœçå°äœ éžæçåçš±ååçã"</string>
<string name="user_add_user" msgid="7876449291500212468">"æ°å¢äœ¿çšè
"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"æ°å¢èšªå®¢"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ç§»é€èšªå®¢"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b5f5e2e..f7414ef 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"ç¡æ³å»ºç«æ°ç䜿çšè
"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"ç¡æ³å»ºç«æ°èšªå®¢"</string>
<string name="user_nickname" msgid="262624187455825083">"æ±çš±"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"䜿çšééšè£çœ®çææäººéœèœçå°äœ éžæçåçš±åçžçã"</string>
<string name="user_add_user" msgid="7876449291500212468">"æ°å¢äœ¿çšè
"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"æ°å¢èšªå®¢"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ç§»é€èšªå®¢"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 19dbebf..8364eef 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -619,8 +619,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"Yehlulekile ukudala umsebenzisi omusha"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Yehlulekile ukusungula isimenywa esisha"</string>
<string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
- <!-- no translation found for edit_user_info_message (6677556031419002895) -->
- <skip />
+ <string name="edit_user_info_message" msgid="6677556031419002895">"Igama nesithombe osikhethayo sizobonakala kunoma ubani osebenzisa le divayisi."</string>
<string name="user_add_user" msgid="7876449291500212468">"Engeza umsebenzisi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 87b4c0f..ad0e6f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -27,6 +27,7 @@
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.hardware.usb.flags.Flags;
+import android.icu.text.NumberFormat;
import android.location.LocationManager;
import android.media.AudioManager;
import android.net.NetworkCapabilities;
@@ -41,7 +42,6 @@
import android.os.UserManager;
import android.print.PrintManager;
import android.provider.Settings;
-import android.provider.Settings.Secure;
import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
@@ -67,7 +67,6 @@
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.settingslib.utils.BuildCompatUtils;
-import java.text.NumberFormat;
import java.time.Duration;
import java.util.List;
@@ -784,29 +783,4 @@
}
return false;
}
-
- /** Whether to show the wireless charging warning in Settings. */
- public static boolean shouldShowWirelessChargingWarningTip(
- @NonNull Context context, @NonNull String tag) {
- try {
- return Secure.getInt(context.getContentResolver(), WIRELESS_CHARGING_WARNING_ENABLED, 0)
- == 1;
- } catch (Exception e) {
- Log.e(tag, "shouldShowWirelessChargingWarningTip()", e);
- }
- return false;
- }
-
- /** Stores the state of whether the wireless charging warning in Settings is enabled. */
- public static void updateWirelessChargingWarningEnabled(
- @NonNull Context context, boolean enabled, @NonNull String tag) {
- try {
- Secure.putInt(
- context.getContentResolver(),
- WIRELESS_CHARGING_WARNING_ENABLED,
- enabled ? 1 : 0);
- } catch (Exception e) {
- Log.e(tag, "setWirelessChargingWarningEnabled()", e);
- }
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
index 9a29f22..f73081a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java
@@ -23,6 +23,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserProperties;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
@@ -132,8 +133,9 @@
int uid = ops.getUid();
UserHandle user = UserHandle.getUserHandleForUid(uid);
- // Don't show apps belonging to background users except managed users.
- if (!profiles.contains(user)) {
+ // Don't show apps belonging to background users except for profiles that shouldn't
+ // be shown in quiet mode.
+ if (!profiles.contains(user) || isHideInQuietEnabledForProfile(um, user)) {
continue;
}
@@ -192,6 +194,16 @@
return accesses;
}
+ private boolean isHideInQuietEnabledForProfile(UserManager userManager, UserHandle userHandle) {
+ if (android.multiuser.Flags.enablePrivateSpaceFeatures()
+ && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) {
+ return userManager.isQuietModeEnabled(userHandle)
+ && userManager.getUserProperties(userHandle).getShowInQuietMode()
+ == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN;
+ }
+ return false;
+ }
+
/**
* Creates a Access entry for the given PackageOps.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
index 416b369..baccda7e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -163,6 +163,16 @@
default void onAclConnectionStateChanged(
@NonNull CachedBluetoothDevice cachedDevice, int state) {}
+ /**
+ * Called when the Auto-on state is changed for any user. Listens to intent
+ * {@link android.bluetooth.BluetoothAdapter#ACTION_AUTO_ON_STATE_CHANGED }
+ *
+ * @param state the Auto-on state, the possible values are:
+ * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_ENABLED},
+ * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_DISABLED}
+ */
+ default void onAutoOnStateChanged(int state) {}
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "STATE_" }, value = {
STATE_DISCONNECTED,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 647fcb9..0996d52 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -133,6 +133,8 @@
addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
+ addHandler(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED, new AutoOnStateChangedHandler());
+
registerAdapterIntentReceiver();
}
@@ -552,4 +554,21 @@
dispatchAudioModeChanged();
}
}
+
+ private class AutoOnStateChangedHandler implements Handler {
+
+ @Override
+ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ String action = intent.getAction();
+ if (action == null) {
+ Log.w(TAG, "AutoOnStateChangedHandler() action is null");
+ return;
+ }
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_AUTO_ON_STATE,
+ BluetoothAdapter.ERROR);
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onAutoOnStateChanged(state);
+ }
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/session/MediaSessionManagerExt.kt b/packages/SettingsLib/src/com/android/settingslib/media/session/MediaSessionManagerExt.kt
index cda6b8b..68f471d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/session/MediaSessionManagerExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/media/session/MediaSessionManagerExt.kt
@@ -17,6 +17,7 @@
package com.android.settingslib.media.session
import android.media.session.MediaController
+import android.media.session.MediaSession
import android.media.session.MediaSessionManager
import android.os.UserHandle
import androidx.concurrent.futures.DirectExecutor
@@ -28,7 +29,7 @@
import kotlinx.coroutines.launch
/** [Flow] for [MediaSessionManager.OnActiveSessionsChangedListener]. */
-val MediaSessionManager.activeMediaChanges: Flow<Collection<MediaController>?>
+val MediaSessionManager.activeMediaChanges: Flow<List<MediaController>?>
get() =
callbackFlow {
val listener =
@@ -42,3 +43,24 @@
awaitClose { removeOnActiveSessionsChangedListener(listener) }
}
.buffer(capacity = Channel.CONFLATED)
+
+/** [Flow] for [MediaSessionManager.RemoteSessionCallback]. */
+val MediaSessionManager.remoteSessionChanges: Flow<MediaSession.Token?>
+ get() =
+ callbackFlow {
+ val callback =
+ object : MediaSessionManager.RemoteSessionCallback {
+ override fun onVolumeChanged(sessionToken: MediaSession.Token, flags: Int) {
+ launch { send(sessionToken) }
+ }
+
+ override fun onDefaultRemoteSessionChanged(
+ sessionToken: MediaSession.Token?
+ ) {
+ launch { send(sessionToken) }
+ }
+ }
+ registerRemoteSessionCallback(DirectExecutor.INSTANCE, callback)
+ awaitClose { unregisterRemoteSessionCallback(callback) }
+ }
+ .buffer(capacity = Channel.CONFLATED)
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index 6730aad..e7fec69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -19,7 +19,6 @@
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.media.AudioManager.OnCommunicationDeviceChangedListener
-import androidx.concurrent.futures.DirectExecutor
import com.android.internal.util.ConcurrentUtils
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.settingslib.volume.shared.model.AudioManagerEvent
@@ -109,8 +108,8 @@
callbackFlow {
val listener = OnCommunicationDeviceChangedListener { trySend(Unit) }
audioManager.addOnCommunicationDeviceChangedListener(
- DirectExecutor.INSTANCE,
- listener
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ listener,
)
awaitClose { audioManager.removeOnCommunicationDeviceChangedListener(listener) }
@@ -146,7 +145,7 @@
maxVolume = audioManager.getStreamMaxVolume(audioStream.value),
volume = audioManager.getStreamVolume(audioStream.value),
isAffectedByRingerMode = audioManager.isStreamAffectedByRingerMode(audioStream.value),
- isMuted = audioManager.isStreamMute(audioStream.value),
+ isMuted = audioManager.isStreamMute(audioStream.value)
)
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/LocalMediaRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/LocalMediaRepository.kt
index 298dd71e..724dd51 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/LocalMediaRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/LocalMediaRepository.kt
@@ -15,14 +15,10 @@
*/
package com.android.settingslib.volume.data.repository
-import android.media.MediaRouter2Manager
-import android.media.RoutingSessionInfo
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.volume.data.model.RoutingSession
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.settingslib.volume.shared.model.AudioManagerEvent
-import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -30,35 +26,23 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filterIsInstance
-import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.withContext
/** Repository providing data about connected media devices. */
interface LocalMediaRepository {
- /** Available devices list */
- val mediaDevices: StateFlow<Collection<MediaDevice>>
-
/** Currently connected media device */
val currentConnectedDevice: StateFlow<MediaDevice?>
-
- val remoteRoutingSessions: StateFlow<Collection<RoutingSession>>
-
- suspend fun adjustSessionVolume(sessionId: String?, volume: Int)
}
class LocalMediaRepositoryImpl(
audioManagerEventsReceiver: AudioManagerEventsReceiver,
private val localMediaManager: LocalMediaManager,
- private val mediaRouter2Manager: MediaRouter2Manager,
coroutineScope: CoroutineScope,
- private val backgroundContext: CoroutineContext,
) : LocalMediaRepository {
private val devicesChanges =
@@ -94,18 +78,6 @@
}
.shareIn(coroutineScope, SharingStarted.WhileSubscribed(), replay = 0)
- override val mediaDevices: StateFlow<Collection<MediaDevice>> =
- mediaDevicesUpdates
- .mapNotNull {
- if (it is DevicesUpdate.DeviceListUpdate) {
- it.newDevices ?: emptyList()
- } else {
- null
- }
- }
- .flowOn(backgroundContext)
- .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
-
override val currentConnectedDevice: StateFlow<MediaDevice?> =
merge(devicesChanges, mediaDevicesUpdates)
.map { localMediaManager.currentConnectedDevice }
@@ -116,30 +88,6 @@
localMediaManager.currentConnectedDevice
)
- override val remoteRoutingSessions: StateFlow<Collection<RoutingSession>> =
- merge(devicesChanges, mediaDevicesUpdates)
- .onStart { emit(Unit) }
- .map { localMediaManager.remoteRoutingSessions.map(::toRoutingSession) }
- .flowOn(backgroundContext)
- .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
-
- override suspend fun adjustSessionVolume(sessionId: String?, volume: Int) {
- withContext(backgroundContext) {
- if (sessionId == null) {
- localMediaManager.adjustSessionVolume(volume)
- } else {
- localMediaManager.adjustSessionVolume(sessionId, volume)
- }
- }
- }
-
- private fun toRoutingSession(info: RoutingSessionInfo): RoutingSession =
- RoutingSession(
- info,
- isMediaOutputDisabled = mediaRouter2Manager.getTransferableRoutes(info).isEmpty(),
- isVolumeSeekBarEnabled = localMediaManager.shouldEnableVolumeSeekBar(info)
- )
-
private sealed interface DevicesUpdate {
data class DeviceListUpdate(val newDevices: List<MediaDevice>?) : DevicesUpdate
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerRepository.kt
index 7c231d1..e4ac9fe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/MediaControllerRepository.kt
@@ -27,18 +27,26 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filterIsInstance
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
/** Provides controllers for currently active device media sessions. */
interface MediaControllerRepository {
- /** Current [MediaController]. Null is emitted when there is no active [MediaController]. */
- val activeLocalMediaController: StateFlow<MediaController?>
+ /**
+ * Get a list of controllers for all ongoing sessions. The controllers will be provided in
+ * priority order with the most important controller at index 0.
+ *
+ * This requires the [android.Manifest.permission.MEDIA_CONTENT_CONTROL] permission be held by
+ * the calling app.
+ */
+ val activeSessions: StateFlow<List<MediaController>>
}
class MediaControllerRepositoryImpl(
@@ -49,51 +57,17 @@
backgroundContext: CoroutineContext,
) : MediaControllerRepository {
- private val devicesChanges =
- audioManagerEventsReceiver.events.filterIsInstance(
- AudioManagerEvent.StreamDevicesChanged::class
- )
-
- override val activeLocalMediaController: StateFlow<MediaController?> =
- combine(
- mediaSessionManager.activeMediaChanges.onStart {
- emit(mediaSessionManager.getActiveSessions(null))
- },
- localBluetoothManager?.headsetAudioModeChanges?.onStart { emit(Unit) }
- ?: flowOf(null),
- devicesChanges.onStart { emit(AudioManagerEvent.StreamDevicesChanged) },
- ) { controllers, _, _ ->
- controllers?.let(::findLocalMediaController)
- }
+ override val activeSessions: StateFlow<List<MediaController>> =
+ merge(
+ mediaSessionManager.activeMediaChanges.filterNotNull(),
+ localBluetoothManager?.headsetAudioModeChanges?.map {
+ mediaSessionManager.getActiveSessions(null)
+ } ?: emptyFlow(),
+ audioManagerEventsReceiver.events
+ .filterIsInstance(AudioManagerEvent.StreamDevicesChanged::class)
+ .map { mediaSessionManager.getActiveSessions(null) },
+ )
+ .onStart { emit(mediaSessionManager.getActiveSessions(null)) }
.flowOn(backgroundContext)
- .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null)
-
- private fun findLocalMediaController(
- controllers: Collection<MediaController>,
- ): MediaController? {
- var localController: MediaController? = null
- val remoteMediaSessionLists: MutableList<String> = ArrayList()
- for (controller in controllers) {
- val playbackInfo: MediaController.PlaybackInfo = controller.playbackInfo ?: continue
- when (playbackInfo.playbackType) {
- MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE -> {
- if (localController?.packageName.equals(controller.packageName)) {
- localController = null
- }
- if (!remoteMediaSessionLists.contains(controller.packageName)) {
- remoteMediaSessionLists.add(controller.packageName)
- }
- }
- MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL -> {
- if (
- localController == null &&
- !remoteMediaSessionLists.contains(controller.packageName)
- ) {
- localController = controller
- }
- }
- }
- }
- return localController
- }
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
index c9ac97d..778653b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
@@ -66,6 +66,10 @@
}
}
+ fun isMutable(audioStream: AudioStream): Boolean =
+ // Alarm stream doesn't support muting
+ audioStream.value != AudioManager.STREAM_ALARM
+
private suspend fun processVolume(
audioStreamModel: AudioStreamModel,
ringerMode: RingerMode,
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/LocalMediaInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/LocalMediaInteractor.kt
deleted file mode 100644
index f621335..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/LocalMediaInteractor.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.volume.domain.interactor
-
-import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.volume.data.repository.LocalMediaRepository
-import com.android.settingslib.volume.domain.model.RoutingSession
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-class LocalMediaInteractor(
- private val repository: LocalMediaRepository,
- coroutineScope: CoroutineScope,
-) {
-
- /** Available devices list */
- val mediaDevices: StateFlow<Collection<MediaDevice>>
- get() = repository.mediaDevices
-
- /** Currently connected media device */
- val currentConnectedDevice: StateFlow<MediaDevice?>
- get() = repository.currentConnectedDevice
-
- val remoteRoutingSessions: StateFlow<List<RoutingSession>> =
- repository.remoteRoutingSessions
- .map { sessions ->
- sessions.map {
- RoutingSession(
- routingSessionInfo = it.routingSessionInfo,
- isMediaOutputDisabled = it.isMediaOutputDisabled,
- isVolumeSeekBarEnabled =
- it.isVolumeSeekBarEnabled && it.routingSessionInfo.volumeMax > 0
- )
- }
- }
- .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
-
- suspend fun adjustSessionVolume(sessionId: String?, volume: Int) =
- repository.adjustSessionVolume(sessionId, volume)
-}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/LocalMediaRepositoryImplTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/LocalMediaRepositoryImplTest.kt
index 2d12dae..caf41f2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/LocalMediaRepositoryImplTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/LocalMediaRepositoryImplTest.kt
@@ -15,17 +15,12 @@
*/
package com.android.settingslib.volume.data.repository
-import android.media.MediaRoute2Info
-import android.media.MediaRouter2Manager
-import android.media.RoutingSessionInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.volume.data.model.RoutingSession
import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -37,15 +32,10 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.anyString
-import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
class LocalMediaRepositoryImplTest {
@@ -53,7 +43,6 @@
@Mock private lateinit var localMediaManager: LocalMediaManager
@Mock private lateinit var mediaDevice1: MediaDevice
@Mock private lateinit var mediaDevice2: MediaDevice
- @Mock private lateinit var mediaRouter2Manager: MediaRouter2Manager
@Captor
private lateinit var deviceCallbackCaptor: ArgumentCaptor<LocalMediaManager.DeviceCallback>
@@ -71,29 +60,11 @@
LocalMediaRepositoryImpl(
eventsReceiver,
localMediaManager,
- mediaRouter2Manager,
testScope.backgroundScope,
- testScope.testScheduler,
)
}
@Test
- fun mediaDevices_areUpdated() {
- testScope.runTest {
- var mediaDevices: Collection<MediaDevice>? = null
- underTest.mediaDevices.onEach { mediaDevices = it }.launchIn(backgroundScope)
- runCurrent()
- verify(localMediaManager).registerCallback(deviceCallbackCaptor.capture())
- deviceCallbackCaptor.value.onDeviceListUpdate(listOf(mediaDevice1, mediaDevice2))
- runCurrent()
-
- assertThat(mediaDevices).hasSize(2)
- assertThat(mediaDevices).contains(mediaDevice1)
- assertThat(mediaDevices).contains(mediaDevice2)
- }
- }
-
- @Test
fun deviceListUpdated_currentConnectedDeviceUpdated() {
testScope.runTest {
var currentConnectedDevice: MediaDevice? = null
@@ -110,78 +81,4 @@
assertThat(currentConnectedDevice).isEqualTo(mediaDevice1)
}
}
-
- @Test
- fun kek() {
- testScope.runTest {
- `when`(localMediaManager.remoteRoutingSessions)
- .thenReturn(
- listOf(
- testRoutingSessionInfo1,
- testRoutingSessionInfo2,
- testRoutingSessionInfo3,
- )
- )
- `when`(localMediaManager.shouldEnableVolumeSeekBar(any())).then {
- (it.arguments[0] as RoutingSessionInfo) == testRoutingSessionInfo1
- }
- `when`(mediaRouter2Manager.getTransferableRoutes(any<RoutingSessionInfo>())).then {
- if ((it.arguments[0] as RoutingSessionInfo) == testRoutingSessionInfo2) {
- return@then listOf(mock(MediaRoute2Info::class.java))
- }
- emptyList<MediaRoute2Info>()
- }
- var remoteRoutingSessions: Collection<RoutingSession>? = null
- underTest.remoteRoutingSessions
- .onEach { remoteRoutingSessions = it }
- .launchIn(backgroundScope)
-
- runCurrent()
-
- assertThat(remoteRoutingSessions)
- .containsExactlyElementsIn(
- listOf(
- RoutingSession(
- routingSessionInfo = testRoutingSessionInfo1,
- isVolumeSeekBarEnabled = true,
- isMediaOutputDisabled = true,
- ),
- RoutingSession(
- routingSessionInfo = testRoutingSessionInfo2,
- isVolumeSeekBarEnabled = false,
- isMediaOutputDisabled = false,
- ),
- RoutingSession(
- routingSessionInfo = testRoutingSessionInfo3,
- isVolumeSeekBarEnabled = false,
- isMediaOutputDisabled = true,
- )
- )
- )
- }
- }
-
- @Test
- fun adjustSessionVolume_adjusts() {
- testScope.runTest {
- var volume = 0
- `when`(localMediaManager.adjustSessionVolume(anyString(), anyInt())).then {
- volume = it.arguments[1] as Int
- Unit
- }
-
- underTest.adjustSessionVolume("test_session", 10)
-
- assertThat(volume).isEqualTo(10)
- }
- }
-
- private companion object {
- val testRoutingSessionInfo1 =
- RoutingSessionInfo.Builder("id_1", "test.pkg.1").addSelectedRoute("route_1").build()
- val testRoutingSessionInfo2 =
- RoutingSessionInfo.Builder("id_2", "test.pkg.2").addSelectedRoute("route_2").build()
- val testRoutingSessionInfo3 =
- RoutingSessionInfo.Builder("id_3", "test.pkg.3").addSelectedRoute("route_3").build()
- }
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/MediaControllerRepositoryImplTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/MediaControllerRepositoryImplTest.kt
index f3d1714..964c3f7 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/MediaControllerRepositoryImplTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/MediaControllerRepositoryImplTest.kt
@@ -22,13 +22,10 @@
import android.media.session.PlaybackState
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.settingslib.bluetooth.BluetoothCallback
import com.android.settingslib.bluetooth.BluetoothEventManager
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.volume.shared.FakeAudioManagerEventsReceiver
-import com.android.settingslib.volume.shared.model.AudioManagerEvent
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
@@ -37,21 +34,15 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.any
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
class MediaControllerRepositoryImplTest {
- @Captor private lateinit var callbackCaptor: ArgumentCaptor<BluetoothCallback>
-
@Mock private lateinit var mediaSessionManager: MediaSessionManager
@Mock private lateinit var localBluetoothManager: LocalBluetoothManager
@Mock private lateinit var eventManager: BluetoothEventManager
@@ -103,7 +94,7 @@
}
@Test
- fun playingMediaDevicesAvailable_sessionIsActive() {
+ fun mediaDevicesAvailable_returnsAllActiveOnes() {
testScope.runTest {
`when`(mediaSessionManager.getActiveSessions(any()))
.thenReturn(
@@ -112,53 +103,25 @@
statelessMediaController,
errorMediaController,
remoteMediaController,
- localMediaController
+ localMediaController,
)
)
- var mediaController: MediaController? = null
- underTest.activeLocalMediaController
- .onEach { mediaController = it }
- .launchIn(backgroundScope)
+
+ var mediaControllers: Collection<MediaController>? = null
+ underTest.activeSessions.onEach { mediaControllers = it }.launchIn(backgroundScope)
runCurrent()
- eventsReceiver.triggerEvent(AudioManagerEvent.StreamDevicesChanged)
- triggerOnAudioModeChanged()
- runCurrent()
-
- assertThat(mediaController).isSameInstanceAs(localMediaController)
- }
- }
-
- @Test
- fun noPlayingMediaDevicesAvailable_sessionIsInactive() {
- testScope.runTest {
- `when`(mediaSessionManager.getActiveSessions(any()))
- .thenReturn(
- listOf(
- stoppedMediaController,
- statelessMediaController,
- errorMediaController,
- )
+ assertThat(mediaControllers)
+ .containsExactly(
+ stoppedMediaController,
+ statelessMediaController,
+ errorMediaController,
+ remoteMediaController,
+ localMediaController,
)
- var mediaController: MediaController? = null
- underTest.activeLocalMediaController
- .onEach { mediaController = it }
- .launchIn(backgroundScope)
- runCurrent()
-
- eventsReceiver.triggerEvent(AudioManagerEvent.StreamDevicesChanged)
- triggerOnAudioModeChanged()
- runCurrent()
-
- assertThat(mediaController).isNull()
}
}
- private fun triggerOnAudioModeChanged() {
- verify(eventManager).registerCallback(callbackCaptor.capture())
- callbackCaptor.value.onAudioModeChanged()
- }
-
private companion object {
val statePlaying: PlaybackState =
PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0, 0f).build()
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 6f31fad..0931b68 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -16,7 +16,6 @@
package com.android.settingslib;
import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY;
-import static com.android.settingslib.Utils.shouldShowWirelessChargingWarningTip;
import static com.google.common.truth.Truth.assertThat;
@@ -543,20 +542,6 @@
assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
- @Test
- public void shouldShowWirelessChargingWarningTip_enabled_returnTrue() {
- Utils.updateWirelessChargingWarningEnabled(mContext, true, TAG);
-
- assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isTrue();
- }
-
- @Test
- public void shouldShowWirelessChargingWarningTip_disabled_returnFalse() {
- Utils.updateWirelessChargingWarningEnabled(mContext, false, TAG);
-
- assertThat(shouldShowWirelessChargingWarningTip(mContext, TAG)).isFalse();
- }
-
private void setupIncompatibleCharging() {
setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
index f9505dd..52622a7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
@@ -32,14 +32,17 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserProperties;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.LongSparseArray;
import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -58,6 +61,8 @@
@Config(shadows = {ShadowPermissionChecker.class})
public class RecentAppOpsAccessesTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final int TEST_UID = 1234;
private static final long NOW = 1_000_000_000; // Approximately 9/8/2001
private static final long ONE_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(1);
@@ -73,6 +78,8 @@
@Mock
private UserManager mUserManager;
@Mock
+ private UserProperties mUserProperties;
+ @Mock
private Clock mClock;
private Context mContext;
private int mTestUserId;
@@ -132,6 +139,58 @@
}
@Test
+ public void testGetAppList_quietModeDisabled_shouldFilterRecentAccesses() {
+ mSetFlagsRule.enableFlags(
+ android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE,
+ android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+ List<RecentAppOpsAccess.Access> requests = mRecentAppOpsAccess.getAppList(false);
+ // Only two of the apps have requested location within 15 min.
+ assertThat(requests).hasSize(2);
+ // Make sure apps are ordered by recency
+ assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+ assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+ assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+ assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+ }
+
+ @Test
+ public void testGetAppList_quietModeEnabledShowInQuietDefault_shouldFilterRecentAccesses() {
+ mSetFlagsRule.enableFlags(
+ android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE,
+ android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+ when(mUserManager.getUserProperties(any())).thenReturn(mUserProperties);
+ when(mUserProperties.getShowInQuietMode())
+ .thenReturn(UserProperties.SHOW_IN_QUIET_MODE_DEFAULT);
+
+ List<RecentAppOpsAccess.Access> requests = mRecentAppOpsAccess.getAppList(false);
+ // Only two of the apps have requested location within 15 min.
+ assertThat(requests).hasSize(2);
+ // Make sure apps are ordered by recency
+ assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+ assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+ assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+ assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+ }
+
+ @Test
+ public void testGetAppList_quietModeEnabledShowInQuietHidden_shouldNotFilterRecentAccesses() {
+ mSetFlagsRule.enableFlags(
+ android.multiuser.Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE,
+ android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+ when(mUserManager.getUserProperties(any())).thenReturn(mUserProperties);
+ when(mUserProperties.getShowInQuietMode())
+ .thenReturn(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN);
+
+ List<RecentAppOpsAccess.Access> requests = mRecentAppOpsAccess.getAppList(false);
+ // Apps doesn't show up in the list of apps.
+ assertThat(requests).hasSize(0);
+ }
+
+ @Test
public void testGetAppList_shouldNotShowAndroidOS() throws NameNotFoundException {
// Add android OS to the list of apps.
PackageOps androidSystemPackageOps =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 13635c3..48bbf4e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -489,4 +490,17 @@
verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
eq(R.string.bluetooth_pairing_pin_error_message));
}
+
+ /**
+ * Intent ACTION_AUTO_ON_STATE_CHANGED should dispatch to callback.
+ */
+ @Test
+ public void intentWithExtraState_autoOnStateChangedShouldDispatchToRegisterCallback() {
+ mBluetoothEventManager.registerCallback(mBluetoothCallback);
+ mIntent = new Intent(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mBluetoothCallback).onAutoOnStateChanged(anyInt());
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index eaec617..87a7f82 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -256,8 +256,7 @@
Settings.Secure.HEARING_AID_MEDIA_ROUTING,
Settings.Secure.HEARING_AID_NOTIFICATION_ROUTING,
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
- Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
- Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
+ Settings.Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED,
Settings.Secure.HUB_MODE_TUTORIAL_STATE,
Settings.Secure.STYLUS_BUTTONS_ENABLED,
Settings.Secure.STYLUS_HANDWRITING_ENABLED,
@@ -270,6 +269,7 @@
Settings.Secure.CAMERA_EXTENSIONS_FALLBACK,
Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED,
Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
- Settings.Secure.AUDIO_DEVICE_INVENTORY
+ Settings.Secure.AUDIO_DEVICE_INVENTORY,
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_TARGETS
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 046d6e2..edef286 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -208,8 +208,7 @@
VALIDATORS.put(Secure.ASSIST_TOUCH_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.SEARCH_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
@@ -327,6 +326,9 @@
Secure.ACCESSIBILITY_BUTTON_TARGETS,
ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(
+ Secure.ACCESSIBILITY_FLOATING_MENU_TARGETS,
+ ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
+ VALIDATORS.put(
Secure.ACCESSIBILITY_QS_TARGETS,
ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index e5d62f8..8e32005 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -75,7 +75,10 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import java.util.zip.CRC32;
/**
@@ -103,6 +106,7 @@
// fatal crash. Creating a backup with a different key will prevent Android 12 versions from
// restoring this data.
private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
+ private static final String KEY_WIFI_SETTINGS_BACKUP_DATA = "wifi_settings_backup_data";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
@@ -126,8 +130,9 @@
private static final int STATE_WIFI_NEW_CONFIG = 9;
private static final int STATE_DEVICE_CONFIG = 10;
private static final int STATE_SIM_SPECIFIC_SETTINGS = 11;
+ private static final int STATE_WIFI_SETTINGS = 12;
- private static final int STATE_SIZE = 12; // The current number of state items
+ private static final int STATE_SIZE = 13; // The current number of state items
// Number of entries in the checksum array at various version numbers
private static final int STATE_SIZES[] = {
@@ -140,7 +145,8 @@
9, // version 6 added STATE_NETWORK_POLICIES
10, // version 7 added STATE_WIFI_NEW_CONFIG
11, // version 8 added STATE_DEVICE_CONFIG
- STATE_SIZE // version 9 added STATE_SIM_SPECIFIC_SETTINGS
+ 12, // version 9 added STATE_SIM_SPECIFIC_SETTINGS
+ STATE_SIZE // version 10 added STATE_WIFI_SETTINGS
};
private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
@@ -230,6 +236,7 @@
byte[] wifiFullConfigData = getNewWifiConfigData();
byte[] deviceSpecificInformation = getDeviceSpecificConfiguration();
byte[] simSpecificSettingsData = getSimSpecificSettingsData();
+ byte[] wifiSettingsData = getWifiSettingsBackupData();
long[] stateChecksums = readOldChecksums(oldState);
@@ -265,6 +272,9 @@
stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] =
writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS],
KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data);
+ stateChecksums[STATE_WIFI_SETTINGS] =
+ writeIfChanged(stateChecksums[STATE_WIFI_SETTINGS],
+ KEY_WIFI_SETTINGS_BACKUP_DATA, wifiSettingsData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -413,7 +423,13 @@
data.readEntityData(restoredSimSpecificSettings, 0, size);
restoreSimSpecificSettings(restoredSimSpecificSettings);
break;
-
+ case KEY_WIFI_SETTINGS_BACKUP_DATA:
+ byte[] restoredWifiData = new byte[size];
+ data.readEntityData(restoredWifiData, 0, size);
+ if (!isWatch()) {
+ restoreWifiData(restoredWifiData);
+ }
+ break;
default :
data.skipEntityData();
@@ -1346,6 +1362,45 @@
}
}
+ private static final class Mutable<E> {
+ public volatile E value;
+
+ Mutable() {
+ value = null;
+ }
+ }
+
+ private byte[] getWifiSettingsBackupData() {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Mutable<byte[]> backupWifiData = new Mutable<byte[]>();
+
+ try {
+ mWifiManager.retrieveWifiBackupData(getBaseContext().getMainExecutor(),
+ new Consumer<byte[]>() {
+ @Override
+ public void accept(byte[] value) {
+ backupWifiData.value = value;
+ latch.countDown();
+ }
+ });
+ // cts requires B&R with 10 seconds
+ if (latch.await(10, TimeUnit.SECONDS) && backupWifiData.value != null) {
+ return backupWifiData.value;
+ }
+ } catch (InterruptedException ie) {
+ Log.e(TAG, "fail to retrieveWifiBackupData, " + ie);
+ }
+ Log.e(TAG, "fail to retrieveWifiBackupData");
+ return new byte[0];
+ }
+
+ private void restoreWifiData(byte[] data) {
+ if (DEBUG_BACKUP) {
+ Log.v(TAG, "Applying restored all wifi data");
+ }
+ mWifiManager.restoreWifiBackupData(data);
+ }
+
private void updateWindowManagerIfNeeded(Integer previousDensity) {
int newDensity;
try {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 02d212c..4603b43 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1838,6 +1838,9 @@
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
SecureSettingsProto.Accessibility.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_TARGETS,
+ SecureSettingsProto.Accessibility.ACCESSIBILITY_FLOATING_MENU_TARGETS);
+ dumpSetting(s, p,
Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
SecureSettingsProto.Accessibility.ODI_CAPTIONS_VOLUME_UI_ENABLED);
dumpSetting(s, p,
@@ -1950,11 +1953,8 @@
Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED,
SecureSettingsProto.Assist.LONG_PRESS_HOME_ENABLED);
dumpSetting(s, p,
- Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
- SecureSettingsProto.Assist.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED);
- dumpSetting(s, p,
- Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
- SecureSettingsProto.Assist.SEARCH_LONG_PRESS_HOME_ENABLED);
+ Settings.Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED,
+ SecureSettingsProto.Assist.SEARCH_ALL_ENTRYPOINTS_ENABLED);
dumpSetting(s, p,
Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED,
SecureSettingsProto.Assist.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 6eb2dd0..8cafe5f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -688,6 +688,7 @@
Settings.Secure.DEVICE_PAIRED,
Settings.Secure.DIALER_DEFAULT_APPLICATION,
Settings.Secure.DISABLED_PRINT_SERVICES,
+ Settings.Secure.DISABLE_SECURE_WINDOWS,
Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
Settings.Secure.DOCKED_CLOCK_FACE,
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 02d19dc..5804071 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -932,6 +932,9 @@
<uses-permission
android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" />
+ <!-- Permission required for Cts test - CtsSettingsTestCases -->
+ <uses-permission android:name="android.permission.PREPARE_FACTORY_RESET" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 6546b87..f70ad9e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -23,10 +23,10 @@
import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS;
import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT;
-import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_OPEN_BLOCKED;
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION;
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION_EXTRA;
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_HIDE_MENU;
+import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_OPEN_BLOCKED;
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU;
import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME;
@@ -77,6 +77,8 @@
private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
private static final int TIMEOUT_UI_CHANGE_S = 5;
private static final int NO_GLOBAL_ACTION = -1;
+ private static final Intent INTENT_OPEN_MENU = new Intent(INTENT_TOGGLE_MENU)
+ .setPackage(PACKAGE_NAME);
private static Instrumentation sInstrumentation;
private static UiAutomation sUiAutomation;
@@ -152,9 +154,6 @@
@Before
public void setup() throws Throwable {
sOpenBlocked.set(false);
- wakeUpScreen();
- sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
- openMenu();
}
@After
@@ -188,24 +187,17 @@
}
private static void openMenu() throws Throwable {
- openMenu(false);
- }
-
- private static void openMenu(boolean abandonOnBlock) throws Throwable {
- Intent intent = new Intent(INTENT_TOGGLE_MENU);
- intent.setPackage(PACKAGE_NAME);
- sInstrumentation.getContext().sendBroadcast(intent);
+ unlockSignal();
+ sInstrumentation.getContext().sendBroadcast(INTENT_OPEN_MENU);
TestUtils.waitUntil("Timed out before menu could appear.",
TIMEOUT_UI_CHANGE_S,
() -> {
- if (sOpenBlocked.get() && abandonOnBlock) {
- throw new IllegalStateException();
- }
if (isMenuVisible()) {
return true;
} else {
- sInstrumentation.getContext().sendBroadcast(intent);
+ unlockSignal();
+ sInstrumentation.getContext().sendBroadcast(INTENT_OPEN_MENU);
return false;
}
});
@@ -249,6 +241,7 @@
@Test
public void testAdjustBrightness() throws Throwable {
+ openMenu();
Context context = sInstrumentation.getTargetContext();
DisplayManager displayManager = context.getSystemService(
DisplayManager.class);
@@ -264,22 +257,28 @@
context.getDisplayId()).getBrightnessInfo();
try {
- displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMinimum);
TestUtils.waitUntil("Could not change to minimum brightness",
TIMEOUT_UI_CHANGE_S,
- () -> displayManager.getBrightness(context.getDisplayId())
- == brightnessInfo.brightnessMinimum);
+ () -> {
+ displayManager.setBrightness(
+ context.getDisplayId(), brightnessInfo.brightnessMinimum);
+ return displayManager.getBrightness(context.getDisplayId())
+ == brightnessInfo.brightnessMinimum;
+ });
brightnessUpButton.performAction(CLICK_ID);
TestUtils.waitUntil("Did not detect an increase in brightness.",
TIMEOUT_UI_CHANGE_S,
() -> displayManager.getBrightness(context.getDisplayId())
> brightnessInfo.brightnessMinimum);
- displayManager.setBrightness(context.getDisplayId(), brightnessInfo.brightnessMaximum);
TestUtils.waitUntil("Could not change to maximum brightness",
TIMEOUT_UI_CHANGE_S,
- () -> displayManager.getBrightness(context.getDisplayId())
- == brightnessInfo.brightnessMaximum);
+ () -> {
+ displayManager.setBrightness(
+ context.getDisplayId(), brightnessInfo.brightnessMaximum);
+ return displayManager.getBrightness(context.getDisplayId())
+ == brightnessInfo.brightnessMaximum;
+ });
brightnessDownButton.performAction(CLICK_ID);
TestUtils.waitUntil("Did not detect a decrease in brightness.",
TIMEOUT_UI_CHANGE_S,
@@ -292,6 +291,7 @@
@Test
public void testAdjustVolume() throws Throwable {
+ openMenu();
Context context = sInstrumentation.getTargetContext();
AudioManager audioManager = context.getSystemService(AudioManager.class);
int resetVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
@@ -332,6 +332,7 @@
@Test
public void testAssistantButton_opensVoiceAssistant() throws Throwable {
+ openMenu();
AccessibilityNodeInfo assistantButton = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_ASSISTANT_VALUE.ordinal()));
Intent expectedIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
@@ -349,6 +350,7 @@
@Test
public void testAccessibilitySettingsButton_opensAccessibilitySettings() throws Throwable {
+ openMenu();
AccessibilityNodeInfo settingsButton = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_A11YSETTING_VALUE.ordinal()));
Intent expectedIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
@@ -364,6 +366,7 @@
@Test
public void testPowerButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_POWER_VALUE.ordinal()));
@@ -376,6 +379,7 @@
@Test
public void testRecentButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_RECENT_VALUE.ordinal()));
@@ -388,6 +392,7 @@
@Test
public void testLockButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_LOCKSCREEN_VALUE.ordinal()));
@@ -400,6 +405,7 @@
@Test
public void testQuickSettingsButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_QUICKSETTING_VALUE.ordinal()));
@@ -412,6 +418,7 @@
@Test
public void testNotificationsButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_NOTIFICATION_VALUE.ordinal()));
@@ -424,6 +431,7 @@
@Test
public void testScreenshotButton_performsGlobalAction() throws Throwable {
+ openMenu();
AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(),
String.valueOf(ShortcutId.ID_SCREENSHOT_VALUE.ordinal()));
@@ -436,6 +444,7 @@
@Test
public void testOnScreenLock_closesMenu() throws Throwable {
+ openMenu();
closeScreen();
wakeUpScreen();
@@ -447,13 +456,18 @@
closeScreen();
wakeUpScreen();
- boolean blocked = false;
- try {
- openMenu(true);
- } catch (IllegalStateException e) {
- // Expected
- blocked = true;
- }
- assertThat(blocked).isTrue();
+ TestUtils.waitUntil("Did not receive signal that menu cannot open",
+ TIMEOUT_UI_CHANGE_S,
+ () -> {
+ sInstrumentation.getContext().sendBroadcast(INTENT_OPEN_MENU);
+ return sOpenBlocked.get();
+ });
+ }
+
+ private static void unlockSignal() {
+ // MENU unlocks screen,
+ // BACK closes any menu that may appear if the screen wasn't locked.
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_BACK");
}
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 8da5021..91717dc 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -25,6 +25,16 @@
}
flag {
+ name: "notification_minimalism_prototype"
+ namespace: "systemui"
+ description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
+ bug: "330387368"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "notification_view_flipper_pausing"
namespace: "systemui"
description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed."
@@ -104,6 +114,13 @@
}
flag {
+ name: "notifications_heads_up_refactor"
+ namespace: "systemui"
+ description: "Use HeadsUpInteractor to feed HUN updates to the NSSL."
+ bug: "325936094"
+}
+
+flag {
name: "pss_app_selector_abrupt_exit_fix"
namespace: "systemui"
description: "Fixes the app selector abruptly disappearing without an animation, when the"
@@ -238,6 +255,13 @@
}
flag {
+ name: "qs_new_tiles_future"
+ namespace: "systemui"
+ description: "Use the new tiles in the Quick Settings that are still under development. This flag will not be used to gate release but to prevent tiles under development from reaching teamfood."
+ bug: "311147395"
+}
+
+flag {
name: "coroutine_tracing"
namespace: "systemui"
description: "Adds thread-local data to System UI's global coroutine scopes to "
@@ -424,6 +448,13 @@
}
flag {
+ name: "screenshot_shelf_ui"
+ namespace: "systemui"
+ description: "Use new shelf UI flow for screenshots"
+ bug: "329659738"
+}
+
+flag {
name: "run_fingerprint_detect_on_dismissible_keyguard"
namespace: "systemui"
description: "Run fingerprint detect instead of authenticate if the keyguard is dismissible."
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
index 596a297..4a89e31 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
@@ -18,6 +18,7 @@
package com.android.compose
+import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Canvas
@@ -266,8 +267,17 @@
label = "PlatformSliderCornersAnimation",
)
- val trackColor = colors.getTrackColor(enabled)
- val indicatorColor = colors.getIndicatorColor(enabled)
+ val trackColor by
+ animateColorAsState(
+ colors.getTrackColor(enabled),
+ label = "PlatformSliderTrackColorAnimation",
+ )
+
+ val indicatorColor by
+ animateColorAsState(
+ colors.getIndicatorColor(enabled),
+ label = "PlatformSliderIndicatorColorAnimation",
+ )
Canvas(modifier.fillMaxSize()) {
val trackCornerRadius = CornerRadius(size.height / 2, size.height / 2)
val trackPath = Path()
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 621ddf7..0f3d3dc2 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
@@ -53,6 +53,7 @@
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -71,6 +72,7 @@
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.times
import com.android.compose.PlatformButton
import com.android.compose.animation.scene.ElementKey
@@ -84,7 +86,9 @@
import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.BouncerMessageViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.bouncer.ui.viewmodel.MessageViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
@@ -166,7 +170,7 @@
modifier = Modifier.fillMaxWidth(),
) {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
modifier = Modifier,
)
@@ -228,7 +232,7 @@
when (authMethod) {
is PinBouncerViewModel -> {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
modifier = Modifier.align(Alignment.TopCenter),
)
@@ -241,7 +245,7 @@
}
is PatternBouncerViewModel -> {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
modifier = Modifier.align(Alignment.TopCenter),
)
@@ -280,7 +284,7 @@
modifier = Modifier.fillMaxWidth().align(Alignment.Center),
) {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
)
OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
@@ -376,7 +380,7 @@
modifier = Modifier.fillMaxWidth()
) {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
)
OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
@@ -441,7 +445,7 @@
modifier = Modifier.fillMaxWidth(),
) {
StatusMessage(
- viewModel = viewModel,
+ viewModel = viewModel.message,
)
OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
@@ -480,6 +484,7 @@
onChangeScene = {},
transitions = SceneTransitions,
modifier = modifier,
+ enableInterruptions = false,
) {
scene(SceneKeys.ContiguousSceneKey) {
FoldableScene(
@@ -548,26 +553,44 @@
@Composable
private fun StatusMessage(
- viewModel: BouncerViewModel,
+ viewModel: BouncerMessageViewModel,
modifier: Modifier = Modifier,
) {
- val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
+ val message: MessageViewModel? by viewModel.message.collectAsState()
+
+ DisposableEffect(Unit) {
+ viewModel.onShown()
+ onDispose {}
+ }
Crossfade(
targetState = message,
label = "Bouncer message",
- animationSpec = if (message.isUpdateAnimated) tween() else snap(),
+ animationSpec = if (message?.isUpdateAnimated == true) tween() else snap(),
modifier = modifier.fillMaxWidth(),
- ) {
- Box(
- contentAlignment = Alignment.Center,
+ ) { msg ->
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth(),
) {
- Text(
- text = it.text,
- color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyLarge,
- )
+ msg?.let {
+ Text(
+ text = it.text,
+ color = MaterialTheme.colorScheme.onSurface,
+ fontSize = 18.sp,
+ lineHeight = 24.sp,
+ overflow = TextOverflow.Ellipsis,
+ )
+ Spacer(modifier = Modifier.size(10.dp))
+ Text(
+ text = it.secondaryText ?: "",
+ color = MaterialTheme.colorScheme.onSurface,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 2
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 2a13d49..c34f2fd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -74,10 +74,7 @@
val isImeSwitcherButtonVisible by viewModel.isImeSwitcherButtonVisible.collectAsState()
val selectedUserId by viewModel.selectedUserId.collectAsState()
- DisposableEffect(Unit) {
- viewModel.onShown()
- onDispose { viewModel.onHidden() }
- }
+ DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
LaunchedEffect(animateFailure) {
if (animateFailure) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index 0a5f5d2..a78c2c0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -72,10 +72,7 @@
centerDotsVertically: Boolean,
modifier: Modifier = Modifier,
) {
- DisposableEffect(Unit) {
- viewModel.onShown()
- onDispose { viewModel.onHidden() }
- }
+ DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
val colCount = viewModel.columnCount
val rowCount = viewModel.rowCount
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index f505b90..5651a46 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -72,10 +72,7 @@
verticalSpacing: Dp,
modifier: Modifier = Modifier,
) {
- DisposableEffect(Unit) {
- viewModel.onShown()
- onDispose { viewModel.onHidden() }
- }
+ DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index d0c4984..a1d8c29 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -71,6 +71,7 @@
currentScene,
onChangeScene = { viewModel.onSceneChanged(it) },
transitions = sceneTransitions,
+ enableInterruptions = false,
)
val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
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 6a510bd..e1608c4 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
@@ -76,7 +76,6 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -159,7 +158,9 @@
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
- ScrollOnNewSmartspaceEffect(viewModel, gridState)
+ if (!viewModel.isEditMode) {
+ ScrollOnUpdatedLiveContentEffect(communalContent, gridState)
+ }
Box(
modifier =
@@ -331,31 +332,33 @@
viewModel.signalUserInteraction()
}
+/**
+ * Observes communal content and scrolls to any added or updated live content, e.g. a new media
+ * session is started, or a paused timer is resumed.
+ */
@Composable
-private fun ScrollOnNewSmartspaceEffect(
- viewModel: BaseCommunalViewModel,
- gridState: LazyGridState
+private fun ScrollOnUpdatedLiveContentEffect(
+ communalContent: List<CommunalContentModel>,
+ gridState: LazyGridState,
) {
- val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
- var smartspaceCount by remember { mutableStateOf(0) }
+ val coroutineScope = rememberCoroutineScope()
+ val liveContentKeys = remember { mutableListOf<String>() }
LaunchedEffect(communalContent) {
- snapshotFlow { gridState.firstVisibleItemIndex }
- .collect { index ->
- val existingSmartspaceCount = smartspaceCount
- smartspaceCount = communalContent.count { it.isSmartspace() }
- val firstIndex = communalContent.indexOfFirst { it.isSmartspace() }
+ val prevLiveContentKeys = liveContentKeys.toList()
+ liveContentKeys.clear()
+ liveContentKeys.addAll(communalContent.filter { it.isLiveContent() }.map { it.key })
- // Scroll to the beginning of the smartspace area whenever the number of
- // smartspace elements grows
- if (
- existingSmartspaceCount < smartspaceCount &&
- !viewModel.isEditMode &&
- index > firstIndex
- ) {
- gridState.animateScrollToItem(firstIndex)
- }
- }
+ // Find the first updated content
+ val indexOfFirstUpdatedContent =
+ liveContentKeys.indexOfFirst { !prevLiveContentKeys.contains(it) }
+
+ // Scroll if current position is behind the first updated content
+ if (indexOfFirstUpdatedContent in 0..<gridState.firstVisibleItemIndex) {
+ // Launching with a scope to prevent the job from being canceled in the case of a
+ // recomposition during scrolling
+ coroutineScope.launch { gridState.animateScrollToItem(indexOfFirstUpdatedContent) }
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index bc4e555..1178cc8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -74,6 +74,7 @@
transitions =
transitions { sceneKeyByBlueprintId.values.forEach { sceneKey -> to(sceneKey) } },
modifier = modifier,
+ enableInterruptions = false,
) {
sceneKeyByBlueprint.entries.forEach { (blueprint, sceneKey) ->
scene(sceneKey) { with(blueprint) { Content(Modifier.fillMaxSize()) } }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
index d9ed497..a12f099 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
@@ -80,5 +80,14 @@
object ClockElementKeys {
val largeClockElementKey = ElementKey("large-clock")
val smallClockElementKey = ElementKey("small-clock")
+ val weatherSmallClockElementKey = ElementKey("weather-small-clock")
val smartspaceElementKey = ElementKey("smart-space")
}
+
+object WeatherClockElementKeys {
+ val timeElementKey = ElementKey("weather-large-clock-time")
+ val dateElementKey = ElementKey("weather-large-clock-date")
+ val weatherIconElementKey = ElementKey("weather-large-clock-weather-icon")
+ val temperatureElementKey = ElementKey("weather-large-clock-temperature")
+ val dndAlarmElementKey = ElementKey("weather-large-clock-dnd-alarm")
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
index ee4e2d6..fe774a0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -23,6 +23,8 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.layout.Layout
@@ -33,11 +35,14 @@
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
+import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.systemui.Flags
+import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
+import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
@@ -47,8 +52,8 @@
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
-import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
import dagger.Binds
@@ -71,6 +76,7 @@
private val settingsMenuSection: SettingsMenuSection,
private val clockInteractor: KeyguardClockInteractor,
private val mediaCarouselSection: MediaCarouselSection,
+ private val clockViewModel: KeyguardClockViewModel,
) : ComposableLockscreenSceneBlueprint {
override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
@@ -79,7 +85,7 @@
val isUdfpsVisible = viewModel.isUdfpsVisible
val burnIn = rememberBurnIn(clockInteractor)
val resources = LocalContext.current.resources
-
+ val currentClockState = clockViewModel.currentClock.collectAsState()
LockscreenLongPress(
viewModel = viewModel.longPress,
modifier = modifier,
@@ -91,7 +97,34 @@
modifier = Modifier.fillMaxWidth(),
) {
with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
- // TODO: Add weather clock for small and large clock
+ val currentClock = currentClockState.value
+ val clockSize by clockViewModel.clockSize.collectAsState()
+ with(weatherClockSection) {
+ if (currentClock == null) {
+ return@with
+ }
+
+ if (clockSize == LARGE) {
+ Time(
+ clock = currentClock,
+ modifier =
+ Modifier.padding(
+ start =
+ dimensionResource(
+ customizationR.dimen.clock_padding_start
+ )
+ )
+ )
+ } else {
+ SmallClock(
+ burnInParams = burnIn.parameters,
+ modifier =
+ Modifier.align(Alignment.Start)
+ .onTopPlacementChanged(burnIn.onSmallClockTopChanged),
+ clock = currentClock
+ )
+ }
+ }
with(smartSpaceSection) {
SmartSpace(
burnInParams = burnIn.parameters,
@@ -119,6 +152,12 @@
)
}
}
+ with(weatherClockSection) {
+ if (currentClock == null || clockSize != LARGE) {
+ return@with
+ }
+ LargeClockSectionBelowSmartspace(clock = currentClock)
+ }
if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
with(ambientIndicationSectionOptional.get()) {
@@ -234,6 +273,7 @@
private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
private val weatherClockSection: WeatherClockSection,
private val mediaCarouselSection: MediaCarouselSection,
+ private val clockViewModel: KeyguardClockViewModel,
) : ComposableLockscreenSceneBlueprint {
override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
@@ -242,7 +282,7 @@
val isUdfpsVisible = viewModel.isUdfpsVisible
val burnIn = rememberBurnIn(clockInteractor)
val resources = LocalContext.current.resources
-
+ val currentClockState = clockViewModel.currentClock.collectAsState()
LockscreenLongPress(
viewModel = viewModel.longPress,
modifier = modifier,
@@ -257,11 +297,42 @@
Row(
modifier = Modifier.fillMaxSize(),
) {
- // TODO: Add weather clock for small and large clock
Column(
modifier = Modifier.fillMaxHeight().weight(weight = 1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
+ val currentClock = currentClockState.value
+ val clockSize by clockViewModel.clockSize.collectAsState()
+ with(weatherClockSection) {
+ if (currentClock == null) {
+ return@with
+ }
+
+ if (clockSize == LARGE) {
+ Time(
+ clock = currentClock,
+ modifier =
+ Modifier.align(Alignment.Start)
+ .padding(
+ start =
+ dimensionResource(
+ customizationR.dimen
+ .clock_padding_start
+ )
+ )
+ )
+ } else {
+ SmallClock(
+ burnInParams = burnIn.parameters,
+ modifier =
+ Modifier.align(Alignment.Start)
+ .onTopPlacementChanged(
+ burnIn.onSmallClockTopChanged
+ ),
+ clock = currentClock,
+ )
+ }
+ }
with(smartSpaceSection) {
SmartSpace(
burnInParams = burnIn.parameters,
@@ -284,6 +355,14 @@
}
with(mediaCarouselSection) { MediaCarousel() }
+
+ with(weatherClockSection) {
+ if (currentClock == null || clockSize != LARGE) {
+ return@with
+ }
+
+ LargeClockSectionBelowSmartspace(currentClock)
+ }
}
with(notificationSection) {
val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 82e19e7c..2781f39 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -20,6 +20,7 @@
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -32,6 +33,7 @@
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R as customizationR
+import com.android.systemui.customization.R
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smallClockElementKey
import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
@@ -58,20 +60,21 @@
if (currentClock?.smallClock?.view == null) {
return
}
- viewModel.clock = currentClock
-
val context = LocalContext.current
MovableElement(key = smallClockElementKey, modifier = modifier) {
content {
AndroidView(
factory = { context ->
FrameLayout(context).apply {
- addClockView(checkNotNull(currentClock).smallClock.view)
+ ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
}
},
- update = { it.addClockView(checkNotNull(currentClock).smallClock.view) },
+ update = {
+ it.ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
+ },
modifier =
- Modifier.padding(
+ Modifier.height(dimensionResource(R.dimen.small_clock_height))
+ .padding(
horizontal =
dimensionResource(customizationR.dimen.clock_padding_start)
)
@@ -89,27 +92,27 @@
@Composable
fun SceneScope.LargeClock(modifier: Modifier = Modifier) {
val currentClock by viewModel.currentClock.collectAsState()
- viewModel.clock = currentClock
if (currentClock?.largeClock?.view == null) {
return
}
-
MovableElement(key = largeClockElementKey, modifier = modifier) {
content {
AndroidView(
factory = { context ->
FrameLayout(context).apply {
- addClockView(checkNotNull(currentClock).largeClock.view)
+ ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
}
},
- update = { it.addClockView(checkNotNull(currentClock).largeClock.view) },
+ update = {
+ it.ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
+ },
modifier = Modifier.fillMaxSize()
)
}
}
}
- private fun FrameLayout.addClockView(clockView: View) {
+ private fun FrameLayout.ensureClockViewExists(clockView: View) {
if (contains(clockView)) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 31d3fa0..9f02201 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -32,12 +32,12 @@
import com.android.compose.animation.scene.SceneScope
import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.biometrics.AuthController
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -69,7 +69,7 @@
) {
@Composable
fun SceneScope.LockIcon(modifier: Modifier = Modifier) {
- if (!keyguardBottomAreaRefactor() && !DeviceEntryUdfpsRefactor.isEnabled) {
+ if (!KeyguardBottomAreaRefactor.isEnabled && !DeviceEntryUdfpsRefactor.isEnabled) {
return
}
@@ -96,7 +96,7 @@
)
}
} else {
- // keyguardBottomAreaRefactor()
+ // KeyguardBottomAreaRefactor.isEnabled
LockIconView(context, null).apply {
id = R.id.lock_icon_view
lockIconViewController.get().setLockIconView(this)
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 5c9b271..6b86a48 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
@@ -16,50 +16,34 @@
package com.android.systemui.keyguard.ui.composable.section
-import android.content.Context
import android.view.ViewGroup
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.android.compose.animation.scene.SceneScope
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.notifications.ui.composable.NotificationStack
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
-import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
@SysUISingleton
class NotificationSection
@Inject
constructor(
- @Application private val context: Context,
private val viewModel: NotificationsPlaceholderViewModel,
- controller: NotificationStackScrollLayoutController,
- sceneContainerFlags: SceneContainerFlags,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
stackScrollLayout: NotificationStackScrollLayout,
- notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
- ambientState: AmbientState,
- notificationStackSizeCalculator: NotificationStackSizeCalculator,
- @Main private val mainImmediateDispatcher: CoroutineDispatcher,
+ sharedNotificationContainerBinder: SharedNotificationContainerBinder,
) {
init {
- if (!migrateClocksToBlueprint()) {
- throw IllegalStateException("this requires migrateClocksToBlueprint()")
+ if (!MigrateClocksToBlueprint.isEnabled) {
+ throw IllegalStateException("this requires MigrateClocksToBlueprint.isEnabled")
}
// This scene container section moves the NSSL to the SharedNotificationContainer.
// This also requires that SharedNotificationContainer gets moved to the
@@ -73,25 +57,10 @@
sharedNotificationContainer.addNotificationStackScrollLayout(stackScrollLayout)
}
- SharedNotificationContainerBinder.bind(
+ sharedNotificationContainerBinder.bind(
sharedNotificationContainer,
sharedNotificationContainerViewModel,
- sceneContainerFlags,
- controller,
- notificationStackSizeCalculator,
- mainImmediateDispatcher = mainImmediateDispatcher,
)
-
- if (sceneContainerFlags.isEnabled()) {
- NotificationStackAppearanceViewBinder.bind(
- context,
- sharedNotificationContainer,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
- mainImmediateDispatcher = mainImmediateDispatcher,
- )
- }
}
@Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 7635841..d72d5ca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -92,6 +92,7 @@
currentScene = currentScene,
onChangeScene = {},
transitions = ClockTransition.defaultClockTransitions,
+ enableInterruptions = false,
) {
scene(ClockScenes.splitShadeLargeClockScene) {
Row(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index 2e7bc2a..d358453 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -16,45 +16,177 @@
package com.android.systemui.keyguard.ui.composable.section
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+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.systemui.customization.R
+import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.weatherSmallClockElementKey
+import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
+import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.plugins.clocks.ClockController
import javax.inject.Inject
/** Provides small clock and large clock composables for the weather clock layout. */
-class WeatherClockSection @Inject constructor() {
+class WeatherClockSection
+@Inject
+constructor(
+ private val viewModel: KeyguardClockViewModel,
+ private val aodBurnInViewModel: AodBurnInViewModel,
+) {
@Composable
fun SceneScope.Time(
+ clock: ClockController,
modifier: Modifier = Modifier,
) {
- // TODO: compose view
+ WeatherElement(
+ weatherClockElementViewId = R.id.weather_clock_time,
+ clock = clock,
+ elementKey = WeatherClockElementKeys.timeElementKey,
+ modifier = modifier.wrapContentSize(),
+ )
}
@Composable
- fun SceneScope.Date(
+ private fun SceneScope.Date(
+ clock: ClockController,
modifier: Modifier = Modifier,
) {
- // TODO: compose view
+ WeatherElement(
+ weatherClockElementViewId = R.id.weather_clock_date,
+ clock = clock,
+ elementKey = WeatherClockElementKeys.dateElementKey,
+ modifier = modifier,
+ )
}
@Composable
- fun SceneScope.Weather(
+ private fun SceneScope.Weather(
+ clock: ClockController,
modifier: Modifier = Modifier,
) {
- // TODO: compose view
+ WeatherElement(
+ weatherClockElementViewId = R.id.weather_clock_weather_icon,
+ clock = clock,
+ elementKey = WeatherClockElementKeys.weatherIconElementKey,
+ modifier = modifier.wrapContentSize(),
+ )
}
@Composable
- fun SceneScope.DndAlarmStatus(
+ private fun SceneScope.DndAlarmStatus(
+ clock: ClockController,
modifier: Modifier = Modifier,
) {
- // TODO: compose view
+ WeatherElement(
+ weatherClockElementViewId = R.id.weather_clock_alarm_dnd,
+ clock = clock,
+ elementKey = WeatherClockElementKeys.dndAlarmElementKey,
+ modifier = modifier.wrapContentSize(),
+ )
}
@Composable
- fun SceneScope.Temperature(
+ private fun SceneScope.Temperature(
+ clock: ClockController,
modifier: Modifier = Modifier,
) {
- // TODO: compose view
+ WeatherElement(
+ weatherClockElementViewId = R.id.weather_clock_temperature,
+ clock = clock,
+ elementKey = WeatherClockElementKeys.temperatureElementKey,
+ modifier = modifier.wrapContentSize(),
+ )
+ }
+
+ @Composable
+ private fun SceneScope.WeatherElement(
+ weatherClockElementViewId: Int,
+ clock: ClockController,
+ elementKey: ElementKey,
+ modifier: Modifier
+ ) {
+ MovableElement(key = elementKey, modifier) {
+ content {
+ AndroidView(
+ factory = {
+ val view =
+ clock.largeClock.layout.views.first {
+ it.id == weatherClockElementViewId
+ }
+ (view.parent as? ViewGroup)?.removeView(view)
+ view
+ },
+ update = {},
+ modifier = modifier
+ )
+ }
+ }
+ }
+
+ @Composable
+ fun SceneScope.LargeClockSectionBelowSmartspace(
+ clock: ClockController,
+ ) {
+ Row(
+ modifier =
+ Modifier.height(IntrinsicSize.Max)
+ .padding(horizontal = dimensionResource(R.dimen.clock_padding_start))
+ ) {
+ Date(clock = clock, modifier = Modifier.wrapContentSize())
+ Box(modifier = Modifier.fillMaxSize()) {
+ Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))
+ Temperature(clock = clock, modifier = Modifier.align(Alignment.BottomEnd))
+ DndAlarmStatus(clock = clock, modifier = Modifier.align(Alignment.TopEnd))
+ }
+ }
+ }
+
+ @Composable
+ fun SceneScope.SmallClock(
+ burnInParams: BurnInParameters,
+ modifier: Modifier = Modifier,
+ clock: ClockController,
+ ) {
+ val localContext = LocalContext.current
+ MovableElement(key = weatherSmallClockElementKey, modifier) {
+ content {
+ AndroidView(
+ factory = {
+ val view = clock.smallClock.view
+ if (view.parent != null) {
+ (view.parent as? ViewGroup)?.removeView(view)
+ }
+ view
+ },
+ modifier =
+ modifier
+ .height(dimensionResource(R.dimen.small_clock_height))
+ .padding(start = dimensionResource(R.dimen.clock_padding_start))
+ .padding(top = { viewModel.getSmallClockTopMargin(localContext) })
+ .burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ ),
+ update = {},
+ )
+ }
+ }
}
}
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 d780978..9ba5e3b 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
@@ -57,6 +57,7 @@
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
@@ -70,9 +71,10 @@
import com.android.systemui.notifications.ui.composable.Notifications.Form
import com.android.systemui.notifications.ui.composable.Notifications.TransitionThresholds.EXPANSION_FOR_MAX_CORNER_RADIUS
import com.android.systemui.notifications.ui.composable.Notifications.TransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA
+import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.composable.ShadeHeader
-import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder.SCRIM_CORNER_RADIUS
+import com.android.systemui.statusbar.notification.stack.shared.model.StackRounding
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import kotlin.math.roundToInt
@@ -139,6 +141,7 @@
) {
val density = LocalDensity.current
val screenCornerRadius = LocalScreenCornerRadius.current
+ val scrimCornerRadius = dimensionResource(R.dimen.notification_scrim_corner_radius)
val scrollState = rememberScrollState()
val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f)
val expansionFraction by viewModel.expandFraction.collectAsState(0f)
@@ -156,6 +159,8 @@
val contentHeight = viewModel.intrinsicContentHeight.collectAsState()
+ val stackRounding = viewModel.stackRounding.collectAsState(StackRounding())
+
// the offset for the notifications scrim. Its upper bound is 0, and its lower bound is
// calculated in minScrimOffset. The scrim is the same height as the screen minus the
// height of the Shade Header, and at rest (scrimOffset = 0) its top bound is at maxScrimStartY.
@@ -222,16 +227,12 @@
.graphicsLayer {
shape =
calculateCornerRadius(
+ scrimCornerRadius,
screenCornerRadius,
{ expansionFraction },
layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade)
)
- .let {
- RoundedCornerShape(
- topStart = it,
- topEnd = it,
- )
- }
+ .let { stackRounding.value.toRoundedCornerShape(it) }
clip = true
}
) {
@@ -359,6 +360,7 @@
}
private fun calculateCornerRadius(
+ scrimCornerRadius: Dp,
screenCornerRadius: Dp,
expansionFraction: () -> Float,
transitioning: Boolean,
@@ -366,12 +368,12 @@
return if (transitioning) {
lerp(
start = screenCornerRadius.value,
- stop = SCRIM_CORNER_RADIUS,
- fraction = (expansionFraction() / EXPANSION_FOR_MAX_CORNER_RADIUS).coerceAtMost(1f),
+ stop = scrimCornerRadius.value,
+ fraction = (expansionFraction() / EXPANSION_FOR_MAX_CORNER_RADIUS).coerceIn(0f, 1f),
)
.dp
} else {
- SCRIM_CORNER_RADIUS.dp
+ scrimCornerRadius
}
}
@@ -394,5 +396,16 @@
this
}
+fun StackRounding.toRoundedCornerShape(radius: Dp): RoundedCornerShape {
+ val topRadius = if (roundTop) radius else 0.dp
+ val bottomRadius = if (roundBottom) radius else 0.dp
+ return RoundedCornerShape(
+ topStart = topRadius,
+ topEnd = topRadius,
+ bottomStart = bottomRadius,
+ bottomEnd = bottomRadius,
+ )
+}
+
private const val TAG = "FlexiNotifs"
private val DEBUG_COLOR = Color(1f, 0f, 0f, 0.2f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 0fdaabe..fe6701c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -79,6 +79,7 @@
initialScene = currentSceneKey,
canChangeScene = { toScene -> viewModel.canChangeScene(toScene) },
transitions = SceneContainerTransitions,
+ enableInterruptions = false,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index dea9485..5349acd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -1,6 +1,11 @@
package com.android.systemui.scene.ui.composable
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
import com.android.compose.animation.scene.transitions
+import com.android.systemui.bouncer.ui.composable.Bouncer
+import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
@@ -27,6 +32,10 @@
* Please keep the list sorted alphabetically.
*/
val SceneContainerTransitions = transitions {
+ defaultSwipeSpec = spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)
+
+ // Scene transitions
+
from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
from(
@@ -64,4 +73,13 @@
from(Scenes.Lockscreen, to = Scenes.QuickSettings) { lockscreenToQuickSettingsTransition() }
from(Scenes.Lockscreen, to = Scenes.Gone) { lockscreenToGoneTransition() }
from(Scenes.Shade, to = Scenes.QuickSettings) { shadeToQuickSettingsTransition() }
+
+ // Scene overscroll
+
+ overscroll(Scenes.Bouncer, Orientation.Vertical) {
+ translate(Bouncer.Elements.Content, y = { absoluteDistance })
+ }
+ overscroll(Scenes.Shade, Orientation.Vertical) {
+ translate(Notifications.Elements.NotificationScrim, y = { absoluteDistance })
+ }
}
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 12b07a3..c5c48e6 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
@@ -32,6 +32,7 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
+import androidx.compose.material3.ColorScheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -40,6 +41,7 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout
@@ -97,6 +99,11 @@
val CollapsedHeight = 48.dp
val ExpandedHeight = 120.dp
}
+
+ object Colors {
+ val ColorScheme.shadeHeaderText: Color
+ get() = Color.White
+ }
}
@Composable
@@ -325,7 +332,10 @@
val animatedScale by animateElementFloatAsState(scale, ClockScale, canOverflow = false)
AndroidView(
factory = { context ->
- Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
+ Clock(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header),
+ null,
+ )
},
modifier =
modifier
@@ -430,11 +440,16 @@
AndroidView(
factory = { context ->
- val iconContainer = StatusIconContainer(context, null)
+ val themedContext =
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header)
+ val iconContainer = StatusIconContainer(themedContext, null)
val iconManager = createTintedIconManager(iconContainer, StatusBarLocation.QS)
iconManager.setTint(
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary),
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimaryInverse),
+ Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary),
+ Utils.getColorAttrDefaultColor(
+ themedContext,
+ android.R.attr.textColorPrimaryInverse
+ ),
)
statusBarIconController.addIconGroup(iconManager)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 677fb1d..85798ac 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -55,6 +55,7 @@
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.animateSceneFloatAsState
@@ -294,6 +295,7 @@
}
val quickSettingsScrollState = rememberScrollState()
+ val isScrollable = layoutState.transitionState is TransitionState.Idle
LaunchedEffect(isCustomizing, quickSettingsScrollState) {
if (isCustomizing) {
quickSettingsScrollState.scrollTo(0)
@@ -322,36 +324,41 @@
Column(
verticalArrangement = Arrangement.Top,
modifier =
- Modifier.weight(1f).fillMaxHeight().thenIf(!isCustomizing) {
- Modifier.verticalNestedScrollToScene()
- .verticalScroll(quickSettingsScrollState)
- .clipScrollableContainer(Orientation.Horizontal)
- .padding(bottom = navBarBottomHeight)
- }
+ Modifier.weight(1f).fillMaxSize().thenIf(!isCustomizing) {
+ Modifier.padding(bottom = navBarBottomHeight)
+ },
) {
- Box(
- modifier = Modifier.element(QuickSettings.Elements.SplitShadeQuickSettings)
+ Column(
+ modifier =
+ Modifier.fillMaxSize().weight(1f).thenIf(!isCustomizing) {
+ Modifier.verticalNestedScrollToScene()
+ .verticalScroll(
+ quickSettingsScrollState,
+ enabled = isScrollable
+ )
+ .clipScrollableContainer(Orientation.Horizontal)
+ }
) {
- QuickSettings(
- qsSceneAdapter = viewModel.qsSceneAdapter,
- heightProvider = { viewModel.qsSceneAdapter.qsHeight },
- isSplitShade = true,
+ Box(
+ modifier =
+ Modifier.element(QuickSettings.Elements.SplitShadeQuickSettings)
+ ) {
+ QuickSettings(
+ qsSceneAdapter = viewModel.qsSceneAdapter,
+ heightProvider = { viewModel.qsSceneAdapter.qsHeight },
+ isSplitShade = true,
+ modifier = Modifier.fillMaxWidth(),
+ squishiness = tileSquishiness,
+ )
+ }
+
+ MediaIfVisible(
+ viewModel = viewModel,
+ mediaCarouselController = mediaCarouselController,
+ mediaHost = mediaHost,
modifier = Modifier.fillMaxWidth(),
- squishiness = tileSquishiness,
)
}
-
- MediaIfVisible(
- viewModel = viewModel,
- mediaCarouselController = mediaCarouselController,
- mediaHost = mediaHost,
- modifier = Modifier.fillMaxWidth(),
- )
-
- Spacer(
- modifier = Modifier.weight(1f),
- )
-
FooterActionsWithAnimatedVisibility(
viewModel = footerActionsViewModel,
isCustomizing = isCustomizing,
@@ -363,7 +370,8 @@
NotificationScrollingStack(
viewModel = viewModel.notifications,
maxScrimTop = { 0f },
- modifier = Modifier.weight(1f).fillMaxHeight(),
+ modifier =
+ Modifier.weight(1f).fillMaxHeight().padding(bottom = navBarBottomHeight),
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
index 799dbd6..5e107c6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
@@ -4,9 +4,9 @@
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
+import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.shadeHeaderText
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@Composable
@@ -23,16 +23,16 @@
{
Text(
text = longerText.value,
- style = MaterialTheme.typography.titleSmall,
- color = MaterialTheme.colorScheme.onBackground,
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.shadeHeaderText,
maxLines = 1,
)
},
{
Text(
text = shorterText.value,
- style = MaterialTheme.typography.titleSmall,
- color = MaterialTheme.colorScheme.onBackground,
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.shadeHeaderText,
maxLines = 1,
)
},
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
index ae267e2..98d1afd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt
@@ -16,38 +16,38 @@
package com.android.systemui.volume.panel.component.selector.ui.composable
-import androidx.compose.animation.core.animateOffsetAsState
-import androidx.compose.foundation.Canvas
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.CornerRadius
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastFirst
+import kotlinx.coroutines.launch
/**
* Radio button group for the Volume Panel. It allows selecting a single item
@@ -65,8 +65,8 @@
spacing: Dp = VolumePanelRadioButtonBarDefaults.DefaultSpacing,
labelIndicatorBackgroundSpacing: Dp =
VolumePanelRadioButtonBarDefaults.DefaultLabelIndicatorBackgroundSpacing,
- indicatorCornerRadius: CornerRadius =
- VolumePanelRadioButtonBarDefaults.defaultIndicatorCornerRadius(),
+ indicatorCornerSize: CornerSize =
+ CornerSize(VolumePanelRadioButtonBarDefaults.DefaultIndicatorCornerRadius),
indicatorBackgroundCornerSize: CornerSize =
CornerSize(VolumePanelRadioButtonBarDefaults.DefaultIndicatorBackgroundCornerRadius),
colors: VolumePanelRadioButtonBarColors = VolumePanelRadioButtonBarDefaults.defaultColors(),
@@ -76,60 +76,41 @@
VolumePanelRadioButtonBarScopeImpl().apply(content).apply {
require(hasSelectedItem) { "At least one item should be selected" }
}
-
val items = scope.items
- var selectedIndex by remember { mutableIntStateOf(items.indexOfFirst { it.isSelected }) }
-
- var size by remember { mutableStateOf(IntSize(0, 0)) }
- val spacingPx = with(LocalDensity.current) { spacing.toPx() }
- val indicatorWidth = size.width / items.size - (spacingPx * (items.size - 1) / items.size)
- val offset by
- animateOffsetAsState(
- targetValue =
- Offset(
- selectedIndex * indicatorWidth + (spacingPx * selectedIndex),
- 0f,
- ),
- label = "VolumePanelRadioButtonOffsetAnimation",
- finishedListener = {
- for (itemIndex in items.indices) {
- val item = items[itemIndex]
- if (itemIndex == selectedIndex) {
- item.onItemSelected()
- break
- }
- }
- }
- )
-
- Column(modifier = modifier) {
- Box(modifier = Modifier.height(IntrinsicSize.Max)) {
- Canvas(
+ val coroutineScope = rememberCoroutineScope()
+ val offsetAnimatable = remember { Animatable(UNSET_OFFSET, Int.VectorConverter) }
+ Layout(
+ modifier = modifier,
+ content = {
+ Spacer(
modifier =
- Modifier.fillMaxSize()
+ Modifier.layoutId(RadioButtonBarComponent.ButtonsBackground)
.background(
colors.indicatorBackgroundColor,
RoundedCornerShape(indicatorBackgroundCornerSize),
)
+ )
+ Spacer(
+ modifier =
+ Modifier.layoutId(RadioButtonBarComponent.Indicator)
+ .offset { IntOffset(offsetAnimatable.value, 0) }
.padding(indicatorBackgroundPadding)
- .onGloballyPositioned { size = it.size }
- ) {
- drawRoundRect(
- color = colors.indicatorColor,
- topLeft = offset,
- size = Size(indicatorWidth, size.height.toFloat()),
- cornerRadius = indicatorCornerRadius,
- )
- }
+ .background(
+ colors.indicatorColor,
+ RoundedCornerShape(indicatorCornerSize),
+ )
+ )
Row(
- modifier = Modifier.padding(indicatorBackgroundPadding),
+ modifier =
+ Modifier.layoutId(RadioButtonBarComponent.Buttons)
+ .padding(indicatorBackgroundPadding),
horizontalArrangement = Arrangement.spacedBy(spacing)
) {
for (itemIndex in items.indices) {
TextButton(
modifier = Modifier.weight(1f),
- onClick = { selectedIndex = itemIndex },
+ onClick = { items[itemIndex].onItemSelected() },
) {
val item = items[itemIndex]
if (item.icon !== Empty) {
@@ -138,28 +119,116 @@
}
}
}
- }
-
- Row(
- modifier =
- Modifier.padding(
- start = indicatorBackgroundPadding,
- top = labelIndicatorBackgroundSpacing,
- end = indicatorBackgroundPadding
- ),
- horizontalArrangement = Arrangement.spacedBy(spacing),
- ) {
- for (itemIndex in items.indices) {
- TextButton(
- modifier = Modifier.weight(1f),
- onClick = { selectedIndex = itemIndex },
- ) {
- val item = items[itemIndex]
- if (item.icon !== Empty) {
- with(items[itemIndex]) { label() }
+ Row(
+ modifier =
+ Modifier.layoutId(RadioButtonBarComponent.Labels)
+ .padding(
+ start = indicatorBackgroundPadding,
+ top = labelIndicatorBackgroundSpacing,
+ end = indicatorBackgroundPadding
+ ),
+ horizontalArrangement = Arrangement.spacedBy(spacing),
+ ) {
+ for (itemIndex in items.indices) {
+ TextButton(
+ modifier = Modifier.weight(1f),
+ onClick = { items[itemIndex].onItemSelected() },
+ ) {
+ val item = items[itemIndex]
+ if (item.icon !== Empty) {
+ with(items[itemIndex]) { label() }
+ }
}
}
}
+ },
+ measurePolicy =
+ with(LocalDensity.current) {
+ val spacingPx =
+ (spacing - indicatorBackgroundPadding * 2).roundToPx().coerceAtLeast(0)
+
+ BarMeasurePolicy(
+ buttonsCount = items.size,
+ selectedIndex = scope.selectedIndex,
+ spacingPx = spacingPx,
+ ) {
+ coroutineScope.launch {
+ if (offsetAnimatable.value == UNSET_OFFSET) {
+ offsetAnimatable.snapTo(it)
+ } else {
+ offsetAnimatable.animateTo(it)
+ }
+ }
+ }
+ },
+ )
+}
+
+private class BarMeasurePolicy(
+ private val buttonsCount: Int,
+ private val selectedIndex: Int,
+ private val spacingPx: Int,
+ private val onTargetIndicatorOffsetMeasured: (Int) -> Unit,
+) : MeasurePolicy {
+
+ override fun MeasureScope.measure(
+ measurables: List<Measurable>,
+ constraints: Constraints
+ ): MeasureResult {
+ val fillWidthConstraints = constraints.copy(minWidth = constraints.maxWidth)
+ val buttonsPlaceable: Placeable =
+ measurables
+ .fastFirst { it.layoutId == RadioButtonBarComponent.Buttons }
+ .measure(fillWidthConstraints)
+ val labelsPlaceable: Placeable =
+ measurables
+ .fastFirst { it.layoutId == RadioButtonBarComponent.Labels }
+ .measure(fillWidthConstraints)
+
+ val buttonsBackgroundPlaceable: Placeable =
+ measurables
+ .fastFirst { it.layoutId == RadioButtonBarComponent.ButtonsBackground }
+ .measure(
+ Constraints(
+ minWidth = buttonsPlaceable.width,
+ maxWidth = buttonsPlaceable.width,
+ minHeight = buttonsPlaceable.height,
+ maxHeight = buttonsPlaceable.height,
+ )
+ )
+
+ val totalSpacing = spacingPx * (buttonsCount - 1)
+ val indicatorWidth = (buttonsBackgroundPlaceable.width - totalSpacing) / buttonsCount
+ val indicatorPlaceable: Placeable =
+ measurables
+ .fastFirst { it.layoutId == RadioButtonBarComponent.Indicator }
+ .measure(
+ Constraints(
+ minWidth = indicatorWidth,
+ maxWidth = indicatorWidth,
+ minHeight = buttonsBackgroundPlaceable.height,
+ maxHeight = buttonsBackgroundPlaceable.height,
+ )
+ )
+
+ onTargetIndicatorOffsetMeasured(
+ selectedIndex * indicatorWidth + (spacingPx * selectedIndex)
+ )
+
+ return layout(constraints.maxWidth, buttonsPlaceable.height + labelsPlaceable.height) {
+ buttonsBackgroundPlaceable.placeRelative(
+ 0,
+ 0,
+ RadioButtonBarComponent.ButtonsBackground.zIndex,
+ )
+ indicatorPlaceable.placeRelative(0, 0, RadioButtonBarComponent.Indicator.zIndex)
+
+ buttonsPlaceable.placeRelative(0, 0, RadioButtonBarComponent.Buttons.zIndex)
+ labelsPlaceable.placeRelative(
+ 0,
+ buttonsBackgroundPlaceable.height,
+ RadioButtonBarComponent.Labels.zIndex,
+ )
}
}
}
@@ -179,12 +248,6 @@
val DefaultIndicatorCornerRadius = 20.dp
val DefaultIndicatorBackgroundCornerRadius = 20.dp
- @Composable
- fun defaultIndicatorCornerRadius(
- x: Dp = DefaultIndicatorCornerRadius,
- y: Dp = DefaultIndicatorCornerRadius,
- ): CornerRadius = with(LocalDensity.current) { CornerRadius(x.toPx(), y.toPx()) }
-
/**
* Returns the default VolumePanelRadioButtonBar colors.
*
@@ -225,9 +288,12 @@
private class VolumePanelRadioButtonBarScopeImpl : VolumePanelRadioButtonBarScope {
- var hasSelectedItem: Boolean = false
+ var selectedIndex: Int = UNSET_INDEX
private set
+ val hasSelectedItem: Boolean
+ get() = selectedIndex != UNSET_INDEX
+
private val mutableItems: MutableList<Item> = mutableListOf()
val items: List<Item> = mutableItems
@@ -238,21 +304,34 @@
label: @Composable RowScope.() -> Unit,
) {
require(!isSelected || !hasSelectedItem) { "Only one item should be selected at a time" }
- hasSelectedItem = hasSelectedItem || isSelected
+ if (isSelected) {
+ selectedIndex = mutableItems.size
+ }
mutableItems.add(
Item(
- isSelected = isSelected,
onItemSelected = onItemSelected,
icon = icon,
label = label,
)
)
}
+
+ private companion object {
+ const val UNSET_INDEX = -1
+ }
}
private class Item(
- val isSelected: Boolean,
val onItemSelected: () -> Unit,
val icon: @Composable RowScope.() -> Unit,
val label: @Composable RowScope.() -> Unit,
)
+
+private const val UNSET_OFFSET = -1
+
+private enum class RadioButtonBarComponent(val zIndex: Float) {
+ ButtonsBackground(0f),
+ Indicator(1f),
+ Buttons(2f),
+ Labels(2f),
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
index bed0ae8..71b3e8a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
@@ -65,7 +65,7 @@
return
}
- val enabledModelStates by viewModel.spatialAudioButtonByEnabled.collectAsState()
+ val enabledModelStates by viewModel.spatialAudioButtons.collectAsState()
if (enabledModelStates.isEmpty()) {
return
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
index 2435170..d31064a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -17,16 +17,20 @@
package com.android.systemui.volume.panel.component.volume.ui.composable
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.foundation.basicMarquee
-import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.ProgressBarRangeInfo
@@ -38,6 +42,7 @@
import androidx.compose.ui.unit.dp
import com.android.compose.PlatformSlider
import com.android.compose.PlatformSliderColors
+import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState
@@ -49,16 +54,15 @@
modifier: Modifier = Modifier,
sliderColors: PlatformSliderColors,
) {
- val value by
- animateFloatAsState(targetValue = state.value, label = "VolumeSliderValueAnimation")
+ val value by valueState(state)
PlatformSlider(
modifier =
modifier.clearAndSetSemantics {
if (!state.isEnabled) disabled()
contentDescription = state.label
- // provide a not animated value to the a11y because it fails to announce the settled
- // value when it changes rapidly.
+ // provide a not animated value to the a11y because it fails to announce the
+ // settled value when it changes rapidly.
progressBarRangeInfo = ProgressBarRangeInfo(state.value, state.valueRange)
setProgress { targetValue ->
val targetDirection =
@@ -86,44 +90,64 @@
Text(text = state.valueText, color = LocalContentColor.current)
} else {
state.icon?.let {
- IconButton(
- onClick = onIconTapped,
- colors =
- IconButtonColors(
- contentColor = LocalContentColor.current,
- containerColor = Color.Transparent,
- disabledContentColor = LocalContentColor.current,
- disabledContainerColor = Color.Transparent,
- )
- ) {
- Icon(modifier = Modifier.size(24.dp), icon = it)
- }
+ SliderIcon(
+ icon = it,
+ onIconTapped = onIconTapped,
+ isTappable = state.isMutable,
+ )
}
}
},
colors = sliderColors,
label = {
- Column(modifier = Modifier) {
- Text(
- modifier = Modifier.basicMarquee(),
- text = state.label,
- style = MaterialTheme.typography.titleMedium,
- color = LocalContentColor.current,
- maxLines = 1,
- )
-
- if (!state.isEnabled) {
- state.disabledMessage?.let { message ->
- Text(
- modifier = Modifier.basicMarquee(),
- text = message,
- style = MaterialTheme.typography.bodySmall,
- color = LocalContentColor.current,
- maxLines = 1,
- )
- }
- }
- }
+ VolumeSliderContent(
+ modifier = Modifier,
+ label = state.label,
+ isEnabled = state.isEnabled,
+ disabledMessage = state.disabledMessage,
+ )
}
)
}
+
+@Composable
+private fun valueState(state: SliderState): State<Float> {
+ var prevState by remember { mutableStateOf(state) }
+ // Don't animate slider value when receive the first value and when changing isEnabled state
+ val shouldSkipAnimation =
+ prevState is SliderState.Empty || prevState.isEnabled != state.isEnabled
+ val value =
+ if (shouldSkipAnimation) mutableFloatStateOf(state.value)
+ else animateFloatAsState(targetValue = state.value, label = "VolumeSliderValueAnimation")
+ prevState = state
+ return value
+}
+
+@Composable
+private fun SliderIcon(
+ icon: Icon,
+ onIconTapped: () -> Unit,
+ isTappable: Boolean,
+ modifier: Modifier = Modifier
+) {
+ if (isTappable) {
+ IconButton(
+ modifier = modifier,
+ onClick = onIconTapped,
+ colors =
+ IconButtonColors(
+ contentColor = LocalContentColor.current,
+ containerColor = Color.Transparent,
+ disabledContentColor = LocalContentColor.current,
+ disabledContainerColor = Color.Transparent,
+ ),
+ content = { Icon(modifier = Modifier.size(24.dp), icon = icon) },
+ )
+ } else {
+ Box(
+ modifier = modifier,
+ contentAlignment = Alignment.Center,
+ content = { Icon(modifier = Modifier.size(24.dp), icon = icon) },
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSliderContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSliderContent.kt
new file mode 100644
index 0000000..4ae4eb8
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSliderContent.kt
@@ -0,0 +1,157 @@
+/*
+ * 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.volume.panel.component.volume.ui.composable
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.shrinkVertically
+import androidx.compose.foundation.basicMarquee
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.util.fastFirst
+import androidx.compose.ui.util.fastFirstOrNull
+import kotlinx.coroutines.launch
+
+private enum class VolumeSliderContentComponent {
+ Label,
+ DisabledMessage,
+}
+
+/** Shows label of the [VolumeSlider]. Also shows [disabledMessage] when not [isEnabled]. */
+@Composable
+fun VolumeSliderContent(
+ label: String,
+ isEnabled: Boolean,
+ disabledMessage: String?,
+ modifier: Modifier = Modifier,
+) {
+ Layout(
+ modifier = modifier.animateContentHeight(),
+ content = {
+ Text(
+ modifier = Modifier.layoutId(VolumeSliderContentComponent.Label).basicMarquee(),
+ text = label,
+ style = MaterialTheme.typography.titleMedium,
+ color = LocalContentColor.current,
+ maxLines = 1,
+ )
+
+ disabledMessage?.let { message ->
+ AnimatedVisibility(
+ modifier = Modifier.layoutId(VolumeSliderContentComponent.DisabledMessage),
+ visible = !isEnabled,
+ enter = expandVertically(expandFrom = Alignment.Top) + fadeIn(),
+ exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut(),
+ ) {
+ Text(
+ modifier = Modifier.basicMarquee(),
+ text = message,
+ style = MaterialTheme.typography.bodySmall,
+ color = LocalContentColor.current,
+ maxLines = 1,
+ )
+ }
+ }
+ },
+ measurePolicy = VolumeSliderContentMeasurePolicy(isEnabled)
+ )
+}
+
+/**
+ * Uses [VolumeSliderContentComponent.Label] width when [isEnabled] and max available width
+ * otherwise. This ensures that the slider always have the correct measurement to position the
+ * content.
+ */
+private class VolumeSliderContentMeasurePolicy(private val isEnabled: Boolean) : MeasurePolicy {
+
+ override fun MeasureScope.measure(
+ measurables: List<Measurable>,
+ constraints: Constraints
+ ): MeasureResult {
+ val labelPlaceable =
+ measurables
+ .fastFirst { it.layoutId == VolumeSliderContentComponent.Label }
+ .measure(constraints)
+ val layoutWidth: Int =
+ if (isEnabled) {
+ labelPlaceable.width
+ } else {
+ constraints.maxWidth
+ }
+ val fullLayoutWidth: Int =
+ if (isEnabled) {
+ // PlatformSlider uses half of the available space for the enabled state.
+ // This is using it to allow disabled message to take whole space when animating to
+ // prevent it from jumping left to right
+ constraints.maxWidth * 2
+ } else {
+ constraints.maxWidth
+ }
+
+ val disabledMessagePlaceable =
+ measurables
+ .fastFirstOrNull { it.layoutId == VolumeSliderContentComponent.DisabledMessage }
+ ?.measure(constraints.copy(maxWidth = fullLayoutWidth))
+
+ val layoutHeight = labelPlaceable.height + (disabledMessagePlaceable?.height ?: 0)
+ return layout(layoutWidth, layoutHeight) {
+ labelPlaceable.placeRelative(0, 0, 0f)
+ disabledMessagePlaceable?.placeRelative(0, labelPlaceable.height, 0f)
+ }
+ }
+}
+
+/** Animates composable height changes. */
+@Composable
+private fun Modifier.animateContentHeight(): Modifier {
+ var heightAnimation by remember { mutableStateOf<Animatable<Int, AnimationVector1D>?>(null) }
+ val coroutineScope = rememberCoroutineScope()
+ return layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ val currentAnimation = heightAnimation
+ val anim =
+ if (currentAnimation == null) {
+ Animatable(placeable.height, Int.VectorConverter).also { heightAnimation = it }
+ } else {
+ coroutineScope.launch { currentAnimation.animateTo(placeable.height) }
+ currentAnimation
+ }
+ layout(placeable.width, anim.value) { placeable.place(0, 0) }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 6cff30c..da07f6d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -138,8 +138,9 @@
// that will actually animate it.
layoutState.startTransition(transition, transitionKey)
- // The transformation now contains the spec that we should use to instantiate the Animatable.
- val animationSpec = layoutState.transformationSpec.progressSpec
+ // The transition now contains the transformation spec that we should use to instantiate the
+ // Animatable.
+ val animationSpec = transition.transformationSpec.progressSpec
val visibilityThreshold =
(animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
val animatable =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 82083f9..1b06275 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -18,10 +18,8 @@
package com.android.compose.animation.scene
-import android.util.Log
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
@@ -145,16 +143,6 @@
}
val transitionState = layoutImpl.state.transitionState
- if (transitionState is TransitionState.Transition) {
- // TODO(b/290184746): Better handle interruptions here if state != idle.
- Log.w(
- TAG,
- "start from TransitionState.Transition is not fully supported: from" +
- " ${transitionState.fromScene} to ${transitionState.toScene} " +
- "(progress ${transitionState.progress})"
- )
- }
-
val fromScene = layoutImpl.scene(transitionState.currentScene)
val swipes = computeSwipes(fromScene, startedPosition, pointersDown)
val result =
@@ -269,19 +257,6 @@
fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
if (isDrivingTransition || force) {
layoutState.startTransition(newTransition, newTransition.key)
-
- // Initialize SwipeTransition.transformationSpec and .swipeSpec. Note that this must be
- // called right after layoutState.startTransition() is called, because it computes the
- // current layoutState.transformationSpec().
- val transformationSpec = layoutState.transformationSpec
- newTransition.transformationSpec = transformationSpec
- newTransition.swipeSpec =
- transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
- } else {
- // We were not driving the transition and we don't force the update, so the specs won't
- // be used and it doesn't matter which ones we set here.
- newTransition.transformationSpec = TransformationSpec.Empty
- newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
}
swipeTransition = newTransition
@@ -616,18 +591,6 @@
override val isUserInputOngoing: Boolean
get() = offsetAnimation == null
- /**
- * The [TransformationSpecImpl] associated to this transition.
- *
- * Note: This is lateinit because this [SwipeTransition] is needed by
- * [BaseSceneTransitionLayoutState] to compute the [TransitionSpec], and it will be set right
- * after [BaseSceneTransitionLayoutState.startTransition] is called with this transition.
- */
- lateinit var transformationSpec: TransformationSpecImpl
-
- /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
- lateinit var swipeSpec: SpringSpec<Float>
-
override val overscrollScope: OverscrollScope =
object : OverscrollScope {
override val absoluteDistance: Float
@@ -701,6 +664,9 @@
coroutineScope
.launch {
try {
+ val swipeSpec =
+ transformationSpec.swipeSpec
+ ?: layoutState.transitions.defaultSwipeSpec
animatable.animateTo(
targetValue = targetOffset,
animationSpec = swipeSpec,
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 15712b5..e7cb5a4 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
@@ -203,7 +203,7 @@
measurable: Measurable,
constraints: Constraints,
): MeasureResult {
- val overscrollScene = layoutImpl.state.currentOverscrollSpec?.scene
+ val overscrollScene = layoutImpl.state.currentTransition?.currentOverscrollSpec?.scene
if (overscrollScene != null && overscrollScene != scene.key) {
// There is an overscroll in progress on another scene
// By measuring composable elements, Compose can cache relevant information.
@@ -269,13 +269,12 @@
transition == null ||
transition.fromScene !in element.sceneStates ||
transition.toScene !in element.sceneStates ||
- layoutImpl.state.currentOverscrollSpec?.scene == scene.key
+ transition.currentOverscrollSpec?.scene == scene.key
) {
return true
}
- val sharedTransformation =
- sharedElementTransformation(layoutImpl.state, transition, element.key)
+ val sharedTransformation = sharedElementTransformation(transition, element.key)
if (sharedTransformation?.enabled == false) {
return true
}
@@ -305,23 +304,21 @@
fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
) == scene
- return chosenByPicker || layoutImpl.state.currentOverscrollSpec?.scene == scene
+ return chosenByPicker || transition.currentOverscrollSpec?.scene == scene
}
private fun isSharedElementEnabled(
- layoutState: BaseSceneTransitionLayoutState,
transition: TransitionState.Transition,
element: ElementKey,
): Boolean {
- return sharedElementTransformation(layoutState, transition, element)?.enabled ?: true
+ return sharedElementTransformation(transition, element)?.enabled ?: true
}
internal fun sharedElementTransformation(
- layoutState: BaseSceneTransitionLayoutState,
transition: TransitionState.Transition,
element: ElementKey,
): SharedElementTransformation? {
- val transformationSpec = layoutState.transformationSpec
+ val transformationSpec = transition.transformationSpec
val sharedInFromScene = transformationSpec.transformations(element, transition.fromScene).shared
val sharedInToScene = transformationSpec.transformations(element, transition.toScene).shared
@@ -360,11 +357,11 @@
}
val isSharedElement = fromState != null && toState != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(transition, element.key)) {
return true
}
- return layoutImpl.state.transformationSpec.transformations(element.key, scene.key).alpha == null
+ return transition.transformationSpec.transformations(element.key, scene.key).alpha == null
}
/**
@@ -388,6 +385,7 @@
transformation = { it.alpha },
idleValue = 1f,
currentValue = { 1f },
+ isSpecified = { true },
::lerp,
)
.fastCoerceIn(0f, 1f)
@@ -425,6 +423,7 @@
transformation = { it.size },
idleValue = lookaheadSize,
currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() },
+ isSpecified = { it != Element.SizeUnspecified },
::lerp,
)
@@ -450,6 +449,7 @@
transformation = { it.drawScale },
idleValue = Scale.Default,
currentValue = { Scale.Default },
+ isSpecified = { true },
::lerp,
)
}
@@ -490,6 +490,7 @@
transformation = { it.offset },
idleValue = targetOffsetInScene,
currentValue = { currentOffset },
+ isSpecified = { it != Offset.Unspecified },
::lerp,
)
@@ -536,6 +537,7 @@
transformation: (ElementTransformations) -> PropertyTransformation<T>?,
idleValue: T,
currentValue: () -> T,
+ isSpecified: (T) -> Boolean,
lerp: (T, T, Float) -> T,
): T {
val transition =
@@ -559,7 +561,7 @@
}
if (transition is TransitionState.HasOverscrollProperties) {
- val overscroll = layoutImpl.state.currentOverscrollSpec
+ val overscroll = transition.currentOverscrollSpec
if (overscroll?.scene == scene.key) {
val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
val propertySpec = transformation(elementSpec) ?: return currentValue()
@@ -597,17 +599,22 @@
// 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 = fromState != null && toState != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(transition, element.key)) {
val start = sceneValue(fromState!!)
val end = sceneValue(toState!!)
+ // TODO(b/316901148): Remove checks to isSpecified() once the lookahead pass runs for all
+ // nodes before the intermediate layout pass.
+ if (!isSpecified(start)) return end
+ if (!isSpecified(end)) return start
+
// 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.
return if (start == end) start else lerp(start, end, transition.progress)
}
val transformation =
- transformation(layoutImpl.state.transformationSpec.transformations(element.key, scene.key))
+ transformation(transition.transformationSpec.transformations(element.key, scene.key))
// If there is no transformation explicitly associated to this element value, let's use
// the value given by the system (like the current position and size given by the layout
// pass).
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 af51cee..dc3b612 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
@@ -73,7 +73,7 @@
internal class SceneScopeImpl(
private val layoutImpl: SceneTransitionLayoutImpl,
private val scene: Scene,
-) : SceneScope {
+) : SceneScope, ElementStateScope by layoutImpl.elementStateScope {
override val layoutState: SceneTransitionLayoutState = layoutImpl.state
override fun Modifier.element(key: ElementKey): Modifier {
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 b7e2dd1..c7c874c 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
@@ -96,9 +96,17 @@
modifier: Modifier = Modifier,
swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
@FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
+ enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
scenes: SceneTransitionLayoutScope.() -> Unit,
) {
- val state = updateSceneTransitionLayoutState(currentScene, onChangeScene, transitions)
+ val state =
+ updateSceneTransitionLayoutState(
+ currentScene,
+ onChangeScene,
+ transitions,
+ enableInterruptions = enableInterruptions,
+ )
+
SceneTransitionLayout(
state,
modifier,
@@ -131,9 +139,30 @@
*/
@DslMarker annotation class ElementDsl
+/** A scope that can be used to query the target state of an element or scene. */
+interface ElementStateScope {
+ /**
+ * Return the *target* size of [this] element in the given [scene], i.e. the size of the element
+ * when idle, or `null` if the element is not composed and measured in that scene (yet).
+ */
+ fun ElementKey.targetSize(scene: SceneKey): IntSize?
+
+ /**
+ * Return the *target* offset of [this] element in the given [scene], i.e. the size of the
+ * element when idle, or `null` if the element is not composed and placed in that scene (yet).
+ */
+ fun ElementKey.targetOffset(scene: SceneKey): Offset?
+
+ /**
+ * Return the *target* size of [this] scene, i.e. the size of the scene when idle, or `null` if
+ * the scene was never composed.
+ */
+ fun SceneKey.targetSize(): IntSize?
+}
+
@Stable
@ElementDsl
-interface BaseSceneScope {
+interface BaseSceneScope : ElementStateScope {
/** The state of the [SceneTransitionLayout] in which this scene is contained. */
val layoutState: SceneTransitionLayoutState
@@ -415,25 +444,7 @@
): Float
}
-interface UserActionDistanceScope : Density {
- /**
- * Return the *target* size of [this] element in the given [scene], i.e. the size of the element
- * when idle, or `null` if the element is not composed and measured in that scene (yet).
- */
- fun ElementKey.targetSize(scene: SceneKey): IntSize?
-
- /**
- * Return the *target* offset of [this] element in the given [scene], i.e. the size of the
- * element when idle, or `null` if the element is not composed and placed in that scene (yet).
- */
- fun ElementKey.targetOffset(scene: SceneKey): Offset?
-
- /**
- * Return the *target* size of [this] scene, i.e. the size of the scene when idle, or `null` if
- * the scene was never composed.
- */
- fun SceneKey.targetSize(): IntSize?
-}
+interface UserActionDistanceScope : Density, ElementStateScope
/** The user action has a fixed [absoluteDistance]. */
class FixedDistance(private val distance: Dp) : UserActionDistance {
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 25b0895..b1cfdcf 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
@@ -98,6 +98,7 @@
private val horizontalDraggableHandler: DraggableHandlerImpl
private val verticalDraggableHandler: DraggableHandlerImpl
+ internal val elementStateScope = ElementStateScopeImpl(this)
private var _userActionDistanceScope: UserActionDistanceScope? = null
internal val userActionDistanceScope: UserActionDistanceScope
get() =
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 617a8ea..f13c016 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
@@ -16,15 +16,16 @@
package com.android.compose.animation.scene
+import android.util.Log
+import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
+import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastFilter
import androidx.compose.ui.util.fastForEach
import com.android.compose.animation.scene.transition.link.LinkedTransition
@@ -50,10 +51,21 @@
*/
val transitionState: TransitionState
- /** The current transition, or `null` if we are idle. */
+ /**
+ * The current transition, or `null` if we are idle.
+ *
+ * Note: If you need to handle interruptions and multiple transitions running in parallel, use
+ * [currentTransitions] instead.
+ */
val currentTransition: TransitionState.Transition?
get() = transitionState as? TransitionState.Transition
+ /**
+ * The list of [TransitionState.Transition] currently running. This will be the empty list if we
+ * are idle.
+ */
+ val currentTransitions: List<TransitionState.Transition>
+
/** The [SceneTransitions] used when animating this state. */
val transitions: SceneTransitions
@@ -120,12 +132,14 @@
transitions: SceneTransitions = SceneTransitions.Empty,
canChangeScene: (SceneKey) -> Boolean = { true },
stateLinks: List<StateLink> = emptyList(),
+ enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
): MutableSceneTransitionLayoutState {
return MutableSceneTransitionLayoutStateImpl(
initialScene,
transitions,
canChangeScene,
stateLinks,
+ enableInterruptions,
)
}
@@ -154,6 +168,7 @@
transitions: SceneTransitions = SceneTransitions.Empty,
canChangeScene: (SceneKey) -> Boolean = { true },
stateLinks: List<StateLink> = emptyList(),
+ enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
): SceneTransitionLayoutState {
return remember {
HoistedSceneTransitionLayoutState(
@@ -162,9 +177,19 @@
onChangeScene,
canChangeScene,
stateLinks,
+ enableInterruptions,
)
}
- .apply { update(currentScene, onChangeScene, canChangeScene, transitions, stateLinks) }
+ .apply {
+ update(
+ currentScene,
+ onChangeScene,
+ canChangeScene,
+ transitions,
+ stateLinks,
+ enableInterruptions,
+ )
+ }
}
@Stable
@@ -204,6 +229,30 @@
/** Whether user input is currently driving the transition. */
abstract val isUserInputOngoing: Boolean
+ /**
+ * The current [TransformationSpecImpl] and [OverscrollSpecImpl] associated to this
+ * transition.
+ *
+ * Important: These will be set exactly once, when this transition is
+ * [started][BaseSceneTransitionLayoutState.startTransition].
+ */
+ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+ private var fromOverscrollSpec: OverscrollSpecImpl? = null
+ private var toOverscrollSpec: OverscrollSpecImpl? = null
+
+ /** The current [OverscrollSpecImpl], if this transition is currently overscrolling. */
+ internal val currentOverscrollSpec: OverscrollSpecImpl?
+ get() {
+ if (this !is HasOverscrollProperties) return null
+ val progress = progress
+ val bouncingScene = bouncingScene
+ return when {
+ progress < 0f || bouncingScene == fromScene -> fromOverscrollSpec
+ progress > 1f || bouncingScene == toScene -> toOverscrollSpec
+ else -> null
+ }
+ }
+
init {
check(fromScene != toScene)
}
@@ -232,6 +281,14 @@
return isTransitioning(from = scene, to = other) ||
isTransitioning(from = other, to = scene)
}
+
+ internal fun updateOverscrollSpecs(
+ fromSpec: OverscrollSpecImpl?,
+ toSpec: OverscrollSpecImpl?,
+ ) {
+ fromOverscrollSpec = fromSpec
+ toOverscrollSpec = toSpec
+ }
}
interface HasOverscrollProperties {
@@ -270,38 +327,41 @@
internal abstract class BaseSceneTransitionLayoutState(
initialScene: SceneKey,
protected var stateLinks: List<StateLink>,
+
+ // TODO(b/290930950): Remove this flag.
+ internal var enableInterruptions: Boolean,
) : SceneTransitionLayoutState {
- override var transitionState: TransitionState by
- mutableStateOf(TransitionState.Idle(initialScene))
- protected set
-
/**
- * The current [transformationSpec] associated to [transitionState]. Accessing this value makes
- * sense only if [transitionState] is a [TransitionState.Transition].
+ * The current [TransitionState]. This list will either be:
+ * 1. A list with a single [TransitionState.Idle] element, when we are idle.
+ * 2. A list with one or more [TransitionState.Transition], when we are transitioning.
*/
- internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+ @VisibleForTesting
+ internal val transitionStates: MutableList<TransitionState> =
+ SnapshotStateList<TransitionState>().apply { add(TransitionState.Idle(initialScene)) }
- private var fromOverscrollSpec: OverscrollSpecImpl? = null
- private var toOverscrollSpec: OverscrollSpecImpl? = null
+ override val transitionState: TransitionState
+ get() = transitionStates.last()
- /**
- * @return the overscroll [OverscrollSpecImpl] if it is defined for the current
- * [transitionState] and we are currently over scrolling.
- */
- internal val currentOverscrollSpec: OverscrollSpecImpl?
+ private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+
+ override val currentTransitions: List<TransitionState.Transition>
get() {
- val transition = currentTransition ?: return null
- if (transition !is TransitionState.HasOverscrollProperties) return null
- val progress = transition.progress
- val bouncingScene = transition.bouncingScene
- return when {
- progress < 0f || bouncingScene == transition.fromScene -> fromOverscrollSpec
- progress > 1f || bouncingScene == transition.toScene -> toOverscrollSpec
- else -> null
+ if (transitionStates.last() is TransitionState.Idle) {
+ check(transitionStates.size == 1)
+ return emptyList()
+ } else {
+ @Suppress("UNCHECKED_CAST")
+ return transitionStates as List<TransitionState.Transition>
}
}
- private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+ /**
+ * The mapping of transitions that are finished, i.e. for which [finishTransition] was called,
+ * to their idle scene.
+ */
+ @VisibleForTesting
+ internal val finishedTransitions = mutableMapOf<TransitionState.Transition, SceneKey>()
/** Whether we can transition to the given [scene]. */
internal abstract fun canChangeScene(scene: SceneKey): Boolean
@@ -324,7 +384,11 @@
return transition.isTransitioningBetween(scene, other)
}
- /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */
+ /**
+ * Start a new [transition], instantly interrupting any ongoing transition if there was one.
+ *
+ * Important: you *must* call [finishTransition] once the transition is finished.
+ */
internal fun startTransition(
transition: TransitionState.Transition,
transitionKey: TransitionKey?,
@@ -333,13 +397,81 @@
val fromScene = transition.fromScene
val toScene = transition.toScene
val orientation = (transition as? TransitionState.HasOverscrollProperties)?.orientation
- transformationSpec =
+
+ // Update the transition specs.
+ transition.transformationSpec =
transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec()
- fromOverscrollSpec = orientation?.let { transitions.overscrollSpec(fromScene, it) }
- toOverscrollSpec = orientation?.let { transitions.overscrollSpec(toScene, it) }
+ if (orientation != null) {
+ transition.updateOverscrollSpecs(
+ fromSpec = transitions.overscrollSpec(fromScene, orientation),
+ toSpec = transitions.overscrollSpec(toScene, orientation),
+ )
+ } else {
+ transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
+ }
+
+ // Handle transition links.
cancelActiveTransitionLinks()
setupTransitionLinks(transition)
- transitionState = transition
+
+ if (!enableInterruptions) {
+ // Set the current transition.
+ check(transitionStates.size == 1)
+ transitionStates[0] = transition
+ return
+ }
+
+ when (val currentState = transitionStates.last()) {
+ is TransitionState.Idle -> {
+ // Replace [Idle] by [transition].
+ check(transitionStates.size == 1)
+ transitionStates[0] = transition
+ }
+ is TransitionState.Transition -> {
+ // Force the current transition to finish to currentScene.
+ currentState.finish().invokeOnCompletion {
+ // Make sure [finishTransition] is called at the end of the transition.
+ finishTransition(currentState, currentState.currentScene)
+ }
+
+ // Check that we don't have too many concurrent transitions.
+ if (transitionStates.size >= MAX_CONCURRENT_TRANSITIONS) {
+ Log.wtf(
+ TAG,
+ buildString {
+ appendLine("Potential leak detected in SceneTransitionLayoutState!")
+ appendLine(
+ " Some transition(s) never called STLState.finishTransition()."
+ )
+ appendLine(" Transitions (size=${transitionStates.size}):")
+ transitionStates.fastForEach { state ->
+ val transition = state as TransitionState.Transition
+ val from = transition.fromScene
+ val to = transition.toScene
+ val indicator =
+ if (finishedTransitions.contains(transition)) "x" else " "
+ appendLine(" [$indicator] $from => $to ($transition)")
+ }
+ }
+ )
+
+ // Force finish all transitions.
+ while (currentTransitions.isNotEmpty()) {
+ val transition = transitionStates[0] as TransitionState.Transition
+ finishTransition(transition, transition.currentScene)
+ }
+
+ // We finished all transitions, so we are now idle. We remove this state so that
+ // we end up only with the new transition after appending it.
+ check(transitionStates.size == 1)
+ check(transitionStates[0] is TransitionState.Idle)
+ transitionStates.clear()
+ }
+
+ // Append the new transition.
+ transitionStates.add(transition)
+ }
+ }
}
private fun cancelActiveTransitionLinks() {
@@ -379,13 +511,54 @@
* nothing if [transition] was interrupted since it was started.
*/
internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
- resolveActiveTransitionLinks(idleScene)
- if (transitionState == transition) {
- transitionState = TransitionState.Idle(idleScene)
+ val existingIdleScene = finishedTransitions[transition]
+ if (existingIdleScene != null) {
+ // This transition was already finished.
+ check(idleScene == existingIdleScene) {
+ "Transition $transition was finished multiple times with different " +
+ "idleScene ($existingIdleScene != $idleScene)"
+ }
+ return
+ }
+
+ if (!transitionStates.contains(transition)) {
+ // This transition was already removed from transitionStates.
+ return
+ }
+
+ check(transitionStates.fastAll { it is TransitionState.Transition })
+
+ // Mark this transition as finished and save the scene it is settling at.
+ finishedTransitions[transition] = idleScene
+
+ // Finish all linked transitions.
+ finishActiveTransitionLinks(idleScene)
+
+ // Keep a reference to the idle scene of the last removed transition, in case we remove all
+ // transitions and should settle to Idle.
+ var lastRemovedIdleScene: SceneKey? = null
+
+ // Remove all first n finished transitions.
+ while (transitionStates.isNotEmpty()) {
+ val firstTransition = transitionStates[0]
+ if (!finishedTransitions.contains(firstTransition)) {
+ // Stop here.
+ break
+ }
+
+ // Remove the transition from the list and from the set of finished transitions.
+ transitionStates.removeAt(0)
+ lastRemovedIdleScene = finishedTransitions.remove(firstTransition)
+ }
+
+ // If all transitions are finished, we are idle.
+ if (transitionStates.isEmpty()) {
+ check(finishedTransitions.isEmpty())
+ transitionStates.add(TransitionState.Idle(checkNotNull(lastRemovedIdleScene)))
}
}
- private fun resolveActiveTransitionLinks(idleScene: SceneKey) {
+ private fun finishActiveTransitionLinks(idleScene: SceneKey) {
val previousTransition = this.transitionState as? TransitionState.Transition ?: return
for ((link, linkedTransition) in activeTransitionLinks) {
if (previousTransition.fromScene == idleScene) {
@@ -406,20 +579,39 @@
* Check if a transition is in progress. If the progress value is near 0 or 1, immediately snap
* to the closest scene.
*
+ * Important: Snapping to the closest scene will instantly finish *all* ongoing transitions,
+ * only the progress of the last transition will be checked.
+ *
* @return true if snapped to the closest scene.
*/
internal fun snapToIdleIfClose(threshold: Float): Boolean {
val transition = currentTransition ?: return false
val progress = transition.progress
+
fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
+ fun finishAllTransitions(lastTransitionIdleScene: SceneKey) {
+ // Force finish all transitions.
+ while (currentTransitions.isNotEmpty()) {
+ val transition = transitionStates[0] as TransitionState.Transition
+ val idleScene =
+ if (transitionStates.size == 1) {
+ lastTransitionIdleScene
+ } else {
+ transition.currentScene
+ }
+
+ finishTransition(transition, idleScene)
+ }
+ }
+
return when {
isProgressCloseTo(0f) -> {
- finishTransition(transition, transition.fromScene)
+ finishAllTransitions(transition.fromScene)
true
}
isProgressCloseTo(1f) -> {
- finishTransition(transition, transition.toScene)
+ finishAllTransitions(transition.toScene)
true
}
else -> false
@@ -437,7 +629,8 @@
private var changeScene: (SceneKey) -> Unit,
private var canChangeScene: (SceneKey) -> Boolean,
stateLinks: List<StateLink> = emptyList(),
-) : BaseSceneTransitionLayoutState(initialScene, stateLinks) {
+ enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
+) : BaseSceneTransitionLayoutState(initialScene, stateLinks, enableInterruptions) {
private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED)
override fun canChangeScene(scene: SceneKey): Boolean = canChangeScene.invoke(scene)
@@ -451,12 +644,14 @@
canChangeScene: (SceneKey) -> Boolean,
transitions: SceneTransitions,
stateLinks: List<StateLink>,
+ enableInterruptions: Boolean,
) {
SideEffect {
this.changeScene = onChangeScene
this.canChangeScene = canChangeScene
this.transitions = transitions
this.stateLinks = stateLinks
+ this.enableInterruptions = enableInterruptions
targetSceneChannel.trySend(currentScene)
}
@@ -482,7 +677,10 @@
override var transitions: SceneTransitions,
private val canChangeScene: (SceneKey) -> Boolean = { true },
stateLinks: List<StateLink> = emptyList(),
-) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene, stateLinks) {
+ enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
+) :
+ MutableSceneTransitionLayoutState,
+ BaseSceneTransitionLayoutState(initialScene, stateLinks, enableInterruptions) {
override fun setTargetScene(
targetScene: SceneKey,
coroutineScope: CoroutineScope,
@@ -501,3 +699,15 @@
setTargetScene(scene, coroutineScope = this)
}
}
+
+private const val TAG = "SceneTransitionLayoutState"
+
+/** Whether support for interruptions in enabled by default. */
+internal const val DEFAULT_INTERRUPTIONS_ENABLED = true
+
+/**
+ * The max number of concurrent transitions. If the number of transitions goes past this number,
+ * this probably means that there is a leak and we will Log.wtf before clearing the list of
+ * transitions.
+ */
+private const val MAX_CONCURRENT_TRANSITIONS = 100
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
index 228d19f..b7abb33 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
@@ -19,15 +19,9 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
-internal class UserActionDistanceScopeImpl(
+internal class ElementStateScopeImpl(
private val layoutImpl: SceneTransitionLayoutImpl,
-) : UserActionDistanceScope {
- override val density: Float
- get() = layoutImpl.density.density
-
- override val fontScale: Float
- get() = layoutImpl.density.fontScale
-
+) : ElementStateScope {
override fun ElementKey.targetSize(scene: SceneKey): IntSize? {
return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetSize.takeIf {
it != Element.SizeUnspecified
@@ -44,3 +38,13 @@
return layoutImpl.scenes[this]?.targetSize.takeIf { it != IntSize.Zero }
}
}
+
+internal class UserActionDistanceScopeImpl(
+ private val layoutImpl: SceneTransitionLayoutImpl,
+) : UserActionDistanceScope, ElementStateScope by layoutImpl.elementStateScope {
+ override val density: Float
+ get() = layoutImpl.density.density
+
+ override val fontScale: Float
+ get() = layoutImpl.density.fontScale
+}
diff --git a/packages/SystemUI/compose/scene/tests/Android.bp b/packages/SystemUI/compose/scene/tests/Android.bp
index 59cc63a..af13896 100644
--- a/packages/SystemUI/compose/scene/tests/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/Android.bp
@@ -26,7 +26,6 @@
name: "PlatformComposeSceneTransitionLayoutTests",
manifest: "AndroidManifest.xml",
test_suites: ["device-tests"],
- sdk_version: "current",
certificate: "platform",
srcs: [
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 1e9a7e2..2ed51eb 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -984,14 +984,14 @@
val scene = layoutState.transitionState.currentScene
// We should have overscroll spec for scene C
assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull()
- assertThat(layoutState.currentOverscrollSpec).isNull()
+ assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNull()
val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
// We scrolled down, under scene C there is nothing, so we can use the overscroll spec
- assertThat(layoutState.currentOverscrollSpec).isNotNull()
- assertThat(layoutState.currentOverscrollSpec?.scene).isEqualTo(SceneC)
+ assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(layoutState.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneC)
val transition = layoutState.currentTransition
assertThat(transition).isNotNull()
assertThat(transition!!.progress).isEqualTo(-0.1f)
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 597da9e..2453e25 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
@@ -595,7 +595,7 @@
}
assertThat(state.currentTransition).isNull()
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// Swipe by half of verticalSwipeDistance.
rule.onRoot().performTouchInput {
@@ -643,7 +643,7 @@
// Scroll 150% (Scene B overscroll by 50%)
assertThat(transition.progress).isEqualTo(1.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
// animatedFloat cannot overflow (canOverflow = false)
assertThat(animatedFloat).isEqualTo(100f)
@@ -655,7 +655,7 @@
// Scroll 250% (Scene B overscroll by 150%)
assertThat(transition.progress).isEqualTo(2.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
assertThat(animatedFloat).isEqualTo(100f)
}
@@ -707,7 +707,7 @@
}
assertThat(state.currentTransition).isNull()
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
@@ -720,7 +720,7 @@
}
val transition = state.currentTransition
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
assertThat(transition).isNotNull()
assertThat(transition!!.progress).isEqualTo(-0.5f)
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
@@ -732,7 +732,7 @@
// Scroll 150% (Scene B overscroll by 50%)
assertThat(transition.progress).isEqualTo(-1.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
}
@@ -771,7 +771,7 @@
// Scroll 150% (100% scroll + 50% overscroll)
assertThat(transition!!.progress).isEqualTo(1.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f)
assertThat(animatedFloat).isEqualTo(100f)
@@ -782,7 +782,7 @@
// Scroll 250% (100% scroll + 150% overscroll)
assertThat(transition.progress).isEqualTo(2.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 1.5f)
assertThat(animatedFloat).isEqualTo(100f)
}
@@ -828,7 +828,7 @@
// Scroll 150% (100% scroll + 50% overscroll)
assertThat(transition.progress).isEqualTo(1.5f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * (transition.progress - 1f))
assertThat(animatedFloat).isEqualTo(100f)
@@ -840,7 +840,7 @@
rule.waitUntil(timeoutMillis = 10_000) { transition.progress < 1f }
assertThat(transition.progress).isLessThan(1f)
- assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
assertThat(transition.bouncingScene).isEqualTo(transition.toScene)
assertThat(animatedFloat).isEqualTo(100f)
}
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 9baabc3..93e94f8 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
@@ -16,6 +16,7 @@
package com.android.compose.animation.scene
+import android.util.Log
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.test.junit4.createComposeRule
@@ -28,9 +29,12 @@
import com.android.compose.test.runMonotonicClockTest
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
-import kotlinx.coroutines.job
import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -271,11 +275,21 @@
}
@Test
- fun linkedTransition_startsLinkButLinkedStateIsTakenOver() {
+ fun linkedTransition_startsLinkButLinkedStateIsTakenOver() = runTest {
val (parentState, childState) = setupLinkedStates()
- val childTransition = transition(SceneA, SceneB)
- val parentTransition = transition(SceneC, SceneA)
+ val childTransition =
+ transition(
+ SceneA,
+ SceneB,
+ onFinish = { launch { /* Do nothing. */} },
+ )
+ val parentTransition =
+ transition(
+ SceneC,
+ SceneA,
+ onFinish = { launch { /* Do nothing. */} },
+ )
childState.startTransition(childTransition, null)
parentState.startTransition(parentTransition, null)
@@ -303,7 +317,7 @@
// Default transition from A to B.
assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
- assertThat(state.transformationSpec.transformations).hasSize(1)
+ assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
// Go back to A.
state.setTargetScene(SceneA, coroutineScope = this)
@@ -320,14 +334,14 @@
)
)
.isNotNull()
- assertThat(state.transformationSpec.transformations).hasSize(2)
+ assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
}
@Test
fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
state.startTransition(
- transition(from = SceneA, to = TestScenes.SceneB, progress = { 0.2f }),
+ transition(from = SceneA, to = SceneB, progress = { 0.2f }),
transitionKey = null
)
assertThat(state.isTransitioning()).isTrue()
@@ -346,7 +360,7 @@
fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
state.startTransition(
- transition(from = SceneA, to = TestScenes.SceneB, progress = { 0.8f }),
+ transition(from = SceneA, to = SceneB, progress = { 0.8f }),
transitionKey = null
)
assertThat(state.isTransitioning()).isTrue()
@@ -358,7 +372,35 @@
// Go to the final scene if it is close to 1.
assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
assertThat(state.isTransitioning()).isFalse()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+ }
+
+ @Test
+ fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+
+ val aToB =
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { 0.5f },
+ onFinish = { launch { /* do nothing */} },
+ )
+ state.startTransition(aToB, transitionKey = null)
+ assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
+
+ val bToC = transition(from = SceneB, to = SceneC, progress = { 0.8f })
+ state.startTransition(bToC, transitionKey = null)
+ assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+ // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+ // Go to the final scene if it is close to 1.
+ assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+ assertThat(state.currentTransitions).isEmpty()
}
@Test
@@ -435,23 +477,23 @@
overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) }
}
)
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneA is NOT defined
progress.value = -0.1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
progress.value = 1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneB is defined
progress.value = 1.1f
- assertThat(state.currentOverscrollSpec).isNotNull()
- assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneB)
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneB)
}
@Test
@@ -465,23 +507,23 @@
overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
}
)
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneA is defined
progress.value = -0.1f
- assertThat(state.currentOverscrollSpec).isNotNull()
- assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneA)
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneA)
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
progress.value = 1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneB is NOT defined
progress.value = 1.1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
}
@Test
@@ -492,21 +534,99 @@
progress = { progress.value },
sceneTransitions = transitions {}
)
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneA is NOT defined
progress.value = -0.1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// scroll from SceneA to SceneB
progress.value = 0.5f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
progress.value = 1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
// overscroll for SceneB is NOT defined
progress.value = 1.1f
- assertThat(state.currentOverscrollSpec).isNull()
+ assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+ }
+
+ @Test
+ fun multipleTransitions() = runTest {
+ val finishingTransitions = mutableSetOf<TransitionState.Transition>()
+ fun onFinish(transition: TransitionState.Transition): Job {
+ // Instead of letting the transition finish, we put the transition in the
+ // finishingTransitions set so that we can verify that finish() is called when expected
+ // and then we call state STLState.finishTransition() ourselves.
+ finishingTransitions.add(transition)
+
+ return backgroundScope.launch {
+ // Try to acquire a locked mutex so that this code never completes.
+ Mutex(locked = true).withLock {}
+ }
+ }
+
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
+ val aToB = transition(SceneA, SceneB, onFinish = ::onFinish)
+ val bToC = transition(SceneB, SceneC, onFinish = ::onFinish)
+ val cToA = transition(SceneC, SceneA, onFinish = ::onFinish)
+
+ // Starting state.
+ assertThat(finishingTransitions).isEmpty()
+ assertThat(state.currentTransitions).isEmpty()
+
+ // A => B.
+ state.startTransition(aToB, transitionKey = null)
+ assertThat(finishingTransitions).isEmpty()
+ assertThat(state.finishedTransitions).isEmpty()
+ assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
+
+ // B => C. This should automatically call finish() on aToB.
+ state.startTransition(bToC, transitionKey = null)
+ assertThat(finishingTransitions).containsExactly(aToB)
+ assertThat(state.finishedTransitions).isEmpty()
+ assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+ // C => A. This should automatically call finish() on bToC.
+ state.startTransition(cToA, transitionKey = null)
+ assertThat(finishingTransitions).containsExactly(aToB, bToC)
+ assertThat(state.finishedTransitions).isEmpty()
+ assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
+
+ // Mark bToC as finished. The list of current transitions does not change because aToB is
+ // still not marked as finished.
+ state.finishTransition(bToC, idleScene = bToC.currentScene)
+ assertThat(state.finishedTransitions).containsExactly(bToC, bToC.currentScene)
+ assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
+
+ // Mark aToB as finished. This will remove both aToB and bToC from the list of transitions.
+ state.finishTransition(aToB, idleScene = aToB.currentScene)
+ assertThat(state.finishedTransitions).isEmpty()
+ assertThat(state.currentTransitions).containsExactly(cToA).inOrder()
+ }
+
+ @Test
+ fun tooManyTransitionsLogsWtfAndClearsTransitions() = runTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
+
+ fun startTransition() {
+ val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */} })
+ state.startTransition(transition, transitionKey = null)
+ }
+
+ var hasLoggedWtf = false
+ val originalHandler = Log.setWtfHandler { _, _, _ -> hasLoggedWtf = true }
+ try {
+ repeat(100) { startTransition() }
+ assertThat(hasLoggedWtf).isFalse()
+ assertThat(state.currentTransitions).hasSize(100)
+
+ startTransition()
+ assertThat(hasLoggedWtf).isTrue()
+ assertThat(state.currentTransitions).hasSize(1)
+ } finally {
+ Log.setWtfHandler(originalHandler)
+ }
}
}
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 efaea71..723a182 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
@@ -299,6 +299,11 @@
.isWithin(DpOffsetSubject.DefaultTolerance)
.of(DpOffset(expectedOffset, expectedOffset))
+ // Wait for the transition to C to finish.
+ rule.mainClock.advanceTimeBy(TestTransitionDuration)
+ assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
+ assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+
// Go back to scene A. This should happen instantly (once the animation started, i.e. after
// 2 frames) given that we use a snap() animation spec.
currentScene = TestScenes.SceneA
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 99372a5..f034c18 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -547,12 +547,12 @@
}
assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
- assertThat(state.transformationSpec.transformations).hasSize(1)
+ assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
// Move the pointer up to swipe to scene B using the new transition.
rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
- assertThat(state.transformationSpec.transformations).hasSize(2)
+ assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
}
@Test
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
index a32fe22..767057b 100644
--- 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
@@ -29,6 +29,7 @@
isUpOrLeft: Boolean = false,
bouncingScene: SceneKey? = null,
orientation: Orientation = Orientation.Horizontal,
+ onFinish: ((TransitionState.Transition) -> Job)? = null,
): TransitionState.Transition {
return object : TransitionState.Transition(from, to), TransitionState.HasOverscrollProperties {
override val currentScene: SceneKey = from
@@ -46,7 +47,13 @@
}
override fun finish(): Job {
- error("finish() is not supported in test transitions")
+ val onFinish =
+ onFinish
+ ?: error(
+ "onFinish() must be provided if finish() is called on test transitions"
+ )
+
+ return onFinish(this)
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 343280d..289896e01 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -444,6 +444,17 @@
AdditionalMatchers.aryEq(credentialAttestation));
}
+ @Test
+ public void testSendsReasonContentViewMoreOptions_whenButtonPressed() throws Exception {
+ showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
+ mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS,
+ null, /* credentialAttestation */
+ mAuthController.mCurrentDialog.getRequestId());
+ verify(mReceiver).onDialogDismissed(
+ eq(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS),
+ eq(null) /* credentialAttestation */);
+ }
+
// Statusbar tests
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 707777b..b0d03b1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -71,34 +71,6 @@
}
@Test
- fun pinAuthMethod() =
- testScope.runTest {
- val message by collectLastValue(underTest.message)
-
- kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin
- )
- runCurrent()
- underTest.clearMessage()
- assertThat(message).isNull()
-
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
-
- // Wrong input.
- assertThat(underTest.authenticate(listOf(9, 8, 7)))
- .isEqualTo(AuthenticationResult.FAILED)
- assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
-
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
-
- // Correct input.
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
- .isEqualTo(AuthenticationResult.SUCCEEDED)
- }
-
- @Test
fun pinAuthMethod_sim_skipsAuthentication() =
testScope.runTest {
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
@@ -146,8 +118,6 @@
@Test
fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
testScope.runTest {
- val message by collectLastValue(underTest.message)
-
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin
)
@@ -156,7 +126,6 @@
// Incomplete input.
assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true))
.isEqualTo(AuthenticationResult.SKIPPED)
- assertThat(message).isNull()
// Correct input.
assertThat(
@@ -166,28 +135,19 @@
)
)
.isEqualTo(AuthenticationResult.SKIPPED)
- assertThat(message).isNull()
}
@Test
fun passwordAuthMethod() =
testScope.runTest {
- val message by collectLastValue(underTest.message)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
runCurrent()
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
-
// Wrong input.
assertThat(underTest.authenticate("alohamora".toList()))
.isEqualTo(AuthenticationResult.FAILED)
- assertThat(message).isEqualTo(MESSAGE_WRONG_PASSWORD)
-
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
// Too short input.
assertThat(
@@ -201,7 +161,6 @@
)
)
.isEqualTo(AuthenticationResult.SKIPPED)
- assertThat(message).isEqualTo(MESSAGE_WRONG_PASSWORD)
// Correct input.
assertThat(underTest.authenticate("password".toList()))
@@ -211,13 +170,10 @@
@Test
fun patternAuthMethod() =
testScope.runTest {
- val message by collectLastValue(underTest.message)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
runCurrent()
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Wrong input.
val wrongPattern =
@@ -231,10 +187,6 @@
assertThat(wrongPattern.size)
.isAtLeast(kosmos.fakeAuthenticationRepository.minPatternLength)
assertThat(underTest.authenticate(wrongPattern)).isEqualTo(AuthenticationResult.FAILED)
- assertThat(message).isEqualTo(MESSAGE_WRONG_PATTERN)
-
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Too short input.
val tooShortPattern =
@@ -244,10 +196,6 @@
)
assertThat(underTest.authenticate(tooShortPattern))
.isEqualTo(AuthenticationResult.SKIPPED)
- assertThat(message).isEqualTo(MESSAGE_WRONG_PATTERN)
-
- underTest.resetMessage()
- assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Correct input.
assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN))
@@ -258,7 +206,6 @@
fun lockoutStarted() =
testScope.runTest {
val lockoutStartedEvents by collectValues(underTest.onLockoutStarted)
- val message by collectLastValue(underTest.message)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin
@@ -272,17 +219,14 @@
.isEqualTo(AuthenticationResult.FAILED)
if (times < FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT - 1) {
assertThat(lockoutStartedEvents).isEmpty()
- assertThat(message).isNotEmpty()
}
}
assertThat(authenticationInteractor.lockoutEndTimestamp).isNotNull()
assertThat(lockoutStartedEvents.size).isEqualTo(1)
- assertThat(message).isNull()
// Advance the time to finish the lockout:
advanceTimeBy(FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS.seconds)
assertThat(authenticationInteractor.lockoutEndTimestamp).isNull()
- assertThat(message).isNull()
assertThat(lockoutStartedEvents.size).isEqualTo(1)
// Trigger lockout again:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index 701b703..c878e0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.bouncer.domain.interactor
import android.content.pm.UserInfo
-import android.os.Handler
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,27 +27,25 @@
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
+import com.android.systemui.biometrics.data.repository.fakeFacePropertyRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
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.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.keyguard.shared.model.AuthenticationFlags
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
import com.android.systemui.res.R.string.kg_trust_agent_disabled
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -61,7 +58,6 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
-import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -70,34 +66,22 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4::class)
class BouncerMessageInteractorTest : SysuiTestCase() {
-
+ private val kosmos = testKosmos()
private val countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
private val repository = BouncerMessageRepositoryImpl()
- private val userRepository = FakeUserRepository()
- private val fakeTrustRepository = FakeTrustRepository()
- private val fakeFacePropertyRepository = FakeFacePropertyRepository()
- private val bouncerRepository = FakeKeyguardBouncerRepository()
- private val fakeDeviceEntryFingerprintAuthRepository =
- FakeDeviceEntryFingerprintAuthRepository()
- private val fakeDeviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- private val biometricSettingsRepository: FakeBiometricSettingsRepository =
- FakeBiometricSettingsRepository()
+ private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
+ private val testScope = kosmos.testScope
@Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var securityModel: KeyguardSecurityModel
@Mock private lateinit var countDownTimerUtil: CountDownTimerUtil
@Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
- private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
- private lateinit var testScope: TestScope
private lateinit var underTest: BouncerMessageInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- userRepository.setUserInfos(listOf(PRIMARY_USER))
- testScope = TestScope()
+ kosmos.fakeUserRepository.setUserInfos(listOf(PRIMARY_USER))
allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
@@ -105,44 +89,28 @@
}
suspend fun TestScope.init() {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES)
- primaryBouncerInteractor =
- PrimaryBouncerInteractor(
- bouncerRepository,
- mock(BouncerView::class.java),
- mock(Handler::class.java),
- mock(KeyguardStateController::class.java),
- mock(KeyguardSecurityModel::class.java),
- mock(PrimaryBouncerCallbackInteractor::class.java),
- mock(FalsingCollector::class.java),
- mock(DismissCallbackRegistry::class.java),
- context,
- keyguardUpdateMonitor,
- fakeTrustRepository,
- testScope.backgroundScope,
- mSelectedUserInteractor,
- mock(DeviceEntryFaceAuthInteractor::class.java),
- )
underTest =
BouncerMessageInteractor(
repository = repository,
- userRepository = userRepository,
+ userRepository = kosmos.fakeUserRepository,
countDownTimerUtil = countDownTimerUtil,
updateMonitor = updateMonitor,
biometricSettingsRepository = biometricSettingsRepository,
- applicationScope = this.backgroundScope,
- trustRepository = fakeTrustRepository,
+ applicationScope = testScope.backgroundScope,
+ trustRepository = kosmos.fakeTrustRepository,
systemPropertiesHelper = systemPropertiesHelper,
- primaryBouncerInteractor = primaryBouncerInteractor,
- facePropertyRepository = fakeFacePropertyRepository,
- deviceEntryFingerprintAuthRepository = fakeDeviceEntryFingerprintAuthRepository,
- faceAuthRepository = fakeDeviceEntryFaceAuthRepository,
+ primaryBouncerInteractor = kosmos.primaryBouncerInteractor,
+ facePropertyRepository = kosmos.fakeFacePropertyRepository,
+ deviceEntryFingerprintAuthInteractor = kosmos.deviceEntryFingerprintAuthInteractor,
+ faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository,
securityModel = securityModel
)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
- fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
- bouncerRepository.setPrimaryShow(true)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+ kosmos.fakeKeyguardBouncerRepository.setPrimaryShow(true)
runCurrent()
}
@@ -268,7 +236,7 @@
init()
val lockoutMessage by collectLastValue(underTest.bouncerMessage)
- fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
runCurrent()
assertThat(primaryResMessage(lockoutMessage))
@@ -276,7 +244,7 @@
assertThat(secondaryResMessage(lockoutMessage))
.isEqualTo("Can’t unlock with face. Too many attempts.")
- fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
runCurrent()
assertThat(primaryResMessage(lockoutMessage))
@@ -289,15 +257,17 @@
testScope.runTest {
init()
val lockoutMessage by collectLastValue(underTest.bouncerMessage)
- fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
- fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(
+ FaceSensorInfo(1, SensorStrength.STRONG)
+ )
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
runCurrent()
assertThat(primaryResMessage(lockoutMessage)).isEqualTo("Enter PIN")
assertThat(secondaryResMessage(lockoutMessage))
.isEqualTo("PIN is required after too many attempts")
- fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
runCurrent()
assertThat(primaryResMessage(lockoutMessage))
@@ -311,14 +281,14 @@
init()
val lockedOutMessage by collectLastValue(underTest.bouncerMessage)
- fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
runCurrent()
assertThat(primaryResMessage(lockedOutMessage)).isEqualTo("Enter PIN")
assertThat(secondaryResMessage(lockedOutMessage))
.isEqualTo("PIN is required after too many attempts")
- fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
runCurrent()
assertThat(primaryResMessage(lockedOutMessage))
@@ -327,6 +297,19 @@
}
@Test
+ fun onUdfpsFingerprint_DoesNotShowFingerprintMessage() =
+ testScope.runTest {
+ init()
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ kosmos.fakeFingerprintPropertyRepository.supportsUdfps()
+ val lockedOutMessage by collectLastValue(underTest.bouncerMessage)
+
+ runCurrent()
+
+ assertThat(primaryResMessage(lockedOutMessage)).isEqualTo("Enter PIN")
+ }
+
+ @Test
fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
testScope.runTest {
init()
@@ -344,9 +327,10 @@
fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
testScope.runTest {
init()
- fakeTrustRepository.setTrustUsuallyManaged(false)
+ kosmos.fakeTrustRepository.setTrustUsuallyManaged(false)
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ runCurrent()
val defaultMessage = Pair("Enter PIN", null)
@@ -377,12 +361,13 @@
testScope.runTest {
init()
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ runCurrent()
- fakeTrustRepository.setCurrentUserTrustManaged(true)
- fakeTrustRepository.setTrustUsuallyManaged(true)
+ kosmos.fakeTrustRepository.setCurrentUserTrustManaged(true)
+ kosmos.fakeTrustRepository.setTrustUsuallyManaged(true)
val defaultMessage = Pair("Enter PIN", null)
@@ -415,8 +400,8 @@
fun authFlagsChanges_withFaceEnrolled_providesDifferentMessages() =
testScope.runTest {
init()
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- fakeTrustRepository.setTrustUsuallyManaged(false)
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeTrustRepository.setTrustUsuallyManaged(false)
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
@@ -453,12 +438,13 @@
fun authFlagsChanges_withFingerprintEnrolled_providesDifferentMessages() =
testScope.runTest {
init()
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- fakeTrustRepository.setCurrentUserTrustManaged(false)
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeTrustRepository.setCurrentUserTrustManaged(false)
biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ runCurrent()
verifyMessagesForAuthFlag(
LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to
@@ -466,6 +452,7 @@
)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
+ runCurrent()
verifyMessagesForAuthFlag(
LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index d30e333..c9fa671 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -48,6 +48,7 @@
isInputEnabled = MutableStateFlow(true),
simBouncerInteractor = kosmos.simBouncerInteractor,
authenticationMethod = AuthenticationMethodModel.Pin,
+ onIntentionalUserInput = {},
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt
new file mode 100644
index 0000000..16ec9aa
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelTest.kt
@@ -0,0 +1,455 @@
+/*
+ * 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.bouncer.ui.viewmodel
+
+import android.content.pm.UserInfo
+import android.hardware.biometrics.BiometricFaceConstants
+import android.hardware.fingerprint.FingerprintManager
+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.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
+import com.android.systemui.biometrics.data.repository.fakeFacePropertyRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
+import com.android.systemui.bouncer.shared.flag.fakeComposeBouncerFlags
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStatus
+import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
+import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
+import com.android.systemui.flags.fakeSystemPropertiesHelper
+import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeTrustRepository
+import com.android.systemui.keyguard.shared.model.AuthenticationFlags
+import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
+import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.currentTime
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BouncerMessageViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
+ private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
+ private lateinit var underTest: BouncerMessageViewModel
+
+ @Before
+ fun setUp() {
+ kosmos.fakeUserRepository.setUserInfos(listOf(PRIMARY_USER))
+ kosmos.fakeComposeBouncerFlags.composeBouncerEnabled = true
+ underTest = kosmos.bouncerMessageViewModel
+ overrideResource(R.string.kg_trust_agent_disabled, "Trust agent is unavailable")
+ kosmos.fakeSystemPropertiesHelper.set(
+ DeviceEntryInteractor.SYS_BOOT_REASON_PROP,
+ "not mainline reboot"
+ )
+ }
+
+ @Test
+ fun message_defaultMessage_basedOnAuthMethod() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ runCurrent()
+
+ assertThat(message!!.text).isEqualTo("Unlock with PIN or fingerprint")
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pattern)
+ runCurrent()
+ assertThat(message!!.text).isEqualTo("Unlock with pattern or fingerprint")
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password
+ )
+ runCurrent()
+ assertThat(message!!.text).isEqualTo("Unlock with password or fingerprint")
+ }
+
+ @Test
+ fun message() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
+ assertThat(message?.isUpdateAnimated).isTrue()
+
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) {
+ bouncerInteractor.authenticate(WRONG_PIN)
+ }
+ assertThat(message?.isUpdateAnimated).isFalse()
+
+ val lockoutEndMs = authenticationInteractor.lockoutEndTimestamp ?: 0
+ advanceTimeBy(lockoutEndMs - testScope.currentTime)
+ assertThat(message?.isUpdateAnimated).isTrue()
+ }
+
+ @Test
+ fun lockoutMessage() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
+ assertThat(kosmos.fakeAuthenticationRepository.lockoutEndTimestamp).isNull()
+ runCurrent()
+
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) { times ->
+ bouncerInteractor.authenticate(WRONG_PIN)
+ runCurrent()
+ if (times < FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT - 1) {
+ assertThat(message?.text).isEqualTo("Wrong PIN. Try again.")
+ assertThat(message?.isUpdateAnimated).isTrue()
+ }
+ }
+ val lockoutSeconds = FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS
+ assertTryAgainMessage(message?.text, lockoutSeconds)
+ assertThat(message?.isUpdateAnimated).isFalse()
+
+ repeat(FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS) { time ->
+ advanceTimeBy(1.seconds)
+ val remainingSeconds = lockoutSeconds - time - 1
+ if (remainingSeconds > 0) {
+ assertTryAgainMessage(message?.text, remainingSeconds)
+ }
+ }
+ assertThat(message?.text).isEqualTo("Enter PIN")
+ assertThat(message?.isUpdateAnimated).isTrue()
+ }
+
+ @Test
+ fun defaultMessage_mapsToDeviceEntryRestrictionReason_whenTrustAgentIsEnabled() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ kosmos.fakeTrustRepository.setTrustUsuallyManaged(true)
+ kosmos.fakeTrustRepository.setCurrentUserTrustManaged(false)
+ runCurrent()
+
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlags(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "PIN required for additional security"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun defaultMessage_mapsToDeviceEntryRestrictionReason_whenFingerprintIsAvailable() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ kosmos.fakeTrustRepository.setCurrentUserTrustManaged(false)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ runCurrent()
+
+ verifyMessagesForAuthFlags(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to
+ Pair("Unlock with PIN or fingerprint", null),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Unlock with PIN or fingerprint", null),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Unlock with PIN or fingerprint", null),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "PIN required for additional security"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Unlock with PIN or fingerprint",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun onFingerprintLockout_messageUpdated() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ val lockedOutMessage by collectLastValue(underTest.message)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(lockedOutMessage?.text).isEqualTo("Enter PIN")
+ assertThat(lockedOutMessage?.secondaryText)
+ .isEqualTo("PIN is required after too many attempts")
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(lockedOutMessage?.text).isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockedOutMessage?.secondaryText.isNullOrBlank()).isTrue()
+ }
+
+ @Test
+ fun onUdfpsFingerprint_DoesNotShowFingerprintMessage() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeFingerprintPropertyRepository.supportsUdfps()
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ val message by collectLastValue(underTest.message)
+
+ runCurrent()
+
+ assertThat(message?.text).isEqualTo("Enter PIN")
+ }
+
+ @Test
+ fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeSystemPropertiesHelper.set("sys.boot.reason.last", "reboot,mainline_update")
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ runCurrent()
+
+ verifyMessagesForAuthFlags(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "Device updated. Enter PIN to continue.")
+ )
+ }
+
+ @Test
+ fun onFaceLockout_whenItIsClass3_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ val lockoutMessage by collectLastValue(underTest.message)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(
+ FaceSensorInfo(1, SensorStrength.STRONG)
+ )
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(lockoutMessage?.text).isEqualTo("Enter PIN")
+ assertThat(lockoutMessage?.secondaryText)
+ .isEqualTo("PIN is required after too many attempts")
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(lockoutMessage?.text).isEqualTo("Enter PIN")
+ assertThat(lockoutMessage?.secondaryText.isNullOrBlank()).isTrue()
+ }
+
+ @Test
+ fun onFaceLockout_whenItIsNotStrong_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ val lockoutMessage by collectLastValue(underTest.message)
+ kosmos.fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.WEAK))
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(lockoutMessage?.text).isEqualTo("Enter PIN")
+ assertThat(lockoutMessage?.secondaryText)
+ .isEqualTo("Can’t unlock with face. Too many attempts.")
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(lockoutMessage?.text).isEqualTo("Enter PIN")
+ assertThat(lockoutMessage?.secondaryText.isNullOrBlank()).isTrue()
+ }
+
+ @Test
+ fun setFingerprintMessage_propagateValue() =
+ testScope.runTest {
+ val bouncerMessage by collectLastValue(underTest.message)
+
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ kosmos.fakeFingerprintPropertyRepository.supportsSideFps()
+ runCurrent()
+
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ HelpFingerprintAuthenticationStatus(1, "some helpful message")
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryText).isEqualTo("some helpful message")
+
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ FailFingerprintAuthenticationStatus
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Fingerprint not recognized")
+ assertThat(bouncerMessage?.secondaryText).isEqualTo("Try again or enter PIN")
+
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ ErrorFingerprintAuthenticationStatus(
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT,
+ "locked out"
+ )
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Enter PIN")
+ assertThat(bouncerMessage?.secondaryText)
+ .isEqualTo("PIN is required after too many attempts")
+ }
+
+ @Test
+ fun setFaceMessage_propagateValue() =
+ testScope.runTest {
+ val bouncerMessage by collectLastValue(underTest.message)
+
+ kosmos.fakeUserRepository.setSelectedUserInfo(PRIMARY_USER)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ kosmos.fakeBiometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
+ runCurrent()
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
+ HelpFaceAuthenticationStatus(1, "some helpful message")
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Enter PIN")
+ assertThat(bouncerMessage?.secondaryText).isEqualTo("some helpful message")
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
+ ErrorFaceAuthenticationStatus(
+ BiometricFaceConstants.FACE_ERROR_TIMEOUT,
+ "Try again"
+ )
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Enter PIN")
+ assertThat(bouncerMessage?.secondaryText).isEqualTo("Try again")
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
+ FailedFaceAuthenticationStatus()
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Face not recognized")
+ assertThat(bouncerMessage?.secondaryText).isEqualTo("Try again or enter PIN")
+
+ kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
+ ErrorFaceAuthenticationStatus(
+ BiometricFaceConstants.FACE_ERROR_LOCKOUT,
+ "locked out"
+ )
+ )
+ runCurrent()
+ assertThat(bouncerMessage?.text).isEqualTo("Enter PIN")
+ assertThat(bouncerMessage?.secondaryText)
+ .isEqualTo("Can’t unlock with face. Too many attempts.")
+ }
+
+ private fun TestScope.verifyMessagesForAuthFlags(
+ vararg authFlagToMessagePair: Pair<Int, Pair<String, String?>>
+ ) {
+ val actualMessage by collectLastValue(underTest.message)
+
+ authFlagToMessagePair.forEach { (flag, expectedMessagePair) ->
+ kosmos.fakeBiometricSettingsRepository.setAuthenticationFlags(
+ AuthenticationFlags(userId = PRIMARY_USER_ID, flag = flag)
+ )
+ runCurrent()
+
+ assertThat(actualMessage?.text).isEqualTo(expectedMessagePair.first)
+
+ if (expectedMessagePair.second == null) {
+ assertThat(actualMessage?.secondaryText.isNullOrBlank()).isTrue()
+ } else {
+ assertThat(actualMessage?.secondaryText).isEqualTo(expectedMessagePair.second)
+ }
+ }
+ }
+
+ private fun assertTryAgainMessage(
+ message: String?,
+ time: Int,
+ ) {
+ assertThat(message).contains("Try again in $time second")
+ }
+
+ companion object {
+ private val WRONG_PIN = FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 }
+ private const val PRIMARY_USER_ID = 0
+ private val PRIMARY_USER =
+ UserInfo(
+ /* id= */ PRIMARY_USER_ID,
+ /* name= */ "primary user",
+ /* flags= */ UserInfo.FLAG_PRIMARY
+ )
+ }
+}
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 73db175..3afca96 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
@@ -37,7 +37,6 @@
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
@@ -142,54 +141,6 @@
}
@Test
- fun message() =
- testScope.runTest {
- val message by collectLastValue(underTest.message)
- kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
- assertThat(message?.isUpdateAnimated).isTrue()
-
- repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) {
- bouncerInteractor.authenticate(WRONG_PIN)
- }
- assertThat(message?.isUpdateAnimated).isFalse()
-
- val lockoutEndMs = authenticationInteractor.lockoutEndTimestamp ?: 0
- advanceTimeBy(lockoutEndMs - testScope.currentTime)
- assertThat(message?.isUpdateAnimated).isTrue()
- }
-
- @Test
- fun lockoutMessage() =
- testScope.runTest {
- val authMethodViewModel by collectLastValue(underTest.authMethodViewModel)
- val message by collectLastValue(underTest.message)
- kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
- assertThat(kosmos.fakeAuthenticationRepository.lockoutEndTimestamp).isNull()
- assertThat(authMethodViewModel?.lockoutMessageId).isNotNull()
-
- repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) { times ->
- bouncerInteractor.authenticate(WRONG_PIN)
- if (times < FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT - 1) {
- assertThat(message?.text).isEqualTo(bouncerInteractor.message.value)
- assertThat(message?.isUpdateAnimated).isTrue()
- }
- }
- val lockoutSeconds = FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS
- assertTryAgainMessage(message?.text, lockoutSeconds)
- assertThat(message?.isUpdateAnimated).isFalse()
-
- repeat(FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS) { time ->
- advanceTimeBy(1.seconds)
- val remainingSeconds = lockoutSeconds - time - 1
- if (remainingSeconds > 0) {
- assertTryAgainMessage(message?.text, remainingSeconds)
- }
- }
- assertThat(message?.text).isEmpty()
- assertThat(message?.isUpdateAnimated).isTrue()
- }
-
- @Test
fun isInputEnabled() =
testScope.runTest {
val isInputEnabled by
@@ -212,25 +163,6 @@
}
@Test
- fun dialogViewModel() =
- testScope.runTest {
- val authMethodViewModel by collectLastValue(underTest.authMethodViewModel)
- val dialogViewModel by collectLastValue(underTest.dialogViewModel)
- kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
- assertThat(authMethodViewModel?.lockoutMessageId).isNotNull()
-
- repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) {
- assertThat(dialogViewModel).isNull()
- bouncerInteractor.authenticate(WRONG_PIN)
- }
- assertThat(dialogViewModel).isNotNull()
- assertThat(dialogViewModel?.text).isNotEmpty()
-
- dialogViewModel?.onDismiss?.invoke()
- assertThat(dialogViewModel).isNull()
- }
-
- @Test
fun isSideBySideSupported() =
testScope.runTest {
val isSideBySideSupported by collectLastValue(underTest.isSideBySideSupported)
@@ -265,13 +197,6 @@
return listOf(None, Pin, Password, Pattern, Sim)
}
- private fun assertTryAgainMessage(
- message: String?,
- time: Int,
- ) {
- assertThat(message).isEqualTo("Try again in $time seconds.")
- }
-
companion object {
private val WRONG_PIN = FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index df50eb6..71c5785 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -66,7 +66,6 @@
private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
private val selectedUserInteractor by lazy { kosmos.selectedUserInteractor }
private val inputMethodInteractor by lazy { kosmos.inputMethodInteractor }
- private val bouncerViewModel by lazy { kosmos.bouncerViewModel }
private val isInputEnabled = MutableStateFlow(true)
private val underTest =
@@ -76,6 +75,7 @@
interactor = bouncerInteractor,
inputMethodInteractor = inputMethodInteractor,
selectedUserInteractor = selectedUserInteractor,
+ onIntentionalUserInput = {},
)
@Before
@@ -88,11 +88,9 @@
fun onShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
lockDeviceAndOpenPasswordBouncer()
- assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
assertThat(password).isEmpty()
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
assertThat(underTest.authenticationMethod).isEqualTo(AuthenticationMethodModel.Password)
@@ -101,16 +99,13 @@
@Test
fun onHidden_resetsPasswordInputAndMessage() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
lockDeviceAndOpenPasswordBouncer()
underTest.onPasswordInputChanged("password")
- assertThat(message?.text).isNotEqualTo(ENTER_YOUR_PASSWORD)
assertThat(password).isNotEmpty()
underTest.onHidden()
- assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
assertThat(password).isEmpty()
}
@@ -118,13 +113,11 @@
fun onPasswordInputChanged() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
lockDeviceAndOpenPasswordBouncer()
underTest.onPasswordInputChanged("password")
- assertThat(message?.text).isEmpty()
assertThat(password).isEqualTo("password")
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
}
@@ -144,7 +137,6 @@
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
lockDeviceAndOpenPasswordBouncer()
@@ -152,13 +144,11 @@
underTest.onAuthenticateKeyPressed()
assertThat(password).isEmpty()
- assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
}
@Test
fun onAuthenticateKeyPressed_whenEmpty() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
@@ -171,14 +161,12 @@
underTest.onAuthenticateKeyPressed()
assertThat(password).isEmpty()
- assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
}
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult)
- val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
lockDeviceAndOpenPasswordBouncer()
@@ -186,12 +174,10 @@
underTest.onPasswordInputChanged("wrong")
underTest.onAuthenticateKeyPressed()
assertThat(password).isEqualTo("")
- assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
assertThat(authResult).isFalse()
// Enter the correct password:
underTest.onPasswordInputChanged("password")
- assertThat(message?.text).isEmpty()
underTest.onAuthenticateKeyPressed()
@@ -331,10 +317,8 @@
private fun TestScope.switchToScene(toScene: SceneKey) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
sceneInteractor.changeScene(toScene, "reason")
- if (bouncerShown) underTest.onShown()
if (bouncerHidden) underTest.onHidden()
runCurrent()
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 91a056d..51b73ee9 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
@@ -63,6 +63,7 @@
viewModelScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
+ onIntentionalUserInput = {},
)
}
@@ -79,12 +80,10 @@
fun onShown() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
lockDeviceAndOpenPatternBouncer()
- assertThat(message?.text).isEqualTo(ENTER_YOUR_PATTERN)
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
@@ -95,14 +94,12 @@
fun onDragStart() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
lockDeviceAndOpenPatternBouncer()
underTest.onDragStart()
- assertThat(message?.text).isEmpty()
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
@@ -148,7 +145,6 @@
fun onDragEnd_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
lockDeviceAndOpenPatternBouncer()
@@ -159,7 +155,6 @@
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
- assertThat(message?.text).isEqualTo(WRONG_PATTERN)
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
}
@@ -302,7 +297,6 @@
@Test
fun onDragEnd_whenPatternTooShort() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val dialogViewModel by collectLastValue(bouncerViewModel.dialogViewModel)
lockDeviceAndOpenPatternBouncer()
@@ -325,7 +319,6 @@
underTest.onDragEnd()
- assertWithMessage("Attempt #$attempt").that(message?.text).isEqualTo(WRONG_PATTERN)
assertWithMessage("Attempt #$attempt").that(dialogViewModel).isNull()
}
}
@@ -334,7 +327,6 @@
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult)
- val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
lockDeviceAndOpenPatternBouncer()
@@ -344,7 +336,6 @@
underTest.onDragEnd()
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
- assertThat(message?.text).isEqualTo(WRONG_PATTERN)
assertThat(authResult).isFalse()
// Enter the correct pattern:
@@ -370,10 +361,8 @@
private fun TestScope.switchToScene(toScene: SceneKey) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
sceneInteractor.changeScene(toScene, "reason")
- if (bouncerShown) underTest.onShown()
if (bouncerHidden) underTest.onHidden()
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 7b75a37..5647954 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -56,7 +56,6 @@
private val sceneInteractor by lazy { kosmos.sceneInteractor }
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
- private val bouncerViewModel by lazy { kosmos.bouncerViewModel }
private lateinit var underTest: PinBouncerViewModel
@Before
@@ -69,6 +68,7 @@
isInputEnabled = MutableStateFlow(true).asStateFlow(),
simBouncerInteractor = kosmos.simBouncerInteractor,
authenticationMethod = AuthenticationMethodModel.Pin,
+ onIntentionalUserInput = {},
)
overrideResource(R.string.keyguard_enter_your_pin, ENTER_YOUR_PIN)
@@ -78,11 +78,9 @@
@Test
fun onShown() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
- assertThat(message?.text).ignoringCase().isEqualTo(ENTER_YOUR_PIN)
assertThat(pin).isEmpty()
assertThat(underTest.authenticationMethod).isEqualTo(AuthenticationMethodModel.Pin)
}
@@ -98,6 +96,7 @@
isInputEnabled = MutableStateFlow(true).asStateFlow(),
simBouncerInteractor = kosmos.simBouncerInteractor,
authenticationMethod = AuthenticationMethodModel.Sim,
+ onIntentionalUserInput = {},
)
assertThat(underTest.isSimAreaVisible).isTrue()
@@ -126,6 +125,7 @@
isInputEnabled = MutableStateFlow(true).asStateFlow(),
simBouncerInteractor = kosmos.simBouncerInteractor,
authenticationMethod = AuthenticationMethodModel.Sim,
+ onIntentionalUserInput = {},
)
kosmos.fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(true)
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
@@ -136,20 +136,17 @@
@Test
fun onPinButtonClicked() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
underTest.onPinButtonClicked(1)
- assertThat(message?.text).isEmpty()
assertThat(pin).containsExactly(1)
}
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
@@ -158,7 +155,6 @@
underTest.onBackspaceButtonClicked()
- assertThat(message?.text).isEmpty()
assertThat(pin).isEmpty()
}
@@ -183,7 +179,6 @@
fun onBackspaceButtonLongPressed() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
@@ -195,7 +190,6 @@
underTest.onBackspaceButtonLongPressed()
- assertThat(message?.text).isEmpty()
assertThat(pin).isEmpty()
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
}
@@ -217,7 +211,6 @@
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
@@ -230,7 +223,6 @@
underTest.onAuthenticateButtonClicked()
assertThat(pin).isEmpty()
- assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
}
@@ -238,7 +230,6 @@
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult)
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
lockDeviceAndOpenPinBouncer()
@@ -248,13 +239,11 @@
underTest.onPinButtonClicked(4)
underTest.onPinButtonClicked(5) // PIN is now wrong!
underTest.onAuthenticateButtonClicked()
- assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
assertThat(pin).isEmpty()
assertThat(authResult).isFalse()
// Enter the correct PIN:
FakeAuthenticationRepository.DEFAULT_PIN.forEach(underTest::onPinButtonClicked)
- assertThat(message?.text).isEmpty()
underTest.onAuthenticateButtonClicked()
@@ -277,7 +266,6 @@
fun onAutoConfirm_whenWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
kosmos.fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(true)
lockDeviceAndOpenPinBouncer()
@@ -290,7 +278,6 @@
) // PIN is now wrong!
assertThat(pin).isEmpty()
- assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
}
@@ -390,10 +377,8 @@
private fun TestScope.switchToScene(toScene: SceneKey) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
sceneInteractor.changeScene(toScene, "reason")
- if (bouncerShown) underTest.onShown()
if (bouncerHidden) underTest.onHidden()
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 8e2e947..a7e98ea 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -18,10 +18,16 @@
import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetProviderInfo
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
import android.content.pm.UserInfo
import android.os.UserHandle
import android.provider.Settings
import android.widget.RemoteViews
+import androidx.activity.result.ActivityResultLauncher
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
@@ -39,6 +45,7 @@
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.ui.view.MediaHost
@@ -46,15 +53,19 @@
import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -64,6 +75,8 @@
@Mock private lateinit var mediaHost: MediaHost
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var providerInfo: AppWidgetProviderInfo
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
@@ -73,6 +86,8 @@
private lateinit var smartspaceRepository: FakeSmartspaceRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
+ private val testableResources = context.orCreateTestableResources
+
private lateinit var underTest: CommunalEditModeViewModel
@Before
@@ -96,6 +111,7 @@
mediaHost,
uiEventLogger,
logcatLogBuffer("CommunalEditModeViewModelTest"),
+ kosmos.testDispatcher,
)
}
@@ -217,7 +233,69 @@
verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
}
+ @Test
+ fun onOpenWidgetPicker_launchesWidgetPickerActivity() {
+ testScope.runTest {
+ whenever(packageManager.resolveActivity(any(), anyInt())).then {
+ ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply { packageName = WIDGET_PICKER_PACKAGE_NAME }
+ }
+ }
+
+ val success =
+ underTest.onOpenWidgetPicker(
+ testableResources.resources,
+ packageManager,
+ activityResultLauncher
+ )
+
+ verify(activityResultLauncher).launch(any())
+ assertTrue(success)
+ }
+ }
+
+ @Test
+ fun onOpenWidgetPicker_launcherActivityNotResolved_doesNotLaunchWidgetPickerActivity() {
+ testScope.runTest {
+ whenever(packageManager.resolveActivity(any(), anyInt())).thenReturn(null)
+
+ val success =
+ underTest.onOpenWidgetPicker(
+ testableResources.resources,
+ packageManager,
+ activityResultLauncher
+ )
+
+ verify(activityResultLauncher, never()).launch(any())
+ assertFalse(success)
+ }
+ }
+
+ @Test
+ fun onOpenWidgetPicker_activityLaunchThrowsException_failure() {
+ testScope.runTest {
+ whenever(packageManager.resolveActivity(any(), anyInt())).then {
+ ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply { packageName = WIDGET_PICKER_PACKAGE_NAME }
+ }
+ }
+
+ whenever(activityResultLauncher.launch(any()))
+ .thenThrow(ActivityNotFoundException::class.java)
+
+ val success =
+ underTest.onOpenWidgetPicker(
+ testableResources.resources,
+ packageManager,
+ activityResultLauncher,
+ )
+
+ assertFalse(success)
+ }
+ }
+
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+ const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
index 69ff5ab..b4f87c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
@@ -21,6 +21,8 @@
import android.view.View
import android.widget.FrameLayout
import android.widget.RemoteViews.RemoteResponse
+import androidx.core.util.component1
+import androidx.core.util.component2
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -29,6 +31,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.refEq
import org.mockito.Mock
import org.mockito.Mockito.isNull
import org.mockito.Mockito.notNull
@@ -62,6 +65,7 @@
val parent = FrameLayout(context)
val view = CommunalAppWidgetHostView(context)
parent.addView(view)
+ val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
underTest.onInteraction(view, testIntent, testResponse)
@@ -70,6 +74,8 @@
eq(testIntent),
isNull(),
notNull(),
+ refEq(fillInIntent),
+ refEq(activityOptions.toBundle()),
)
}
@@ -78,10 +84,17 @@
val parent = FrameLayout(context)
val view = View(context)
parent.addView(view)
+ val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
underTest.onInteraction(view, testIntent, testResponse)
verify(activityStarter)
- .startPendingIntentMaybeDismissingKeyguard(eq(testIntent), isNull(), isNull())
+ .startPendingIntentMaybeDismissingKeyguard(
+ eq(testIntent),
+ isNull(),
+ isNull(),
+ refEq(fillInIntent),
+ refEq(activityOptions.toBundle()),
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
index decbdaf..51f9957 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorTest.kt
@@ -26,12 +26,10 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.Test
import org.junit.runner.RunWith
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class DeviceEntryFingerprintAuthInteractorTest : SysuiTestCase() {
@@ -59,17 +57,20 @@
}
@Test
- fun isSensorUnderDisplay_trueForUdfpsSensorTypes() =
+ fun isFingerprintCurrentlyAllowedInBouncer_trueForNonUdfpsSensorTypes() =
testScope.runTest {
- val isSensorUnderDisplay by collectLastValue(underTest.isSensorUnderDisplay)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ val isFingerprintCurrentlyAllowedInBouncer by
+ collectLastValue(underTest.isFingerprintCurrentlyAllowedOnBouncer)
fingerprintPropertyRepository.supportsUdfps()
- assertThat(isSensorUnderDisplay).isTrue()
+ assertThat(isFingerprintCurrentlyAllowedInBouncer).isFalse()
fingerprintPropertyRepository.supportsRearFps()
- assertThat(isSensorUnderDisplay).isFalse()
+ assertThat(isFingerprintCurrentlyAllowedInBouncer).isTrue()
fingerprintPropertyRepository.supportsSideFps()
- assertThat(isSensorUnderDisplay).isFalse()
+ assertThat(isFingerprintCurrentlyAllowedInBouncer).isTrue()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 769caaa..36458ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -270,12 +270,61 @@
}
@Test
+ fun transitionValue_canceled_toAnotherState() =
+ testScope.runTest {
+ val transitionValuesGone by collectValues(underTest.transitionValue(state = GONE))
+ val transitionValuesAod by collectValues(underTest.transitionValue(state = AOD))
+ val transitionValuesLs by collectValues(underTest.transitionValue(state = LOCKSCREEN))
+
+ listOf(
+ TransitionStep(GONE, AOD, 0f, STARTED),
+ TransitionStep(GONE, AOD, 0.5f, RUNNING),
+ TransitionStep(GONE, AOD, 0.5f, CANCELED),
+ TransitionStep(AOD, LOCKSCREEN, 0.5f, STARTED),
+ TransitionStep(AOD, LOCKSCREEN, 0.7f, RUNNING),
+ TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED),
+ )
+ .forEach {
+ repository.sendTransitionStep(it)
+ runCurrent()
+ }
+
+ assertThat(transitionValuesGone).isEqualTo(listOf(1f, 0.5f, 0f))
+ assertThat(transitionValuesAod).isEqualTo(listOf(0f, 0.5f, 0.5f, 0.3f, 0f))
+ assertThat(transitionValuesLs).isEqualTo(listOf(0.5f, 0.7f, 1f))
+ }
+
+ @Test
+ fun transitionValue_canceled_backToOriginalState() =
+ testScope.runTest {
+ val transitionValuesGone by collectValues(underTest.transitionValue(state = GONE))
+ val transitionValuesAod by collectValues(underTest.transitionValue(state = AOD))
+
+ listOf(
+ TransitionStep(GONE, AOD, 0f, STARTED),
+ TransitionStep(GONE, AOD, 0.5f, RUNNING),
+ TransitionStep(GONE, AOD, 1f, CANCELED),
+ TransitionStep(AOD, GONE, 0.5f, STARTED),
+ TransitionStep(AOD, GONE, 0.7f, RUNNING),
+ TransitionStep(AOD, GONE, 1f, FINISHED),
+ )
+ .forEach {
+ repository.sendTransitionStep(it)
+ runCurrent()
+ }
+
+ assertThat(transitionValuesGone).isEqualTo(listOf(1f, 0.5f, 0.5f, 0.7f, 1f))
+ assertThat(transitionValuesAod).isEqualTo(listOf(0f, 0.5f, 0.5f, 0.3f, 0f))
+ }
+
+ @Test
fun isInTransitionToAnyState() =
testScope.runTest {
val inTransition by collectValues(underTest.isInTransitionToAnyState)
assertEquals(
listOf(
+ false,
true, // The repo is seeded with a transition from OFF to LOCKSCREEN.
false,
),
@@ -288,6 +337,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -301,6 +351,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -314,6 +365,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -330,6 +382,7 @@
assertEquals(
listOf(
+ false,
true,
false,
),
@@ -345,6 +398,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -359,6 +413,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -379,6 +434,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
@@ -398,6 +454,7 @@
assertEquals(
listOf(
+ false,
true,
false,
true,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
index d443851..0cc0c2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
@@ -19,6 +19,7 @@
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.coroutines.collectValues
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -32,6 +33,7 @@
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,9 +51,7 @@
}
private val testScope = kosmos.testScope
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
- private val underTest by lazy {
- kosmos.alternateBouncerToGoneTransitionViewModel
- }
+ private val underTest by lazy { kosmos.alternateBouncerToGoneTransitionViewModel }
@Test
fun deviceEntryParentViewDisappear() =
@@ -73,6 +73,61 @@
values.forEach { assertThat(it).isEqualTo(0f) }
}
+ @Test
+ fun lockscreenAlpha() =
+ testScope.runTest {
+ val startAlpha = 0.6f
+ val viewState = ViewStateAccessor(alpha = { startAlpha })
+ val alpha by collectLastValue(underTest.lockscreenAlpha(viewState))
+ runCurrent()
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ step(0f, TransitionState.STARTED),
+ step(0.25f),
+ step(0.5f),
+ step(0.75f),
+ step(1f),
+ ),
+ testScope,
+ )
+
+ // Alpha starts at the starting value from ViewStateAccessor.
+ keyguardTransitionRepository.sendTransitionStep(
+ step(0f, state = TransitionState.STARTED)
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(startAlpha)
+
+ // Alpha finishes in 200ms out of 500ms, check the alpha at the halfway point.
+ val progress = 0.2f
+ keyguardTransitionRepository.sendTransitionStep(step(progress))
+ runCurrent()
+ assertThat(alpha).isEqualTo(0.3f)
+
+ // Alpha ends at 0.
+ keyguardTransitionRepository.sendTransitionStep(step(1f))
+ runCurrent()
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun lockscreenAlpha_zeroInitialAlpha() =
+ testScope.runTest {
+ // ViewState starts at 0 alpha.
+ val viewState = ViewStateAccessor(alpha = { 0f })
+ val alpha by collectValues(underTest.lockscreenAlpha(viewState))
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = GONE,
+ testScope
+ )
+
+ // Alpha starts and ends at 0.
+ alpha.forEach { assertThat(it).isEqualTo(0f) }
+ }
+
private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
return TransitionStep(
from = KeyguardState.ALTERNATE_BOUNCER,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
index e7aaddd..857b9f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
@@ -68,9 +68,7 @@
repository.sendTransitionStep(step(0f))
assertThat(alpha).isEqualTo(0.5f)
- repository.sendTransitionStep(step(0.25f))
- assertThat(alpha).isEqualTo(0.25f)
-
+ // Before the halfway point, it will have reached zero
repository.sendTransitionStep(step(.5f))
assertThat(alpha).isEqualTo(0f)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
index 0796af0..409c551 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
@@ -91,27 +91,6 @@
assertThat(bgViewAlpha).isEqualTo(1f)
}
- @Test
- fun deviceEntryBackgroundViewAlpha_rearFpEnrolled_noUpdates() =
- testScope.runTest {
- fingerprintPropertyRepository.supportsRearFps()
- val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
- keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
- assertThat(bgViewAlpha).isNull()
-
- keyguardTransitionRepository.sendTransitionStep(step(0.5f))
- assertThat(bgViewAlpha).isNull()
-
- keyguardTransitionRepository.sendTransitionStep(step(.75f))
- assertThat(bgViewAlpha).isNull()
-
- keyguardTransitionRepository.sendTransitionStep(step(1f))
- assertThat(bgViewAlpha).isNull()
-
- keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED))
- assertThat(bgViewAlpha).isNull()
- }
-
private fun step(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestHelper.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestHelper.kt
new file mode 100644
index 0000000..8e44932
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestHelper.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.media.controls
+
+import android.R
+import android.app.smartspace.SmartspaceAction
+import android.content.Context
+import android.graphics.drawable.Icon
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+class MediaTestHelper {
+ companion object {
+ /** Returns a list of three mocked recommendations */
+ fun getValidRecommendationList(context: Context): List<SmartspaceAction> {
+ val mediaRecommendationItem =
+ mock<SmartspaceAction> {
+ whenever(icon)
+ .thenReturn(
+ Icon.createWithResource(
+ context,
+ R.drawable.ic_media_play,
+ )
+ )
+ }
+ return listOf(mediaRecommendationItem, mediaRecommendationItem, mediaRecommendationItem)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryTest.kt
new file mode 100644
index 0000000..6c41bc3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryTest.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.media.controls.data.repository
+
+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.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.controls.MediaTestHelper
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MediaDataRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val underTest: MediaDataRepository = kosmos.mediaDataRepository
+
+ @Test
+ fun setRecommendation() =
+ testScope.runTest {
+ val smartspaceData by collectLastValue(underTest.smartspaceMediaData)
+ val recommendation = SmartspaceMediaData(isActive = true)
+
+ underTest.setRecommendation(recommendation)
+
+ assertThat(smartspaceData).isEqualTo(recommendation)
+ }
+
+ @Test
+ fun addAndRemoveMediaData() =
+ testScope.runTest {
+ val entries by collectLastValue(underTest.mediaEntries)
+
+ val firstKey = "key1"
+ val firstData = MediaData().copy(isPlaying = true)
+
+ val secondKey = "key2"
+ val secondData = MediaData().copy(resumption = true)
+
+ underTest.addMediaEntry(firstKey, firstData)
+ underTest.addMediaEntry(secondKey, secondData)
+ underTest.addMediaEntry(firstKey, firstData.copy(isPlaying = false))
+
+ assertThat(entries!!.size).isEqualTo(2)
+ assertThat(entries!![firstKey]).isNotEqualTo(firstData)
+
+ underTest.removeMediaEntry(firstKey)
+
+ assertThat(entries!!.size).isEqualTo(1)
+ assertThat(entries!![secondKey]).isEqualTo(secondData)
+ }
+
+ @Test
+ fun setRecommendationInactive() =
+ testScope.runTest {
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, true)
+ val smartspaceData by collectLastValue(underTest.smartspaceMediaData)
+ val recommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+
+ underTest.setRecommendation(recommendation)
+
+ assertThat(smartspaceData).isEqualTo(recommendation)
+
+ underTest.setRecommendationInactive(KEY_MEDIA_SMARTSPACE)
+
+ assertThat(smartspaceData).isNotEqualTo(recommendation)
+ assertThat(smartspaceData!!.isActive).isFalse()
+ }
+
+ @Test
+ fun dismissRecommendation() =
+ testScope.runTest {
+ val smartspaceData by collectLastValue(underTest.smartspaceMediaData)
+ val recommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+
+ underTest.setRecommendation(recommendation)
+
+ assertThat(smartspaceData).isEqualTo(recommendation)
+
+ underTest.dismissSmartspaceRecommendation(KEY_MEDIA_SMARTSPACE)
+
+ assertThat(smartspaceData!!.isActive).isFalse()
+ }
+
+ companion object {
+ private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
new file mode 100644
index 0000000..d39e77d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
@@ -0,0 +1,144 @@
+/*
+ * 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.media.controls.data.repository
+
+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.kosmos.testScope
+import com.android.systemui.media.controls.MediaTestHelper
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MediaFilterRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val underTest: MediaFilterRepository = kosmos.mediaFilterRepository
+
+ @Test
+ fun addSelectedUserMediaEntry_activeThenInactivate() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(underTest.selectedUserEntries)
+
+ val userMedia = MediaData().copy(active = true)
+
+ underTest.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(selectedUserEntries?.get(KEY)).isEqualTo(userMedia)
+
+ underTest.addSelectedUserMediaEntry(KEY, userMedia.copy(active = false))
+
+ assertThat(selectedUserEntries?.get(KEY)).isNotEqualTo(userMedia)
+ assertThat(selectedUserEntries?.get(KEY)?.active).isFalse()
+ }
+
+ @Test
+ fun addSelectedUserMediaEntry_thenRemove_returnsBoolean() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(underTest.selectedUserEntries)
+
+ val userMedia = MediaData()
+
+ underTest.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(selectedUserEntries?.get(KEY)).isEqualTo(userMedia)
+
+ assertThat(underTest.removeSelectedUserMediaEntry(KEY, userMedia)).isTrue()
+ }
+
+ @Test
+ fun addSelectedUserMediaEntry_thenRemove_returnsValue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(underTest.selectedUserEntries)
+
+ val userMedia = MediaData()
+
+ underTest.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(selectedUserEntries?.get(KEY)).isEqualTo(userMedia)
+
+ assertThat(underTest.removeSelectedUserMediaEntry(KEY)).isEqualTo(userMedia)
+ }
+
+ @Test
+ fun addAllUserMediaEntry_activeThenInactivate() =
+ testScope.runTest {
+ val allUserEntries by collectLastValue(underTest.allUserEntries)
+
+ val userMedia = MediaData().copy(active = true)
+
+ underTest.addMediaEntry(KEY, userMedia)
+
+ assertThat(allUserEntries?.get(KEY)).isEqualTo(userMedia)
+
+ underTest.addMediaEntry(KEY, userMedia.copy(active = false))
+
+ assertThat(allUserEntries?.get(KEY)).isNotEqualTo(userMedia)
+ assertThat(allUserEntries?.get(KEY)?.active).isFalse()
+ }
+
+ @Test
+ fun addAllUserMediaEntry_thenRemove_returnsValue() =
+ testScope.runTest {
+ val allUserEntries by collectLastValue(underTest.allUserEntries)
+
+ val userMedia = MediaData()
+
+ underTest.addMediaEntry(KEY, userMedia)
+
+ assertThat(allUserEntries?.get(KEY)).isEqualTo(userMedia)
+
+ assertThat(underTest.removeMediaEntry(KEY)).isEqualTo(userMedia)
+ }
+
+ @Test
+ fun addActiveRecommendation_thenInactive() =
+ testScope.runTest {
+ val smartspaceMediaData by collectLastValue(underTest.smartspaceMediaData)
+
+ val mediaRecommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+
+ underTest.setRecommendation(mediaRecommendation)
+
+ assertThat(smartspaceMediaData).isEqualTo(mediaRecommendation)
+
+ underTest.setRecommendation(mediaRecommendation.copy(isActive = false))
+
+ assertThat(smartspaceMediaData).isNotEqualTo(mediaRecommendation)
+ assertThat(smartspaceMediaData?.isActive).isFalse()
+ }
+
+ companion object {
+ private const val KEY = "KEY"
+ private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
new file mode 100644
index 0000000..6e67000
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
@@ -0,0 +1,199 @@
+/*
+ * 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.media.controls.domain.interactor
+
+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.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.controls.MediaTestHelper
+import com.android.systemui.media.controls.data.repository.MediaFilterRepository
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
+import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MediaCarouselInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val mediaFilterRepository: MediaFilterRepository = kosmos.mediaFilterRepository
+ private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor
+
+ @Test
+ fun addUserMediaEntry_activeThenInactivate() =
+ testScope.runTest {
+ val hasActiveMediaOrRecommendation by
+ collectLastValue(underTest.hasActiveMediaOrRecommendation)
+ val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)
+ val hasAnyMedia by collectLastValue(underTest.hasAnyMedia)
+
+ val userMedia = MediaData().copy(active = true)
+
+ mediaFilterRepository.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(hasActiveMediaOrRecommendation).isTrue()
+ assertThat(hasActiveMedia).isTrue()
+ assertThat(hasAnyMedia).isTrue()
+
+ mediaFilterRepository.addSelectedUserMediaEntry(KEY, userMedia.copy(active = false))
+
+ assertThat(hasActiveMediaOrRecommendation).isFalse()
+ assertThat(hasActiveMedia).isFalse()
+ assertThat(hasAnyMedia).isTrue()
+ }
+
+ @Test
+ fun addInactiveUserMediaEntry_thenRemove() =
+ testScope.runTest {
+ val hasActiveMediaOrRecommendation by
+ collectLastValue(underTest.hasActiveMediaOrRecommendation)
+ val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)
+ val hasAnyMedia by collectLastValue(underTest.hasAnyMedia)
+
+ val userMedia = MediaData().copy(active = false)
+
+ mediaFilterRepository.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(hasActiveMediaOrRecommendation).isFalse()
+ assertThat(hasActiveMedia).isFalse()
+ assertThat(hasAnyMedia).isTrue()
+
+ assertThat(mediaFilterRepository.removeSelectedUserMediaEntry(KEY, userMedia)).isTrue()
+
+ assertThat(hasActiveMediaOrRecommendation).isFalse()
+ assertThat(hasActiveMedia).isFalse()
+ assertThat(hasAnyMedia).isFalse()
+ }
+
+ @Test
+ fun addActiveRecommendation_inactiveMedia() =
+ testScope.runTest {
+ val hasActiveMediaOrRecommendation by
+ collectLastValue(underTest.hasActiveMediaOrRecommendation)
+ val hasAnyMediaOrRecommendation by
+ collectLastValue(underTest.hasAnyMediaOrRecommendation)
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+
+ val userMediaRecommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+ val userMedia = MediaData().copy(active = false)
+
+ mediaFilterRepository.setRecommendation(userMediaRecommendation)
+
+ assertThat(hasActiveMediaOrRecommendation).isTrue()
+ assertThat(hasAnyMediaOrRecommendation).isTrue()
+
+ mediaFilterRepository.addSelectedUserMediaEntry(KEY, userMedia)
+
+ assertThat(hasActiveMediaOrRecommendation).isTrue()
+ assertThat(hasAnyMediaOrRecommendation).isTrue()
+ }
+
+ @Test
+ fun addActiveRecommendation_thenInactive() =
+ testScope.runTest {
+ val hasActiveMediaOrRecommendation by
+ collectLastValue(underTest.hasActiveMediaOrRecommendation)
+ val hasAnyMediaOrRecommendation by
+ collectLastValue(underTest.hasAnyMediaOrRecommendation)
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+
+ val mediaRecommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+
+ mediaFilterRepository.setRecommendation(mediaRecommendation)
+
+ assertThat(hasActiveMediaOrRecommendation).isTrue()
+ assertThat(hasAnyMediaOrRecommendation).isTrue()
+
+ mediaFilterRepository.setRecommendation(mediaRecommendation.copy(isActive = false))
+
+ assertThat(hasActiveMediaOrRecommendation).isFalse()
+ assertThat(hasAnyMediaOrRecommendation).isFalse()
+ }
+
+ @Test
+ fun addActiveRecommendation_thenInvalid() =
+ testScope.runTest {
+ val hasActiveMediaOrRecommendation by
+ collectLastValue(underTest.hasActiveMediaOrRecommendation)
+ val hasAnyMediaOrRecommendation by
+ collectLastValue(underTest.hasAnyMediaOrRecommendation)
+ kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false)
+
+ val mediaRecommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(context),
+ )
+
+ mediaFilterRepository.setRecommendation(mediaRecommendation)
+
+ assertThat(hasActiveMediaOrRecommendation).isTrue()
+ assertThat(hasAnyMediaOrRecommendation).isTrue()
+
+ mediaFilterRepository.setRecommendation(
+ mediaRecommendation.copy(recommendations = listOf())
+ )
+
+ assertThat(hasActiveMediaOrRecommendation).isFalse()
+ assertThat(hasAnyMediaOrRecommendation).isFalse()
+ }
+
+ @Test
+ fun hasAnyMedia_noMediaSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasAnyMedia.value).isFalse() }
+
+ @Test
+ fun hasAnyMediaOrRecommendation_noMediaSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasAnyMediaOrRecommendation.value).isFalse() }
+
+ @Test
+ fun hasActiveMedia_noMediaSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasActiveMedia.value).isFalse() }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasActiveMediaOrRecommendation.value).isFalse() }
+
+ companion object {
+ private const val KEY = "KEY"
+ private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
index c2ce392..f1cd0c8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt
@@ -185,7 +185,7 @@
setOf(QSTileState.UserAction.CLICK),
label,
null,
- QSTileState.SideViewIcon.None,
+ QSTileState.SideViewIcon.Chevron,
QSTileState.EnabledState.ENABLED,
Switch::class.qualifiedName
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
index f24723a..97a10e6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
@@ -33,7 +33,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
/** Test [DataSaverDialogDelegate]. */
@@ -69,7 +68,7 @@
fun delegateSetsDialogTitleCorrectly() {
val expectedResId = R.string.data_saver_enable_title
- dataSaverDialogDelegate.onCreate(sysuiDialog, null)
+ dataSaverDialogDelegate.beforeCreate(sysuiDialog, null)
verify(sysuiDialog).setTitle(eq(expectedResId))
}
@@ -78,7 +77,7 @@
fun delegateSetsDialogMessageCorrectly() {
val expectedResId = R.string.data_saver_description
- dataSaverDialogDelegate.onCreate(sysuiDialog, null)
+ dataSaverDialogDelegate.beforeCreate(sysuiDialog, null)
verify(sysuiDialog).setMessage(expectedResId)
}
@@ -87,7 +86,7 @@
fun delegateSetsDialogPositiveButtonCorrectly() {
val expectedResId = R.string.data_saver_enable_button
- dataSaverDialogDelegate.onCreate(sysuiDialog, null)
+ dataSaverDialogDelegate.beforeCreate(sysuiDialog, null)
verify(sysuiDialog).setPositiveButton(eq(expectedResId), any())
}
@@ -96,7 +95,7 @@
fun delegateSetsDialogCancelButtonCorrectly() {
val expectedResId = R.string.cancel
- dataSaverDialogDelegate.onCreate(sysuiDialog, null)
+ dataSaverDialogDelegate.beforeCreate(sysuiDialog, null)
verify(sysuiDialog).setNeutralButton(eq(expectedResId), eq(null))
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractorTest.kt
new file mode 100644
index 0000000..8651300
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractorTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.qs.tiles.impl.work.domain.interactor
+
+import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
+import android.testing.LeakCheck
+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.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.utils.leaks.FakeManagedProfileController
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class WorkModeTileDataInteractorTest : SysuiTestCase() {
+ private val controller = FakeManagedProfileController(LeakCheck())
+ private val underTest: WorkModeTileDataInteractor = WorkModeTileDataInteractor(controller)
+
+ @Test
+ fun availability_matchesControllerHasActiveProfiles() = runTest {
+ val availability by collectLastValue(underTest.availability(TEST_USER))
+
+ assertThat(availability).isFalse()
+
+ controller.setHasActiveProfile(true)
+ assertThat(availability).isTrue()
+
+ controller.setHasActiveProfile(false)
+ assertThat(availability).isFalse()
+ }
+
+ @Test
+ fun tileData_whenHasActiveProfile_matchesControllerIsEnabled() = runTest {
+ controller.setHasActiveProfile(true)
+ val data by
+ collectLastValue(
+ underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
+ )
+
+ assertThat(data).isInstanceOf(WorkModeTileModel.HasActiveProfile::class.java)
+ assertThat((data as WorkModeTileModel.HasActiveProfile).isEnabled).isFalse()
+
+ controller.isWorkModeEnabled = true
+ assertThat(data).isInstanceOf(WorkModeTileModel.HasActiveProfile::class.java)
+ assertThat((data as WorkModeTileModel.HasActiveProfile).isEnabled).isTrue()
+
+ controller.isWorkModeEnabled = false
+ assertThat(data).isInstanceOf(WorkModeTileModel.HasActiveProfile::class.java)
+ assertThat((data as WorkModeTileModel.HasActiveProfile).isEnabled).isFalse()
+ }
+
+ @Test
+ fun tileData_matchesControllerHasActiveProfile() = runTest {
+ val data by
+ collectLastValue(
+ underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
+ )
+ assertThat(data).isInstanceOf(WorkModeTileModel.NoActiveProfile::class.java)
+
+ controller.setHasActiveProfile(true)
+ assertThat(data).isInstanceOf(WorkModeTileModel.HasActiveProfile::class.java)
+
+ controller.setHasActiveProfile(false)
+ assertThat(data).isInstanceOf(WorkModeTileModel.NoActiveProfile::class.java)
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractorTest.kt
new file mode 100644
index 0000000..8a63e2c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractorTest.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.qs.tiles.impl.work.domain.interactor
+
+import android.platform.test.annotations.EnabledOnRavenwood
+import android.provider.Settings
+import android.testing.LeakCheck
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.utils.leaks.FakeManagedProfileController
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class WorkModeTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+ private val profileController = FakeManagedProfileController(LeakCheck())
+
+ private val underTest =
+ WorkModeTileUserActionInteractor(
+ profileController,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ profileController.isWorkModeEnabled = wasEnabled
+
+ underTest.handleInput(
+ QSTileInputTestKtx.click(WorkModeTileModel.HasActiveProfile(wasEnabled))
+ )
+
+ assertThat(profileController.isWorkModeEnabled).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ profileController.isWorkModeEnabled = wasEnabled
+
+ underTest.handleInput(
+ QSTileInputTestKtx.click(WorkModeTileModel.HasActiveProfile(wasEnabled))
+ )
+
+ assertThat(profileController.isWorkModeEnabled).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenUnavailable() = runTest {
+ val wasEnabled = false
+ profileController.isWorkModeEnabled = wasEnabled
+
+ underTest.handleInput(QSTileInputTestKtx.click(WorkModeTileModel.NoActiveProfile))
+
+ assertThat(profileController.isWorkModeEnabled).isEqualTo(wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(
+ QSTileInputTestKtx.longClick(WorkModeTileModel.HasActiveProfile(enabled))
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_MANAGED_PROFILE_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(
+ QSTileInputTestKtx.longClick(WorkModeTileModel.HasActiveProfile(enabled))
+ )
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_MANAGED_PROFILE_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenUnavailable() = runTest {
+ underTest.handleInput(QSTileInputTestKtx.longClick(WorkModeTileModel.NoActiveProfile))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledNoInputs()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index cc66f8b..f018cc1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -51,6 +51,8 @@
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -175,10 +177,12 @@
transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
assertThat(isVisible).isFalse()
- kosmos.headsUpNotificationRepository.hasPinnedHeadsUp.value = true
+ kosmos.headsUpNotificationRepository.activeHeadsUpRows.value =
+ buildNotificationRows(isPinned = true)
assertThat(isVisible).isTrue()
- kosmos.headsUpNotificationRepository.hasPinnedHeadsUp.value = false
+ kosmos.headsUpNotificationRepository.activeHeadsUpRows.value =
+ buildNotificationRows(isPinned = false)
assertThat(isVisible).isFalse()
}
@@ -1070,4 +1074,17 @@
return transitionStateFlow
}
+
+ private fun buildNotificationRows(isPinned: Boolean = false): Set<HeadsUpRowRepository> =
+ setOf(
+ fakeHeadsUpRowRepository(key = "0", isPinned = isPinned),
+ fakeHeadsUpRowRepository(key = "1", isPinned = isPinned),
+ fakeHeadsUpRowRepository(key = "2", isPinned = isPinned),
+ fakeHeadsUpRowRepository(key = "3", isPinned = isPinned),
+ )
+
+ private fun fakeHeadsUpRowRepository(key: String, isPinned: Boolean) =
+ FakeHeadsUpRowRepository(key = key, elementKey = Any()).apply {
+ this.isPinned.value = isPinned
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 1c54961..d1c4ec3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -95,7 +95,7 @@
scope = testScope.backgroundScope,
)
- private val qsFlexiglassAdapter = FakeQSSceneAdapter({ mock() })
+ private val qsSceneAdapter = FakeQSSceneAdapter({ mock() })
private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
@@ -122,7 +122,7 @@
applicationScope = testScope.backgroundScope,
deviceEntryInteractor = deviceEntryInteractor,
shadeHeaderViewModel = shadeHeaderViewModel,
- qsSceneAdapter = qsFlexiglassAdapter,
+ qsSceneAdapter = qsSceneAdapter,
notifications = kosmos.notificationsPlaceholderViewModel,
mediaDataManager = mediaDataManager,
shadeInteractor = kosmos.shadeInteractor,
@@ -279,6 +279,20 @@
}
@Test
+ fun upTransitionSceneKey_customizing_noTransition() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+
+ qsSceneAdapter.setCustomizing(true)
+ assertThat(
+ destinationScenes!!
+ .keys
+ .filterIsInstance<Swipe>()
+ .filter { it.direction == SwipeDirection.Up }
+ ).isEmpty()
+ }
+
+ @Test
fun shadeMode() =
testScope.runTest {
val shadeMode by collectLastValue(underTest.shadeMode)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index 2689fc1..94539a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -31,6 +30,7 @@
import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
import com.android.systemui.testKosmos
@@ -64,7 +64,7 @@
@Test
fun updateBounds() =
testScope.runTest {
- val bounds by collectLastValue(appearanceViewModel.stackBounds)
+ val clipping by collectLastValue(appearanceViewModel.stackClipping)
val top = 200f
val left = 0f
@@ -76,15 +76,8 @@
right = right,
bottom = bottom
)
- assertThat(bounds)
- .isEqualTo(
- NotificationContainerBounds(
- left = left,
- top = top,
- right = right,
- bottom = bottom
- )
- )
+ assertThat(clipping?.bounds)
+ .isEqualTo(StackBounds(left = left, top = top, right = right, bottom = bottom))
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
new file mode 100644
index 0000000..bba9991
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.domain.interactor
+
+import android.platform.test.annotations.EnableFlags
+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.kosmos.testScope
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
+import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
+import com.android.systemui.statusbar.notification.stack.data.repository.setNotifications
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+class HeadsUpNotificationInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val repository = kosmos.headsUpNotificationRepository
+
+ private val underTest = kosmos.headsUpNotificationInteractor
+
+ @Test
+ fun hasPinnedRows_emptyList_false() =
+ testScope.runTest {
+ val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+
+ assertThat(hasPinnedRows).isFalse()
+ }
+
+ @Test
+ fun hasPinnedRows_noPinnedRows_false() =
+ testScope.runTest {
+ val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+ // WHEN no pinned rows are set
+ repository.setNotifications(
+ fakeHeadsUpRowRepository("key 0"),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ runCurrent()
+
+ // THEN hasPinnedRows is false
+ assertThat(hasPinnedRows).isFalse()
+ }
+
+ @Test
+ fun hasPinnedRows_hasPinnedRows_true() =
+ testScope.runTest {
+ val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+ // WHEN a pinned rows is set
+ repository.setNotifications(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ runCurrent()
+
+ // THEN hasPinnedRows is true
+ assertThat(hasPinnedRows).isTrue()
+ }
+
+ @Test
+ fun hasPinnedRows_rowGetsPinned_true() =
+ testScope.runTest {
+ val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+ // GIVEN no rows are pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0"),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // WHEN a row gets pinned
+ rows[0].isPinned.value = true
+ runCurrent()
+
+ // THEN hasPinnedRows updates to true
+ assertThat(hasPinnedRows).isTrue()
+ }
+
+ @Test
+ fun hasPinnedRows_rowGetsUnPinned_false() =
+ testScope.runTest {
+ val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
+ // GIVEN one row is pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // THEN that row gets unpinned
+ rows[0].isPinned.value = false
+ runCurrent()
+
+ // THEN hasPinnedRows updates to false
+ assertThat(hasPinnedRows).isFalse()
+ }
+
+ @Test
+ fun pinnedRows_noRows_isEmpty() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+
+ assertThat(pinnedHeadsUpRows).isEmpty()
+ }
+
+ @Test
+ fun pinnedRows_noPinnedRows_isEmpty() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+ // WHEN no rows are pinned
+ repository.setNotifications(
+ fakeHeadsUpRowRepository("key 0"),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ runCurrent()
+
+ // THEN all rows are filtered
+ assertThat(pinnedHeadsUpRows).isEmpty()
+ }
+
+ @Test
+ fun pinnedRows_hasPinnedRows_containsPinnedRows() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+ // WHEN some rows are pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1", isPinned = true),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // THEN the unpinned rows are filtered
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0], rows[1])
+ }
+
+ @Test
+ fun pinnedRows_rowGetsPinned_containsPinnedRows() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+ // GIVEN some rows are pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1", isPinned = true),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // WHEN all rows gets pinned
+ rows[2].isPinned.value = true
+ runCurrent()
+
+ // THEN no rows are filtered
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0], rows[1], rows[2])
+ }
+
+ @Test
+ fun pinnedRows_allRowsPinned_containsAllRows() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+ // WHEN all rows are pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1", isPinned = true),
+ fakeHeadsUpRowRepository("key 2", isPinned = true),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // THEN no rows are filtered
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0], rows[1], rows[2])
+ }
+
+ @Test
+ fun pinnedRows_rowGetsUnPinned_containsPinnedRows() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+ // GIVEN all rows are pinned
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0", isPinned = true),
+ fakeHeadsUpRowRepository("key 1", isPinned = true),
+ fakeHeadsUpRowRepository("key 2", isPinned = true),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ // WHEN a row gets unpinned
+ rows[0].isPinned.value = false
+ runCurrent()
+
+ // THEN the unpinned row is filtered
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[1], rows[2])
+ }
+
+ @Test
+ fun pinnedRows_rowGetsPinnedAndUnPinned_containsTheSameInstance() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository("key 0"),
+ fakeHeadsUpRowRepository("key 1"),
+ fakeHeadsUpRowRepository("key 2"),
+ )
+ repository.setNotifications(rows)
+ runCurrent()
+
+ rows[0].isPinned.value = true
+ runCurrent()
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
+
+ rows[0].isPinned.value = false
+ runCurrent()
+ assertThat(pinnedHeadsUpRows).isEmpty()
+
+ rows[0].isPinned.value = true
+ runCurrent()
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
+ }
+
+ private fun fakeHeadsUpRowRepository(key: String, isPinned: Boolean = false) =
+ FakeHeadsUpRowRepository(key = key, elementKey = Any()).apply {
+ this.isPinned.value = isPinned
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
index ffe6e6d..e3fa89c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
@@ -19,10 +19,13 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.StackRounding
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -30,10 +33,9 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-@android.platform.test.annotations.EnabledOnRavenwood
class NotificationStackAppearanceInteractorTest : SysuiTestCase() {
- private val kosmos = Kosmos()
+ private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val underTest = kosmos.notificationStackAppearanceInteractor
@@ -43,29 +45,39 @@
val stackBounds by collectLastValue(underTest.stackBounds)
val bounds1 =
- NotificationContainerBounds(
+ StackBounds(
top = 100f,
bottom = 200f,
- isAnimated = true,
)
underTest.setStackBounds(bounds1)
assertThat(stackBounds).isEqualTo(bounds1)
val bounds2 =
- NotificationContainerBounds(
+ StackBounds(
top = 200f,
bottom = 300f,
- isAnimated = false,
)
underTest.setStackBounds(bounds2)
assertThat(stackBounds).isEqualTo(bounds2)
}
+ @Test
+ fun stackRounding() =
+ testScope.runTest {
+ val stackRounding by collectLastValue(underTest.stackRounding)
+
+ kosmos.shadeRepository.setShadeMode(ShadeMode.Single)
+ assertThat(stackRounding).isEqualTo(StackRounding(roundTop = true, roundBottom = false))
+
+ kosmos.shadeRepository.setShadeMode(ShadeMode.Split)
+ assertThat(stackRounding).isEqualTo(StackRounding(roundTop = true, roundBottom = true))
+ }
+
@Test(expected = IllegalStateException::class)
fun setStackBounds_withImproperBounds_throwsException() =
testScope.runTest {
underTest.setStackBounds(
- NotificationContainerBounds(
+ StackBounds(
top = 100f,
bottom = 99f,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
index 693de55..2ccc8b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -36,9 +37,9 @@
fun onBoundsChanged_setsNotificationContainerBounds() {
underTest.onBoundsChanged(left = 5f, top = 5f, right = 5f, bottom = 5f)
assertThat(kosmos.keyguardInteractor.notificationContainerBounds.value)
- .isEqualTo(NotificationContainerBounds(left = 5f, top = 5f, right = 5f, bottom = 5f))
+ .isEqualTo(NotificationContainerBounds(top = 5f, bottom = 5f))
assertThat(kosmos.notificationStackAppearanceInteractor.stackBounds.value)
- .isEqualTo(NotificationContainerBounds(left = 5f, top = 5f, right = 5f, bottom = 5f))
+ .isEqualTo(StackBounds(left = 5f, top = 5f, right = 5f, bottom = 5f))
}
@Test
fun onContentTopChanged_setsContentTop() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 53a8e5d..5256bb9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -720,6 +720,59 @@
}
@Test
+ fun alphaDoesNotUpdateWhileGoneTransitionIsRunning() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showLockscreen()
+ // GONE transition gets to 90% complete
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.STARTED,
+ value = 0f,
+ )
+ )
+ runCurrent()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+
+ // At this point, alpha should be zero
+ assertThat(alpha).isEqualTo(0f)
+
+ // An attempt to override by the shade should be ignored
+ shadeRepository.setQsExpansion(0.5f)
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun alphaWhenGoneIsSetToOne() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showLockscreen()
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope
+ )
+ keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
fun shadeCollapseFadeIn() =
testScope.runTest {
val fadeIn by collectValues(underTest.shadeCollapseFadeIn)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index 8aa0e3fc..c8062fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.phone
+import android.app.ActivityOptions
import android.app.PendingIntent
import android.content.Intent
+import android.os.Bundle
import android.os.RemoteException
import android.os.UserHandle
import android.view.View
import android.widget.FrameLayout
+import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
@@ -48,6 +51,7 @@
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
@@ -173,6 +177,53 @@
)
}
+ fun startPendingIntentDismissingKeyguard_fillInIntentAndExtraOptions_sendAndReturnResult() {
+ val pendingIntent = mock(PendingIntent::class.java)
+ val fillInIntent = mock(Intent::class.java)
+ val parent = FrameLayout(context)
+ val view =
+ object : View(context), LaunchableView {
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+ }
+ parent.addView(view)
+ val controller = ActivityTransitionAnimator.Controller.fromView(view)
+ whenever(pendingIntent.isActivity).thenReturn(true)
+ whenever(keyguardStateController.isShowing).thenReturn(true)
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
+ .thenReturn(false)
+
+ // extra activity options to set on pending intent
+ val activityOptions = mock(ActivityOptions::class.java)
+ activityOptions.splashScreenStyle = SPLASH_SCREEN_STYLE_SOLID_COLOR
+ activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission = false
+ val bundleCaptor = argumentCaptor<Bundle>()
+
+ underTest.startPendingIntentMaybeDismissingKeyguard(
+ intent = pendingIntent,
+ animationController = controller,
+ intentSentUiThreadCallback = null,
+ fillInIntent = fillInIntent,
+ extraOptions = activityOptions.toBundle(),
+ )
+ mainExecutor.runAllReady()
+
+ // Fill-in intent is passed and options contain extra values specified
+ verify(pendingIntent)
+ .sendAndReturnResult(
+ eq(context),
+ eq(0),
+ eq(fillInIntent),
+ nullable(),
+ nullable(),
+ nullable(),
+ bundleCaptor.capture()
+ )
+ val options = ActivityOptions.fromBundle(bundleCaptor.value)
+ assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission).isFalse()
+ assertThat(options.splashScreenStyle).isEqualTo(SPLASH_SCREEN_STYLE_SOLID_COLOR)
+ }
+
@Test
fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
val pendingIntent = mock(PendingIntent::class.java)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 9169938..781a9a8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -46,7 +46,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index be63301..30564bb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -60,7 +60,7 @@
private val mGlobalSettings = FakeGlobalSettings()
private val mSystemClock = FakeSystemClock()
private val mExecutor = FakeExecutor(mSystemClock)
- private var testableHeadsUpManager: BaseHeadsUpManager? = null
+ private lateinit var testableHeadsUpManager: BaseHeadsUpManager
@Before
fun setUp() {
@@ -88,20 +88,15 @@
}
private fun createHeadsUpEntry(id: Int): BaseHeadsUpManager.HeadsUpEntry {
- val entry = testableHeadsUpManager!!.createHeadsUpEntry()
-
- entry.setEntry(
+ return testableHeadsUpManager.createHeadsUpEntry(
NotificationEntryBuilder()
.setSbn(HeadsUpManagerTestUtil.createSbn(id, Notification.Builder(mContext, "")))
.build()
)
- return entry
}
private fun createFsiHeadsUpEntry(id: Int): BaseHeadsUpManager.HeadsUpEntry {
- val entry = testableHeadsUpManager!!.createHeadsUpEntry()
- entry.setEntry(createFullScreenIntentEntry(id, mContext))
- return entry
+ return testableHeadsUpManager.createHeadsUpEntry(createFullScreenIntentEntry(id, mContext))
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index ed0d272..3dc4495 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -38,7 +38,6 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
-import android.content.Intent;
import android.testing.TestableLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -498,16 +497,16 @@
public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
- ongoingCall.setEntry(new NotificationEntryBuilder()
- .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
- new Notification.Builder(mContext, "")
- .setCategory(Notification.CATEGORY_CALL)
- .setOngoing(true)))
- .build());
+ final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry(
+ new NotificationEntryBuilder()
+ .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
+ new Notification.Builder(mContext, "")
+ .setCategory(Notification.CATEGORY_CALL)
+ .setOngoing(true)))
+ .build());
- final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
- activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
+ final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
+ HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
activeRemoteInput.mRemoteInputActive = true;
assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -518,18 +517,18 @@
public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();
final Person person = new Person.Builder().setName("person").build();
final PendingIntent intent = mock(PendingIntent.class);
- incomingCall.setEntry(new NotificationEntryBuilder()
- .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
- new Notification.Builder(mContext, "")
- .setStyle(Notification.CallStyle
- .forIncomingCall(person, intent, intent))))
- .build());
+ final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry(
+ new NotificationEntryBuilder()
+ .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
+ new Notification.Builder(mContext, "")
+ .setStyle(Notification.CallStyle
+ .forIncomingCall(person, intent, intent))))
+ .build());
- final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
- activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
+ final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(
+ HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
activeRemoteInput.mRemoteInputActive = true;
assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -541,8 +540,7 @@
final BaseHeadsUpManager hum = createHeadsUpManager();
// Needs full screen intent in order to be pinned
- final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();
- entryToPin.setEntry(
+ final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(
HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext));
// Note: the standard way to show a notification would be calling showNotification rather
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
index d8f77f0..3c9dc63 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -54,9 +54,10 @@
mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
}
+ @NonNull
@Override
- protected HeadsUpEntry createHeadsUpEntry() {
- mLastCreatedEntry = spy(super.createHeadsUpEntry());
+ protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
+ mLastCreatedEntry = spy(super.createHeadsUpEntry(entry));
return mLastCreatedEntry;
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/DisposableHandlesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/DisposableHandlesTest.kt
new file mode 100644
index 0000000..a5ad3c3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/DisposableHandlesTest.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.util.kotlin
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.DisposableHandle
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DisposableHandlesTest : SysuiTestCase() {
+ @Test
+ fun disposeWorksOnce() {
+ var handleDisposeCount = 0
+ val underTest = DisposableHandles()
+
+ // Add a handle
+ underTest += DisposableHandle { handleDisposeCount++ }
+
+ // dispose() calls dispose() on children
+ underTest.dispose()
+ assertThat(handleDisposeCount).isEqualTo(1)
+
+ // Once disposed, children are not disposed again
+ underTest.dispose()
+ assertThat(handleDisposeCount).isEqualTo(1)
+ }
+
+ @Test
+ fun replaceCallsDispose() {
+ var handleDisposeCount1 = 0
+ var handleDisposeCount2 = 0
+ val underTest = DisposableHandles()
+ val handle1 = DisposableHandle { handleDisposeCount1++ }
+ val handle2 = DisposableHandle { handleDisposeCount2++ }
+
+ // First add handle1
+ underTest += handle1
+
+ // replace() calls dispose() on existing children
+ underTest.replaceAll(handle2)
+ assertThat(handleDisposeCount1).isEqualTo(1)
+ assertThat(handleDisposeCount2).isEqualTo(0)
+
+ // Once disposed, replaced children are not disposed again
+ underTest.dispose()
+ assertThat(handleDisposeCount1).isEqualTo(1)
+ assertThat(handleDisposeCount2).isEqualTo(1)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
index 3d93654..5358a6d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
@@ -200,6 +200,15 @@
}
}
+ @Test
+ fun alarmStream_isNotMutable() {
+ with(kosmos) {
+ val isMutable = underTest.isMutable(AudioStream(AudioManager.STREAM_ALARM))
+
+ assertThat(isMutable).isFalse()
+ }
+ }
+
private companion object {
val audioStream = AudioStream(AudioManager.STREAM_SYSTEM)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
index 471c8d8..8e92557 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.panel.component.bottombar.ui.viewmodel
+import android.app.ActivityManager
import android.content.Intent
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -23,6 +24,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.activityStarter
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.capture
@@ -49,6 +51,8 @@
@Captor private lateinit var intentCaptor: ArgumentCaptor<Intent>
+ @Captor private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback>
+
private val kosmos = testKosmos()
private lateinit var underTest: BottomBarViewModel
@@ -80,10 +84,13 @@
runCurrent()
+ verify(activityStarter).startActivity(capture(intentCaptor), eq(true),
+ capture(activityStartedCaptor))
+ assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
+
+ activityStartedCaptor.value.onActivityStarted(ActivityManager.START_SUCCESS)
val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState)
assertThat(volumePanelState!!.isVisible).isFalse()
- verify(activityStarter).startActivity(capture(intentCaptor), eq(true))
- assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
new file mode 100644
index 0000000..b5c5809
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractorTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.volume.panel.component.mediaoutput.domain.interactor
+
+import android.os.Handler
+import android.testing.TestableLooper
+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.kosmos.testCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.localMediaController
+import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.remoteMediaController
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class MediaDeviceSessionInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private lateinit var underTest: MediaDeviceSessionInteractor
+
+ @Before
+ fun setup() {
+ with(kosmos) {
+ mediaControllerRepository.setActiveSessions(
+ listOf(localMediaController, remoteMediaController)
+ )
+
+ underTest =
+ MediaDeviceSessionInteractor(
+ testScope.testScheduler,
+ Handler(TestableLooper.get(kosmos.testCase).looper),
+ mediaControllerRepository,
+ )
+ }
+ }
+
+ @Test
+ fun playbackInfo_returnsPlaybackInfo() {
+ with(kosmos) {
+ testScope.runTest {
+ val session by collectLastValue(mediaOutputInteractor.defaultActiveMediaSession)
+ runCurrent()
+ val info by collectLastValue(underTest.playbackInfo(session!!))
+ runCurrent()
+
+ assertThat(info).isEqualTo(localMediaController.playbackInfo)
+ }
+ }
+ }
+
+ @Test
+ fun playbackState_returnsPlaybackState() {
+ with(kosmos) {
+ testScope.runTest {
+ val session by collectLastValue(mediaOutputInteractor.defaultActiveMediaSession)
+ runCurrent()
+ val state by collectLastValue(underTest.playbackState(session!!))
+ runCurrent()
+
+ assertThat(state).isEqualTo(localMediaController.playbackState)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
index dcf635e..6f7f20b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt
@@ -29,9 +29,10 @@
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
-import com.android.systemui.volume.mediaController
import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.mediaOutputActionsInteractor
import com.android.systemui.volume.mediaOutputInteractor
import com.android.systemui.volume.panel.volumePanelViewModel
@@ -63,6 +64,7 @@
testScope.backgroundScope,
volumePanelViewModel,
mediaOutputActionsInteractor,
+ mediaDeviceSessionInteractor,
mediaOutputInteractor,
)
@@ -74,11 +76,11 @@
)
}
- whenever(mediaController.packageName).thenReturn("test.pkg")
- whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
- whenever(mediaController.playbackState).then { playbackStateBuilder.build() }
+ whenever(localMediaController.packageName).thenReturn("test.pkg")
+ whenever(localMediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+ whenever(localMediaController.playbackState).then { playbackStateBuilder.build() }
- mediaControllerRepository.setActiveLocalMediaController(mediaController)
+ mediaControllerRepository.setActiveSessions(listOf(localMediaController))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
index 1ed7f5d..2f69942 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
@@ -32,8 +32,8 @@
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
-import com.android.systemui.volume.mediaController
import com.android.systemui.volume.mediaControllerRepository
import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor
import com.google.common.truth.Truth.assertThat
@@ -66,11 +66,11 @@
}
)
- whenever(mediaController.packageName).thenReturn("test.pkg")
- whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
- whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build())
+ whenever(localMediaController.packageName).thenReturn("test.pkg")
+ whenever(localMediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+ whenever(localMediaController.playbackState).thenReturn(PlaybackState.Builder().build())
- mediaControllerRepository.setActiveLocalMediaController(mediaController)
+ mediaControllerRepository.setActiveSessions(listOf(localMediaController))
underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
index 281b03d..e36ae60 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
@@ -34,8 +34,8 @@
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
-import com.android.systemui.volume.mediaController
import com.android.systemui.volume.mediaControllerRepository
import com.android.systemui.volume.mediaOutputInteractor
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
@@ -70,11 +70,11 @@
}
)
- whenever(mediaController.packageName).thenReturn("test.pkg")
- whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
- whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build())
+ whenever(localMediaController.packageName).thenReturn("test.pkg")
+ whenever(localMediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+ whenever(localMediaController.playbackState).thenReturn(PlaybackState.Builder().build())
- mediaControllerRepository.setActiveLocalMediaController(mediaController)
+ mediaControllerRepository.setActiveSessions(listOf(localMediaController))
underTest =
SpatialAudioComponentInteractor(
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 1126ec3..072ec99 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Intent;
+import android.os.Bundle;
import android.os.UserHandle;
import android.view.View;
@@ -67,6 +68,17 @@
@Nullable ActivityTransitionAnimator.Controller animationController);
/**
+ * Similar to {@link #startPendingIntentMaybeDismissingKeyguard(PendingIntent, Runnable,
+ * ActivityTransitionAnimator.Controller)}, but also specifies a fill-in intent and extra
+ * options that could be used to populate the pending intent and launch the activity.
+ */
+ void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
+ @Nullable Runnable intentSentUiThreadCallback,
+ @Nullable ActivityTransitionAnimator.Controller animationController,
+ @Nullable Intent fillInIntent,
+ @Nullable Bundle extraOptions);
+
+ /**
* The intent flag can be specified in startActivity().
*/
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index b4d89ab..6f60d84 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik eerder ’n patroon vir bykomende sekuriteit"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik eerder ’n PIN vir bykomende sekuriteit"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik eerder ’n wagwoord vir bykomende sekuriteit"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN word vir bykomende sekuriteit vereis"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Patroon word vir bykomende sekuriteit vereis"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Wagwoord word vir bykomende sekuriteit vereis"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Toestel is deur administrateur gesluit"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Toestel is handmatig gesluit"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie herken nie"</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index bfe918f..529d609 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"áá°ášá᪠á°á
áááµ á ááµá© áµááá° á¥ááµ áá áá"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"áá°ášá᪠á°á
áááµ á ááµá© áá áá áá"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"áá°ášá᪠á°á
áááµ á ááµá© ášááá áá áá áá"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"áá áá°ášá᪠á°á
áááµ á«áµáááá"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"á¥ááá° á¥ááµ áá°ášá᪠á°á
áááµ á«áµáááá"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ášááá áá áá°ášá᪠á°á
áááµ á«áµáááá"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"áá£áªá« á á áµá°á³á³áª á°áááá"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"áá£áªá« á á°á ááá á«á± á°áááá"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"á áá³ááá"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index e4dc86d..d07c5b5 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
Ø§ÙØ استخدÙÙ
اÙÙÙØŽ ØšØ¯ÙØ§Ù Ù
٠ذÙÙ."</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
Ø§ÙØ أدخÙ٠رÙÙ
Ø§ÙØªØ¹Ø±ÙÙ Ø§ÙØŽØ®ØµÙ ØšØ¯ÙØ§Ù Ù
٠ذÙÙ."</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
Ø§ÙØ أدخÙÙ ÙÙÙ
Ø© اÙÙ
Ø±ÙØ± ØšØ¯ÙØ§Ù Ù
٠ذÙÙ."</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÙØ¬Øš إدخا٠رÙÙ
Ø§ÙØªØ¹Ø±ÙÙ Ø§ÙØŽØ®ØµÙ ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
اÙ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÙØ¬Øš رسÙ
اÙÙÙØŽ ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
اÙ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÙØ¬Øš إدخا٠ÙÙÙ
Ø© اÙÙ
Ø±ÙØ± ÙÙ
Ø²ÙØ¯ Ù
Ù Ø§ÙØ£Ù
اÙ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"اختار اÙÙ
؎ر٠ÙÙÙ Ø§ÙØ¬Ùاز"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"تÙ
ØØžØ± Ø§ÙØ¬Ùاز ÙØ¯ÙÙÙØ§"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ÙÙ
ÙØªÙ
Ø§ÙØªØ¹Ø±Ù٠عÙÙÙ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 7a12aef..ce8ebd3 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§, àŠàŠ¯àŠŒàŠŸà§° àŠªà§°àŠ¿à§±à§°à§àŠ€à§ àŠà§°à§àŠ¹àŠ¿ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§, àŠàŠ¯àŠŒàŠŸà§° àŠªà§°àŠ¿à§±à§°à§àŠ€à§ àŠªàŠ¿àŠš àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§, àŠàŠ¯àŠŒàŠŸà§° àŠªà§°àŠ¿à§±à§°à§àŠ€à§ àŠªàŠŸàŠà§±à§°à§àŠ¡ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠªàŠ¿àŠš àŠŠàŠ¿àŠ¯àŠŒàŠŸàŠà§ àŠ¬àŠŸàŠ§à§àŠ¯àŠ€àŠŸàŠ®à§àвàŠ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠàаà§àŠ¹àŠ¿ àŠŠàŠ¿àŠ¯àŠŒàŠŸàŠà§ àŠ¬àŠŸàŠ§à§àŠ¯àŠ€àŠŸàŠ®à§àвàŠ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àŠ
àŠ€àŠ¿à§°àŠ¿àŠà§àŠ€ àŠžà§à§°àŠà§àŠ·àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠªàŠŸàŠà§±àаà§àŠ¡ àŠŠàŠ¿àŠ¯àŠŒàŠŸàŠà§ àŠ¬àŠŸàŠ§à§àŠ¯àŠ€àŠŸàŠ®à§àвàŠ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àŠªà§à§°àŠ¶àŠŸàŠžàŠà§ àŠ¡àŠ¿àŠàŠŸàŠàŠ àŠ²àŠ àŠà§°àŠ¿ à§°àŠŸàŠàŠ¿àŠà§"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àŠ¡àŠ¿àŠàŠŸàŠàŠàŠà§ àŠ®à§àŠšà§à§±à§àвàŠàŠŸà§±à§ àŠ²àŠ àŠà§°àŠŸ àŠ¹à§àŠàŠ¿àŠ²"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àŠàŠ¿àŠšàŠŸàŠà§àŠ€ àŠà§°àŠ¿àŠ¬ àŠªà§°àŠŸ àŠšàŠŸàŠ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index ba07b27..832391c 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÆlavÉ tÉhlükÉsizlik üçün modeldÉn istifadÉ edin"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÆlavÉ tÉhlükÉsizlik üçün PIN istifadÉ edin"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÆlavÉ tÉhlükÉsizlik üçün paroldan istifadÉ edin"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÆlavÉ tÉhlükÉsizlik üçün PIN tÉlÉb olunur"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÆlavÉ tÉhlükÉsizlik üçün model tÉlÉb olunur"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÆlavÉ tÉhlükÉsizlik üçün parol tÉlÉb olunur"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz admin tÉrÉfindÉn kilidlÉnib"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihaz Él ilÉ kilidlÉndi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmır"</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 9d6fdfa..ee27e83 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu bezbednost koristite šablon"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu bezbednost koristite PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu bezbednost koristite lozinku"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Treba da unesete PIN radi dodatne bezbednosti"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Treba da unesete šablon radi dodatne bezbednosti"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Treba da unesete lozinku radi dodatne bezbednosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zakljuÄao ureÄaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"UreÄaj je ruÄno zakljuÄan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 0a27f5e..7d37e6e 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"У ÐŒÑÑаÑ
ЎаЎаÑкПвай бÑÑÐ¿ÐµÐºÑ ÑкаÑÑÑÑайÑе ÑÐ·ÐŸÑ ÑазблакÑÑПÑкÑ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"У ÐŒÑÑаÑ
ЎаЎаÑкПвай бÑÑÐ¿ÐµÐºÑ ÑкаÑÑÑÑайÑе PIN-кПЎ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"У ÐŒÑÑаÑ
ЎаЎаÑкПвай бÑÑÐ¿ÐµÐºÑ ÑкаÑÑÑÑайÑе паÑПлÑ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÐÐ»Ñ ÐŽÐ°ÐŽÐ°ÑкПвай бÑÑÐ¿ÐµÐºÑ ÐœÐµÐ°Ð±Ñ
ПЎМа ÑвеÑÑÑ PIN-кПЎ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÐÐ»Ñ ÐŽÐ°ÐŽÐ°ÑкПвай бÑÑÐ¿ÐµÐºÑ ÐœÐµÐ°Ð±Ñ
ПЎМа ÑвеÑÑÑ ÑÐ·ÐŸÑ ÑазблакÑÑПÑкÑ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÐÐ»Ñ ÐŽÐ°ÐŽÐ°ÑкПвай бÑÑÐ¿ÐµÐºÑ ÐœÐµÐ°Ð±Ñ
ПЎМа ÑвеÑÑÑ Ð¿Ð°ÑПлÑ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÐÑÑлаЎа заблакÑÑаваМа аЎЌÑМÑÑÑÑаÑаÑаЌ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ÐÑÑлаЎа бÑла заблакÑÑаваМа ÑÑÑÑМÑÑ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ðе ÑаÑпазМаМа"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 8fa334d..5b804e2 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠžà§àаàŠà§àŠ·àŠŸàŠ° àŠàŠšà§àН, àŠàа àŠ¬àŠŠàŠ²à§ àŠªà§àŠ¯àŠŸàŠàŠŸàŠ°à§àŠš àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàаà§àŠš"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠžà§àаàŠà§àŠ·àŠŸàŠ° àŠàŠšà§àН, àŠàа àŠ¬àŠŠàŠ²à§ àŠªàŠ¿àŠš àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàаà§àŠš"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠžà§àаàŠà§àŠ·àŠŸàŠ° àŠàŠšà§àН, àŠàа àŠ¬àŠŠàŠ²à§ àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàаà§àŠš"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠšàŠ¿àŠ°àŠŸàŠªàŠ€à§àŠ€àŠŸàŠ° àŠàŠšà§àН àŠªàŠ¿àŠš àŠŠàŠ¿àŠ€à§ àŠ¹àŠ¬à§"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠšàŠ¿àŠ°àŠŸàŠªàŠ€à§àŠ€àŠŸàŠ° àŠàŠšà§àН àŠªà§àŠ¯àŠŸàŠàŠŸàŠ°à§àŠš àŠŠàŠ¿àŠ€à§ àŠ¹àŠ¬à§"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àŠ
àŠ€àŠ¿àŠ°àŠ¿àŠà§àŠ€ àŠšàŠ¿àŠ°àŠŸàŠªàŠ€à§àŠ€àŠŸàŠ° àŠàŠšà§àН àŠªàŠŸàŠžàŠàŠ¯àŠŒàŠŸàŠ°à§àŠ¡ àŠŠàŠ¿àŠ€à§ àŠ¹àŠ¬à§"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àŠªà§àŠ°àŠ¶àŠŸàŠžàŠ àŠ¡àŠ¿àŠàŠŸàŠàŠžàŠàŠ¿ àŠ²àŠ àŠàаà§àŠà§àŠš"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àŠ¡àŠ¿àŠàŠŸàŠàŠžàŠàŠ¿àŠà§ àŠ®à§àŠ¯àŠŸàŠšà§àŠ¯àŠŒàŠŸàŠ²àŠ¿ àŠ²àŠ àŠàŠ°àŠŸ àŠ¹àŠ¯àŠŒà§àŠà§"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àŠ¶àŠšàŠŸàŠà§àŠ€ àŠàŠ°àŠŸ àŠ¯àŠŸàŠ¯àŠŒàŠšàŠ¿"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 7290a60..9677945 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Radi dodatne zaštite, umjesto toga koristite uzorak"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Radi dodatne zaštite, umjesto toga koristite PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Radi dodatne zašitite, umjesto toga koristite lozinku"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN je potreban radi dodatne sigurnosti"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Uzorak je potreban radi dodatne sigurnosti"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Lozinka je potrebna radi dodatne sigurnosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"UreÄaj je zakljuÄao administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"UreÄaj je ruÄno zakljuÄan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 1b91b09..226d193 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per a més seguretat, utilitza el patró"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per a més seguretat, utilitza el PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per a més seguretat, utilitza la contrasenya"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Cal introduir el PIN per disposar de més seguretat"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Cal introduir el patró per disposar de més seguretat"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Cal introduir la contrasenya per disposar de més seguretat"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'administrador ha bloquejat el dispositiu"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositiu s\'ha bloquejat manualment"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No s\'ha reconegut"</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index c62e9dd..8e97e84 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Z bezpeÄnostních důvodů radÄji pouÅŸijte gesto"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Z bezpeÄnostních důvodů radÄji pouÅŸijte PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Z bezpeÄnostních důvodů radÄji pouÅŸijte heslo"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Pro ještÄ lepší zabezpeÄení je vyÅŸadován kód PIN"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pro ještÄ lepší zabezpeÄení je vyÅŸadováno gesto"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Pro ještÄ lepší zabezpeÄení je vyÅŸadováno heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ZaÅízení je uzamknuto administrátorem"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ZaÅízení bylo ruÄnÄ uzamÄeno"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznáno"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index f776d2e..3053e70 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Øg sikkerheden ved at bruge dit oplåsningsmønter i stedet"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Øg sikkerheden ved at bruge din pinkode i stedet"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Øg sikkerheden ved at bruge din adgangskode i stedet"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Der kræves en pinkode som ekstra beskyttelse"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Der kræves et mønster som ekstra beskyttelse"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Der kræves en adgangskode som ekstra beskyttelse"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheden er blevet låst af administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheden blev låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke genkendt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 633eab5..2245710 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Verwende für mehr Sicherheit stattdessen dein Muster"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Verwende für mehr Sicherheit stattdessen deine PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Verwende für mehr Sicherheit stattdessen dein Passwort"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Zur Verbesserung der Sicherheit ist eine PIN erforderlich"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Zur Verbesserung der Sicherheit ist ein Muster erforderlich"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Zur Verbesserung der Sicherheit ist ein Passwort erforderlich"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Gerät vom Administrator gesperrt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Gerät manuell gesperrt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nicht erkannt"</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 4f69be1..aa804635 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Για πρÏσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά μοτίβο"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Για πρÏσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Για πρÏσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά κωδικÏ πρÏσβασης"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Απαιτείται PIN για πρÏσθετη ασφάλεια"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Απαιτείται μοτίβο για πρÏσθετη ασφάλεια"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Απαιτείται κωδικÏς πρÏσβασης για πρÏσθετη ασφάλεια"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Η συσκευή κλειδÏθηκε απÏ τον διαχειριστή"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Η συσκευή κλειδÏθηκε με μη αυτÏματο τρÏπο"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Δεν αναγνωρίστηκε"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index f9ed764..2a93dfe 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN required for additional security"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pattern required for additional security"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index f9ed764..2a93dfe 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN required for additional security"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pattern required for additional security"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index f9ed764..2a93dfe 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN required for additional security"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pattern required for additional security"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Password required for additional security"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 5da50fd..45e2a9d 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para seguridad adicional, usa un patrón"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para seguridad adicional, usa un PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para seguridad adicional, usa una contraseña"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Se requiere el PIN por razones de seguridad"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Se requiere el patrón por razones de seguridad"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Se requiere la contraseña por razones de seguridad"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 9a67b07..3a09852 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para mayor seguridad, usa el patrón"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para mayor seguridad, usa el PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para mayor seguridad, usa la contraseña"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Debes introducir el PIN como medida de seguridad adicional"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Debes introducir el patrón como medida de seguridad adicional"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Debes introducir la contraseña como medida de seguridad adicional"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 446b927..0b8ad02 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kasutage tugevama turvalisuse huvides hoopis mustrit"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kasutage tugevama turvalisuse huvides hoopis PIN-koodi"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kasutage tugevama turvalisuse huvides hoopis parooli"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Lisaturvalisuse huvides tuleb sisestada PIN-kood"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Lisaturvalisuse huvides tuleb sisestada muster"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Lisaturvalisuse huvides tuleb sisestada parool"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administraator lukustas seadme"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Seade lukustati käsitsi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tuvastatud"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index ad20008..41c3e06 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Babestuago egoteko, erabili eredua"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Babestuago egoteko, erabili PINa"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Babestuago egoteko, erabili pasahitza"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PINa behar da gailua babestuago izateko"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Eredua behar da gailua babestuago izateko"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Pasahitza behar da gailua babestuago izateko"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratzaileak blokeatu egin du gailua"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Eskuz blokeatu da gailua"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ez da ezagutu"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 087e45f..917e131 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ØšØ±Ø§Û Ø§Ù
ÙÛØª ØšÛØŽØªØ±Ø ØšÙØ¬Ø§Û آ٠از اÙÚ¯Ù Ø§Ø³ØªÙØ§Ø¯Ù Ú©ÙÛØ¯"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ØšØ±Ø§Û Ø§Ù
ÙÛØª ØšÛØŽØªØ±Ø ØšÙØ¬Ø§Û آ٠از ÙŸÛÙ Ø§Ø³ØªÙØ§Ø¯Ù Ú©ÙÛØ¯"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ØšØ±Ø§Û Ø§Ù
ÙÛØª ØšÛØŽØªØ±Ø ØšÙØ¬Ø§Û آ٠از Ú¯Ø°Ø±ÙØ§ÚÙ Ø§Ø³ØªÙØ§Ø¯Ù Ú©ÙÛØ¯"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ØšØ±Ø§Û Ø§ÛÙ
ÙÛ ØšÛØŽØªØ± ØšØ§ÛØ¯ ÙŸÛÙ ÙØ§Ø±Ø¯ ØŽÙØ¯"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ØšØ±Ø§Û Ø§ÛÙ
ÙÛ ØšÛØŽØªØ± ØšØ§ÛØ¯ اÙÚ¯Ù ÙØ§Ø±Ø¯ ØŽÙØ¯"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ØšØ±Ø§Û Ø§ÛÙ
ÙÛ ØšÛØŽØªØ± ØšØ§ÛØ¯ Ú¯Ø°Ø±ÙØ§ÚÙ ÙØ§Ø±Ø¯ ØŽÙØ¯"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Ø¯Ø³ØªÚ¯Ø§Ù ØªÙØ³Ø· سرٟرست Ø³ÛØ³ØªÙ
ÙÙ٠؎د٠است"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ø¯Ø³ØªÚ¯Ø§Ù ØšÙØµÙرت Ø¯Ø³ØªÛ ÙÙ٠؎د٠است"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ØŽÙØ§Ø³Ø§ÛÛ ÙØŽØ¯"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index b5e8fb5..ea1dd13 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Lisäsuojaa saat, kun käytät sen sijaan kuviota"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Lisäsuojaa saat, kun käytät sen sijaan PIN-koodia"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Lisäsuojaa saat, kun käytät sen sijaan salasanaa"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN-koodi vaaditaan suojauksen parantamiseksi."</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Kuvio vaaditaan suojauksen parantamiseksi."</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Salasana vaaditaan suojauksen parantamiseksi."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Järjestelmänvalvoja lukitsi laitteen."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Laite lukittiin manuaalisesti"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tunnistettu"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index ea61070..6eea6c9 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pour plus de sécurité, utilisez plutôt un schéma"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pour plus de sécurité, utilisez plutôt un NIP"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pour plus de sécurité, utilisez plutôt un mot de passe"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Le NIP est exigé pour plus de sécurité"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Le schéma est exigé pour plus de sécurité"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Le mot de passe est exigé pour plus de sécurité"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'appareil a été verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"L\'appareil a été verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Doigt non reconnu"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 40e10ef..188a76a 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pour plus de sécurité, utilisez plutôt un schéma"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pour plus de sécurité, utilisez plutôt un code"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pour plus de sécurité, utilisez plutôt un mot de passe"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Veuillez saisir le code pour renforcer la sécurité"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Veuillez dessiner le schéma pour renforcer la sécurité"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Veuillez saisir le mot de passe pour renforcer la sécurité"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Appareil verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 2eb0323..6b51ac2 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Utiliza un padrón para obter maior seguranza"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Utiliza un PIN para obter maior seguranza"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Utiliza un contrasinal para obter maior seguranza"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"É necesario poñer o PIN como medida de seguranza adicional"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"É necesario poñer o padrón como medida de seguranza adicional"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"É necesario poñer o contrasinal como medida de seguranza adicional"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"O administrador bloqueou o dispositivo"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo bloqueouse manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non se recoñeceu"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 5f01e28..4645f03 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà«, ઀à«àªšàªŸ બઊલૠપà«
àªàª°à«àªšàªšà« àªàªªàª¯à«àª àªàª°à«"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà«, ઀à«àªšàªŸ બઊલૠપિચચૠàªàªªàª¯à«àª àªàª°à«"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà«, ઀à«àªšàªŸ બઊલૠપટઞવરà«àª¡àªšà« àªàªªàª¯à«àª àªàª°à«"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà« પિચ àªàª°à«àª°à« àªà«"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà« પà«
àªàª°à«àªš àªàª°à«àª°à« àªà«"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"વધટરટચૠઞà«àª°àªà«àª·àªŸ મટàªà« પટઞવરà«àª¡ àªàª°à«àª°à« àªà«"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"વà«àª¯àªµàªžà«àª¥àªŸàªªàªà« àªàªªàªàª°àª£ લà«àª àªàª°à«àª²à«àª àªà«"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àªàªªàªàª°àª£ મà«àªšà«àª¯à«àª
લૠલà«àª àªàª°à«àª¯à«àª હ઀à«àª"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àªàª³àªàªŸàª¯à«àª² ચથà«"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 11e608c..a762b49 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€, à€à€žà€à¥ à€¬à€à€Ÿà€¯ à€ªà¥à€à€°à¥à€š à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à¥à€"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€, à€à€žà€à¥ à€¬à€à€Ÿà€¯ à€ªà€¿à€š à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à¥à€"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€, à€à€žà€à¥ à€¬à€à€Ÿà€¯ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à¥à€"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€ à€ªà€¿à€š à€à€Œà€°à¥à€°à¥ à€¹à¥"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€ à€ªà¥à€à€°à¥à€š à€à€Œà€°à¥à€°à¥ à€¹à¥"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿ à€à¥ à€²à€¿à€ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à€Œà€°à¥à€°à¥ à€¹à¥"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€ à€šà¥ à€¡à€¿à€µà€Ÿà€à€ž à€à¥ à€²à¥à€ à€à€¿à€¯à€Ÿ à€¹à¥"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"à€¡à€¿à€µà€Ÿà€à€ž à€à¥ à€®à¥à€šà¥à€¯à¥à€
à€² à€°à¥à€ª à€žà¥ à€²à¥à€ à€à€¿à€¯à€Ÿ à€à€¯à€Ÿ à€¥à€Ÿ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à€ªà€¹à€à€Ÿà€š à€šà€¹à¥à€ à€¹à¥ à€ªà€Ÿà€"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 274fdee..b4b2a19 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu sigurnost upotrijebite uzorak"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu sigurnost upotrijebite PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu sigurnost upotrijebite zaporku"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Unesite PIN radi dodatne sigurnosti"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Unesite uzorak radi dodatne sigurnosti"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Unesite zaporku radi dodatne sigurnosti"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zakljuÄao ureÄaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"UreÄaj je ruÄno zakljuÄan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 0a5ac59..bc4fe05 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"A nagyobb biztonság érdekében használjon inkább mintát"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"A nagyobb biztonság érdekében használjon inkább PIN-kódot"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"A nagyobb biztonság érdekében használjon inkább jelszót"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"A nagyobb biztonság érdekében PIN-kód szükséges"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"A nagyobb biztonság érdekében minta szükséges"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"A nagyobb biztonság érdekében jelszó szükséges"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"A rendszergazda zárolta az eszközt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Az eszközt manuálisan lezárták"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nem ismerhetÅ fel"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 28344c9..4a375e2 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÔŒÖÕ¡ÖÕžÖÖÕ«Õ¹ Õ¡Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Ö Õ¶Õ¡ÕÕ·"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÔŒÖÕ¡ÖÕžÖÖÕ«Õ¹ Õ¡Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Ö PIN Õ¯ÕžÕ€"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÔŒÖÕ¡ÖÕžÖÖÕ«Õ¹ Õ¡Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Ö Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡ÕŒ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Ô±Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ նկատաՌ՞ÖÕŽÕ¶Õ¥ÖÕ«Ö Õ¥Õ¬Õ¶Õ¥Õ¬ÕžÕŸ Õ¡Õ¶Õ°ÖÕ¡ÕªÕ¥Õ·Õ¿ Õ§ ÕŽÕžÖÕ¿ÖÕ¡Õ£ÖÕ¥Õ¬ PIN Õ¯ÕžÕ€Õš"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Ô±Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ նկատաՌ՞ÖÕŽÕ¶Õ¥ÖÕ«Ö Õ¥Õ¬Õ¶Õ¥Õ¬ÕžÕŸ Õ¡Õ¶Õ°ÖÕ¡ÕªÕ¥Õ·Õ¿ Õ§ ÕŽÕžÖÕ¿ÖÕ¡Õ£ÖÕ¥Õ¬ Õ¶Õ¡ÕÕ·Õš"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Ô±Õ¶ÕŸÕ¿Õ¡Õ¶Õ£ÕžÖÕ©ÕµÕ¡Õ¶ նկատաՌ՞ÖÕŽÕ¶Õ¥ÖÕ«Ö Õ¥Õ¬Õ¶Õ¥Õ¬ÕžÕŸ Õ¡Õ¶Õ°ÖÕ¡ÕªÕ¥Õ·Õ¿ Õ§ ÕŽÕžÖÕ¿ÖÕ¡Õ£ÖÕ¥Õ¬ գաղտնաբաՌ՚"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÕÕ¡ÖÖÕš Õ¯ÕžÕ²ÕºÕŸÕ¡Õ® Õ§ աՀՎինի՜տÖÕ¡Õ¿ÕžÖÕ« Õ¯ÕžÕ²ÕŽÕ«Ö"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ÕÕ¡ÖÖÕš Õ¯ÕžÕ²ÕºÕŸÕ¥Õ¬ Õ§ Õ±Õ¥ÕŒÖÕžÕŸ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ÕÕ°Õ¡Õ»ÕžÕ²ÕŸÕ¥Ö Õ³Õ¡Õ¶Õ¡Õ¹Õ¥Õ¬"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 2a8d8a9..dc5b0b8 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keamanan tambahan, gunakan pola"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keamanan tambahan, gunakan PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keamanan tambahan, gunakan sandi"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN diperlukan untuk keamanan tambahan"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pola diperlukan untuk keamanan tambahan"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Sandi diperlukan untuk keamanan tambahan"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Perangkat dikunci oleh admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Perangkat dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 0c14e6c..20808db 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Fyrir aukið öryggi skaltu nota mynstur í staðinn"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Fyrir aukið öryggi skaltu nota PIN-númer í staðinn"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Fyrir aukið öryggi skaltu nota aðgangsorð í staðinn"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN-númers er krafist af öryggisástæðum"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Mynsturs er krafist af öryggisástæðum"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Aðgangsorðs er krafist af öryggisástæðum"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Kerfisstjóri læsti tæki"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Tækinu var læst handvirkt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Þekktist ekki"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 2c2bacc..722d43d 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per maggior sicurezza, usa invece la sequenza"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per maggior sicurezza, usa invece il PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per maggior sicurezza, usa invece la password"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN obbligatorio per maggiore sicurezza"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Sequenza obbligatoria per maggiore sicurezza"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Password obbligatoria per maggiore sicurezza"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloccato dall\'amministratore"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 6e54ba9..71a60a8 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"××× ×××××ך ×ת ך×ת ××××××, ×××× ××שת×ש ××§× ××××× × ×¢××× ×××§×× ××ת"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"××× ×××××ך ×ת ך×ת ××××××, ×××× ××שת×ש ××§×× ××××ת ×××§×× ××ת"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"××× ×××××ך ×ת ך×ת ××××××, ×××× ××שת×ש ×ס×ס×× ×××§×× ××ת"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"× ×ךש ×§×× ××××ת ××× ×ש׀ך ×ת ך×ת ××××××"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"× ×ךש ×§× ××××× × ×¢××× ××× ×ש׀ך ×ת ך×ת ××××××"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"× ×ךשת ס×ס×× ××× ×ש׀ך ×ת ך×ת ××××××"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"××× ×× ×©× ×××ש×ך × ×× ××ת×"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"×××ש×ך × × ×¢× ××××€× ××× ×"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"×× ×××ת×"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index db99d96..562726f 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ áááááá§áááá áááá£ášá"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ áááááá§áááá PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ áááááá§áááá ááá ááá"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ á¡áááá áá PIN-ááááá¡ ášáá§áááá"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ á¡áááá áá áááá£ášáá¡ ášáá§áááá"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ááááá¢ááááá á£á¡áá€á áá®ááááá¡áááá¡ á¡áááá áá ááá áááá¡ ášáá§áááá"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ááá¬á§ááááááá á©áááá¢áááá ááááááá¡á¢á áá¢áá áá¡ áááá "</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ááá¬á§ááááááá á®áááá á©ááááá¢á"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"áá áá áá¡ ááááªáááááá"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 7bf93ae..103f8ad 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк Ò¯ÑÑМ Ó©ÑМекÑÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒ£Ñз."</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк Ò¯ÑÑМ PIN кПЎÑМ пайЎалаМÑÒ£Ñз."</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк Ò¯ÑÑМ ÒÒ±Ð¿ÐžÑ ÑÓ©Ð·ÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒ£Ñз."</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк ÑаÑаÑÑ ÑеÑÑМЎе PIN кПЎÑМ еМгÑÐ·Ñ ÒажеÑ."</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк ÑаÑаÑÑ ÑеÑÑМЎе Ó©ÑМекÑÑ ÐµÐœÐ³ÑÐ·Ñ ÒажеÑ."</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÒПÑÑÐŒÑа ÒаÑÑпÑÑзЎÑк ÑаÑаÑÑ ÑеÑÑМЎе ÒÒ±Ð¿ÐžÑ ÑÓ©Ð·ÐŽÑ ÐµÐœÐ³ÑÐ·Ñ ÒажеÑ."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÒÒ±ÑÑлÒÑÐœÑ ÓкÑÐŒÑÑ ÒұлÑпÑаÒаМ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ÒÒ±ÑÑлÒÑ ÒПлЌеМ ÒұлÑпÑалЎÑ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ТаМÑлЌаЎÑ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index b326f4c..b816748 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ááŸáááážáá»ááááá·áá¶ááááááá ááŒáááááŸáááá¶áááááœááá·á"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ááŸáááážáá»ááááá·áá¶ááááááá ááŒáááááŸááŒá PIN ááááœááá·á"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ááŸáááážáá»ááááá·áá¶ááááááá ááŒáááááŸáá¶áááááááá¶ááááááœááá·á"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"áááááŒáá±áááááá
áŒáááŒá PIN ááŸáááážáááœááá¶ááá»ááááá·áá¶ááááááá"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"áááááŒáá±ááááááŸáááá¶á ááŸáááážáááœááá¶ááá»ááááá·áá¶ááááááá"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"áááááŒáá±áááááá
áŒááá¶áááááááá¶áá ááŸáááážáááœááá¶ááá»ááááá·áá¶ááááááá"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"á§áááááâááááŒááá¶áâá
á¶ááááâáááá¢áááâááááááááá"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"á§áááááááááŒááá¶áá
á¶áááááááá¢áááááááŸáááá¶áá"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"áá·áá¢á¶á
ááááá¶áááá¶ááá"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 10bd9bf..7560621 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿, ಬಊಲಿà²à³ ಪà³à²¯à²Ÿà²à²°à³à²šà³ à²
ಚà³à²šà³ ಬಳಞಿ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿, ಬಊಲಿà²à³ ಪಿಚೠಬಳಞಿ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿, ಬಊಲಿà²à³ ಪಟಞà³à²µà²°à³à²¡à³ à²
ಚà³à²šà³ ಬಳಞಿ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿ ಪಿಚೠà²
à²à²€à³à²¯à²µà²¿à²Šà³"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿ ಪà³à²¯à²Ÿà²à²°à³à²šà³ à²
à²à²€à³à²¯à²µà²¿à²Šà³"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ಹà³à²à³à²à³à²µà²°à²¿ à²à²Šà³à²°à²€à³à²à²Ÿà²à²¿ ಪಟಞà³à²µà²°à³à²¡à³ à²
à²à²€à³à²¯à²µà²¿à²Šà³"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ಚಿರà³à²µà²Ÿà²¹à²à²°à³ ಞಟಧಚವಚà³à²šà³ ಲಟà²à³ ಮಟಡಿಊà³à²Šà²Ÿà²°à³"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ಞಟಧಚವಚà³à²šà³ ಹಞà³à²€à²à²Ÿà²²à²¿à²€à²µà²Ÿà²à²¿ ಲಟà²à³ ಮಟಡಲಟà²à²¿à²Šà³"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à²à³à²°à³à²€à²¿à²žà²²à²Ÿà²à²¿à²²à³à²²"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 6304539..8d86a8d 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"볎ì ê°í륌 ìíŽ ëì íšíŽ ì¬ì©"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"볎ì ê°í륌 ìíŽ ëì PIN ì¬ì©"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"볎ì ê°í륌 ìíŽ ëì ë¹ë°ë²íž ì¬ì©"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"볎ì ê°í륌 ìíŽ PINìŽ íìí©ëë€."</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"볎ì ê°í륌 ìíŽ íšíŽìŽ íìí©ëë€."</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"볎ì ê°í륌 ìíŽ ë¹ë°ë²ížê° íìí©ëë€."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"êŽëЬìê° êž°êž°ë¥Œ ì ê°ìµëë€."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"êž°êž°ê° ìëìŒë¡ ì êž ì€ì ëììµëë€."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ìžìí ì ìì"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 8575d60..6bfbd64 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÐПÑÑÐŒÑа кППпÑÑзЎÑк Ò¯ÑүМ аМÑМ ПÑÐŽÑМа гÑаÑОкалÑк аÑкÑÑÑÑ ÐºÐŸÐ»ÐŽÐŸÐœÑÒ£Ñз"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÐПÑÑÐŒÑа кППпÑÑзЎÑк Ò¯ÑүМ аМÑМ ПÑÐŽÑМа PIN ÐºÐŸÐŽÐŽÑ ÐºÐŸÐ»ÐŽÐŸÐœÑÒ£Ñз"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÐПÑÑÐŒÑа кППпÑÑзЎÑк Ò¯ÑүМ аМÑМ ПÑÐŽÑМа ÑÑÑÑөзЎү кПлЎПМÑÒ£Ñз"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÐППпÑÑзЎÑкÑÑ Ð±ÐµÐºÐµÐŒÐŽÓ©Ó© Ò¯ÑүМ PIN кПЎ Ñалап кÑлÑМаÑ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÐППпÑÑзЎÑкÑÑ Ð±ÐµÐºÐµÐŒÐŽÓ©Ó© Ò¯ÑүМ гÑаÑОкалÑк аÑкÑÑ Ñалап кÑлÑМаÑ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÐППпÑÑзЎÑкÑÑ Ð±ÐµÐºÐµÐŒÐŽÓ©Ó© Ò¯ÑүМ ÑÑÑÑөз Ñалап кÑлÑМаÑ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ТүзЌөкÑÒ¯ аЎЌОМОÑÑÑаÑÐŸÑ ÐºÑлпÑлап кПйгПМ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ТүзЌөк кПл ЌеМеМ кÑлпÑлаМЎÑ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ТааМÑлгаМ жПк"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 984cc56..d567794 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡, à»àº«à»à»àºà»àº®àº¹àºà»àºàºà»àºàº"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡, à»àº«à»à»àºà» PIN à»àºàº"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡, à»àº«à»à»àºà»àº¥àº°àº«àº±àºàºà»àº²àºà»àºàº"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àºàº³à»àºàº±àºàºà»àºàºàº¡àºµ PIN à»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àºàº³à»àºàº±àºàºà»àºàºàº¡àºµà»àºàºàº®àº¹àºà»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àºàº³à»àºàº±àºàºà»àºàºàº¡àºµàº¥àº°àº«àº±àºàºà»àº²àºà»àºàº·à»àºàºàº§àº²àº¡àºàºàºà»àºà»àºàºµà»àº¡à»àºàºµàº¡"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àºàºžàºàº°àºàºàºàºàº·àºàº¥àº±àºàºà»àºàºàºàº¹à»à»àºàºŽà»àºà»àºàºàº¥àº°àºàº»àº"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àºàºžàºàº°àºàºàºàºàº·àºàºªàº±à»àºà»àº«à»àº¥àº±àºàº"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àºà»à»àº®àº¹à»àºàº±àº"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 96dc266..0cf3294 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildomai saugai uÅŸtikrinti geriau naudokite atrakinimo piešinį"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildomai saugai uÅŸtikrinti geriau naudokite PIN kodÄ
"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildomai saugai uştikrinti geriau naudokite slaptaşodį"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Norint uÅŸtikrinti papildomÄ
saugÄ
būtinas PIN kodas"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Norint uÅŸtikrinti papildomÄ
saugÄ
bÅ«tinas atrakinimo piešinys"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Norint uÅŸtikrinti papildomÄ
saugÄ
būtinas slaptaşodis"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Įrenginį uşrakino administratorius"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ä®renginys uÅŸrakintas neautomatiškai"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"NeatpaÅŸinta"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 9ca5c6e..da1f62c 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildu drošÄ«bai izmantojiet kombinÄciju"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildu drošÄ«bai izmantojiet PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildu drošÄ«bai izmantojiet paroli"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Papildu drošÄ«bai ir jÄievada PIN kods"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Papildu drošÄ«bai ir jÄievada atbloÄ·Äšanas kombinÄcija"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Papildu drošÄ«bai ir jÄievada parole"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrators bloÄ·Äja ierÄ«ci."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"IerÄ«ce tika bloÄ·Äta manuÄli."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nav atpazīts"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 421637f..3e110b5 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ðа ЎПпПлМОÑелМа безбеЎМПÑÑ, кПÑОÑÑеÑе ÑеЌа"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ðа ЎПпПлМОÑелМа безбеЎМПÑÑ, кПÑОÑÑеÑе PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ðа ЎПпПлМОÑелМа безбеЎМПÑÑ, кПÑОÑÑеÑе лПзОМка"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÐПÑÑебеМ е PIN за ЎПпПлМОÑелМа безбеЎМПÑÑ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÐПÑÑебМа е ÑеЌа за ЎПпПлМОÑелМа безбеЎМПÑÑ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÐПÑÑебМа е лПзОМка за ЎПпПлМОÑелМа безбеЎМПÑÑ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"УÑÐµÐŽÐŸÑ Ðµ заклÑÑеМ ПЎ аЎЌОМОÑÑÑаÑПÑПÑ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"УÑÐµÐŽÐŸÑ Ðµ заклÑÑеМ ÑаÑМП"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ÐепПзМаÑ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 9bb1c60..2861d7c 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàŽŸàŽ¯àŽ¿, àŽªàŽàŽ°àŽ àŽªàŽŸàŽ±àµàޱàµàµº àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµàŽ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàŽŸàŽ¯àŽ¿, àŽªàŽàŽ°àŽ àŽªàŽ¿àµ» àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµàŽ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàŽŸàŽ¯àŽ¿, àŽªàŽàŽ°àŽ àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµàŽ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàµ àŽªàŽ¿àµ» àŽàŽµàŽ¶àµàŽ¯àŽ®àŽŸàŽ£àµ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàµ àŽªàŽŸàŽ±àµàޱàµàµº àŽàŽµàŽ¶àµàŽ¯àŽ®àŽŸàŽ£àµ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àŽ
àŽ§àŽ¿àŽ àŽžàµàްàŽàµàŽ·àŽ¯àµàŽàµàŽàµ àŽªàŽŸàŽžàµà޵àµàŽ¡àµ àŽàŽµàŽ¶àµàŽ¯àŽ®àŽŸàŽ£àµ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àŽàŽªàŽàŽ°àŽ£àŽ àŽ
àŽ¡àµàŽ®àŽ¿àµ» àŽ²àµàŽàµàŽàµàŽàµàޝàµàŽ€àµ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àŽàŽªàŽàŽ°àŽ£àŽ àŽšàµàŽ°àŽ¿àŽàµàŽàµ àŽ²àµàŽàµàŽàµàŽàµàޝàµàŽ€àµ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àŽ€àŽ¿àŽ°àŽ¿àŽàµàŽàŽ±àŽ¿àŽ¯àµàŽšàµàŽšàŽ¿àŽ²àµà޲"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 443e028..83ce698 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ ÐŸÑПМЎ ÐœÑ Ñ
ÑÑ Ð°ÑОглаМа ÑÑ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ ÐŸÑПМЎ ÐœÑ ÐÐРаÑОглаМа ÑÑ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ ÐŸÑПМЎ ÐœÑ ÐœÑÑÑ Ò¯Ð³ аÑОглаМа ÑÑ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ ÐÐÐ ÑааÑЎлагаÑай"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ Ñ
ÑÑ ÑааÑЎлагаÑай"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÐÑÐŒÑÐ»Ñ Ð°ÑÑлгүй байЎлÑМ үүЎМÑÑÑ ÐœÑÑÑ Ò¯Ð³ ÑааÑЎлагаÑай"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÐЎЌОМ ÑÓ©Ñ
Ó©Ó©ÑөЌжОйг ÑүгжÑÑМ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ТөÑ
Ó©Ó©ÑөЌжОйг гаÑÐ°Ð°Ñ ÑүгжÑÑМ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ТаМÑж ÑаЎÑаМгүй"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 8b23abe8..3f65cdb 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥, à€€à¥à€¯à€Ÿà€à€µà€à¥ à€ªà¥
à€à€°à¥à€š à€µà€Ÿà€ªà€°à€Ÿ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥, à€€à¥à€¯à€Ÿà€à€µà€à¥ à€ªà€¿à€š à€µà€Ÿà€ªà€°à€Ÿ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥, à€€à¥à€¯à€Ÿà€à€µà€à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€µà€Ÿà€ªà€°à€Ÿ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥ à€ªà€¿à€š à€à€µà€¶à¥à€¯à€ à€à€¹à¥"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥ à€ªà¥
à€à€°à¥à€š à€à€µà€¶à¥à€¯à€ à€à€¹à¥"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à¥à€žà€Ÿà€ à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à€µà€¶à¥à€¯à€ à€à€¹à¥"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"à€ªà¥à€°à€¶à€Ÿà€žà€à€Ÿà€Šà¥à€µà€Ÿà€°à¥ à€²à¥à€ à€à¥à€²à¥à€²à¥ à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž à€®à¥
à€šà¥à€¯à¥à€
à€²à¥ à€²à¥à€ à€à¥à€²à¥ à€¹à¥à€€à¥"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à€à€³à€à€²à¥ à€šà€Ÿà€¹à¥"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 3291bd4..ecf843d 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keselamatan tambahan, gunakan corak"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keselamatan tambahan, gunakan PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keselamatan tambahan, gunakan kata laluan"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN diperlukan untuk keselamatan tambahan"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Corak diperlukan untuk keselamatan tambahan"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Kata laluan diperlukan untuk keselamatan tambahan"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Peranti dikunci oleh pentadbir"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Peranti telah dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 9d83323..95d638e 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"áááºáá±á¬ááºážáá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠáááºážá¡á
á¬áž áá¯á¶á
á¶áá¯á¶ážáá«"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"áááºáá±á¬ááºážáá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠáááºážá¡á
á¬áž áááºáá¶áá«ááºáá¯á¶ážáá«"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"áááºáá±á¬ááºážáá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠáááºážá¡á
á¬áž á
áá¬ážááŸááºáá¯á¶ážáá«"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"áááºáá±á¬ááºáž áá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠáááºáá¶áá«áẠááá¯á¡ááºáááº"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"áááºáá±á¬ááºáž áá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠáá¯á¶áá±á¬áºááŒááºáž ááá¯á¡ááºáááº"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"áááºáá±á¬ááºáž áá¯á¶ááŒá¯á¶áá±ážá¡ááœáẠá
áá¬ážááŸáẠááá¯á¡ááºáááº"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"á
ááºáá
á¹á
ááºážááᯠá
á®áá¶ááá·áºááœá²áá°á áá±á¬á·ááºáá»áá¬ážáá«áááº"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"á
ááºáá
á¹á
ááºážááᯠááá¯ááºááá¯ááºááá¯ááºáá» áá±á¬á·ááºáá»áá¬ážáá²á·áááº"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ááá"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 1aefaa9..b6aa09d 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Bruk mønster i stedet, for å øke sikkerheten"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Bruk PIN-kode i stedet, for å øke sikkerheten"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Bruk passord i stedet, for å øke sikkerheten"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Du må skrive inn PIN-koden for ekstra sikkerhet"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Du må tegne mønsteret for ekstra sikkerhet"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Du må skrive inn passordet for ekstra sikkerhet"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheten er låst av administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten ble låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke gjenkjent"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 16d23ef..219072b 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€¯à¥ à€ªà¥à€°à€®à€Ÿà€£à¥à€à€°à€£ à€µà€¿à€§à€¿à€à¥ à€žà€Ÿà€à¥ à€ªà¥à€¯à€Ÿà€à€°à¥à€š à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€¯à¥ à€ªà¥à€°à€®à€Ÿà€£à¥à€à€°à€£ à€µà€¿à€§à€¿à€à¥ à€žà€Ÿà€à¥ à€ªà€¿à€š à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€¯à¥ à€ªà¥à€°à€®à€Ÿà€£à¥à€à€°à€£ à€µà€¿à€§à€¿à€à¥ à€žà€Ÿà€à¥ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ PIN à€à€Ÿà€¹à€¿à€šà¥à€"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€ªà¥à€¯à€Ÿà€à€°à¥à€š à€à€Ÿà€¹à€¿à€šà¥à€"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à€
à€€à€¿à€°à€¿à€à¥à€€ à€žà¥à€°à€à¥à€·à€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€ªà€Ÿà€žà€µà€°à¥à€¡ à€à€Ÿà€¹à€¿à€šà¥à€"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"à€ªà¥à€°à€¶à€Ÿà€žà€à€²à¥ à€¯à€šà¥à€€à¥à€°à€²à€Ÿà€ à€²à€ à€à€°à¥à€šà¥à€à€à€à¥ à€"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"à€¯à€šà¥à€€à¥à€°à€²à€Ÿà€ à€®à¥à€¯à€Ÿà€šà¥à€
à€² à€€à€°à€¿à€à€Ÿà€²à¥ à€²à€ à€à€°à€¿à€à€à¥ à€¥à€¿à€¯à¥"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à€ªà€¹à€¿à€à€Ÿà€š à€à€à€š"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 77b5b57..81e1007 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik in plaats daarvan het patroon voor extra beveiliging"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik de pincode voor extra beveiliging"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik in plaats daarvan het wachtwoord voor extra beveiliging"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Pincode vereist voor extra beveiliging"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Patroon vereist voor extra beveiliging"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Wachtwoord vereist voor extra beveiliging"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Apparaat vergrendeld door beheerder"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Apparaat is handmatig vergrendeld"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Niet herkend"</string>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 73ed727..bb3da3a 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬, à¬à¬¹à¬Ÿ ପରିବରà଀à଀à ପଟà¬à¬°àଚ ବààବହଟର à¬à¬°à¬šà଀à"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬, à¬à¬¹à¬Ÿ ପରିବରà଀à଀à PIN ବààବହଟର à¬à¬°à¬šà଀à"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬, à¬à¬¹à¬Ÿ ପରିବରà଀à଀à ପଟଞà±à¬Ÿà¬°àଡ ବààବହଟର à¬à¬°à¬šà଀à"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬ PIN à¬à¬¬à¬¶ààଠà¬
à¬à"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬ ପଟà¬à¬°àଚ à¬à¬¬à¬¶ààà¬"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à¬
଀ିରିà¬à଀ ଞàରà¬àଷଟ ପଟà¬à¬ ପଟଞàà±à¬°àଡ à¬à¬¬à¬¶ààà¬"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ଡିà¬à¬Ÿà¬à¬žà à¬à¬¡à¬®à¬¿à¬šà¬àଠଊàà±à¬Ÿà¬°à¬Ÿ ଲà¬à à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ଡିà¬à¬Ÿà¬à¬žà ମଟଚàà¬à¬² à¬à¬Ÿà¬¬à ଲà¬à à¬à¬°à¬Ÿà¬à¬²à¬Ÿ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à¬à¬¿à¬¹àଚଠହàଲଟଚଟହିà¬"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 2e4d190..f0d9596 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš, àšàšžàšŠà© àš¬àšàšŸàš àšªà©àšàš°àšš àšµàš°àš€à©"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš, àšàšžàšŠà© àš¬àšàšŸàš àšªàš¿à©°àšš àšµàš°àš€à©"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš, àšàšžàšŠà© àš¬àšàšŸàš àšªàšŸàšžàšµàš°àš¡ àšµàš°àš€à©"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš àšªàš¿à©°àšš àšŠà© àš²à©à© àš¹à©"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš àšªà©àšàš°àšš àšŠà© àš²à©à© àš¹à©"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àšµàš§à©àš àšžà©àš°à©±àšàš¿àš àš²àš àšªàšŸàšžàšµàš°àš¡ àšŠà© àš²à©à© àš¹à©"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àšªà©àš°àšžàšŒàšŸàšžàš àšµà©±àš²à©àš àš¡à©àšµàšŸàšàšž àššà©à©° àš²àšŸàš àšà©àš€àšŸ àšàš¿àš"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àš¡à©àšµàšŸàšàšž àššà©à©° àš¹à©±àš¥à©àš àš²àšŸàš àšà©àš€àšŸ àšàš¿àš"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"àšªàšàšŸàš£ àššàš¹à©àš àš¹à©àš"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 92cee60..e04cef1 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"O PIN é necessário para aumentar a segurança"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"O padrão é necessário para aumentar a segurança"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"A senha é necessária para aumentar a segurança"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index cc5ccd8..1ae1aeb 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para uma segurança adicional, use antes o padrão"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para uma segurança adicional, use antes o PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para uma segurança adicional, use antes a palavra-passe"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Para segurança adicional, é necessária um PIN"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Para segurança adicional, é necessário um padrão"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Para segurança adicional, é necessária uma palavra-passe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo gestor"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 92cee60..e04cef1 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"O PIN é necessário para aumentar a segurança"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"O padrão é necessário para aumentar a segurança"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"A senha é necessária para aumentar a segurança"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado pelo administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 7d07480..bc74e0a 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pentru mai multÄ securitate, foloseÈte modelul"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pentru mai multÄ securitate, foloseÈte codul PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pentru mai multÄ securitate, foloseÈte parola"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Codul PIN este necesar pentru securitate suplimentarÄ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Modelul este necesar pentru securitate suplimentarÄ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Parola este necesarÄ pentru securitate suplimentarÄ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispozitiv blocat de administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Dispozitivul a fost blocat manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nu este recunoscut"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index d91cf97..aa2d080 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ð ÑелÑÑ
ЎПпПлМОÑелÑМПй безПпаÑМПÑÑО ОÑпПлÑзÑйÑе гÑаÑОÑеÑкОй клÑÑ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ð ÑелÑÑ
ЎПпПлМОÑелÑМПй безПпаÑМПÑÑО ОÑпПлÑзÑйÑе PIN-кПЎ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ð ÑелÑÑ
ЎПпПлМОÑелÑМПй безПпаÑМПÑÑО ОÑпПлÑзÑйÑе паÑПлÑ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Ð ÑелÑÑ
безПпаÑМПÑÑО ввеЎОÑе PIN-кПЎ."</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Ð ÑелÑÑ
безПпаÑМПÑÑО ввеЎОÑе гÑаÑОÑеÑкОй клÑÑ."</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Ð ÑелÑÑ
безПпаÑМПÑÑО ввеЎОÑе паÑПлÑ."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"УÑÑÑПйÑÑвП заблПкОÑПваМП аЎЌОМОÑÑÑаÑПÑПЌ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"УÑÑÑПйÑÑвП бÑлП заблПкОÑПваМП вÑÑÑМÑÑ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ðе ÑаÑпПзМаМП"</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index a9fc70a..343902a 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à¶
à¶à·à¶»à·à¶ à¶à¶»à¶à·à·à·à· à·à¶³à·à·, à¶ à·à·à¶±à·à·à¶§ රටà·à· à¶·à·à·à·à¶à· à¶à¶»à¶±à·à¶±"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à¶
à¶à·à¶»à·à¶ à¶à¶»à¶à·à·à·à· à·à¶³à·à·, à¶ à·à·à¶±à·à·à¶§ PIN à¶·à·à·à·à¶à· à¶à¶»à¶±à·à¶±"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à¶
à¶à·à¶»à·à¶ à¶à¶»à¶à·à·à·à· à·à¶³à·à·, à¶ à·à·à¶±à·à·à¶§ à¶žà·à¶»à¶Žà¶¯à¶º à¶·à·à·à·à¶à· à¶à¶»à¶±à·à¶±"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à¶
à¶žà¶à¶» à¶à¶»à¶à·à·à·à· à·à¶³à·à· PIN à¶
à¶à¶à¶º à¶
à·à·à·à¶ºà¶ºà·"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à¶
à¶žà¶à¶» à¶à¶»à¶à·à·à·à· à·à¶³à·à· රටà·à· à¶
à·à·à·à¶ºà¶ºà·"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à¶
à¶žà¶à¶» à¶à¶»à¶à·à·à·à· à·à¶³à·à· à¶žà·à¶»à¶Žà¶¯à¶º à¶
à·à·à·à¶ºà¶ºà·"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"à¶à¶¶à¶à· à¶Žà¶»à·à¶Žà·à¶œà¶ à·à·à·à·à¶±à· à¶à¶Žà·à¶à¶à¶º à¶
à¶à·à·
෠දඞ෠à¶à¶"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"à¶à¶Žà·à¶à¶à¶º à·à·à·à¶à·à¶ºà· à¶
à¶à·à¶œà· දඞන ගදà·"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à·à¶³à·à¶±à· à¶±à·à¶à¶±à·à¶±à· ගදà·"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index e1b83ee..5725fe0 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"V rámci zvýšenia zabezpeÄenia pouÅŸite radšej vzor"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"V rámci zvýšenia zabezpeÄenia pouÅŸite radšej PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"V rámci zvýšenia zabezpeÄenia pouÅŸite radšej heslo"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Zvýšenie zabezpeÄenia vyÅŸaduje kód PIN"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Zvýšenie zabezpeÄenia vyÅŸaduje vzor"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Zvýšenie zabezpeÄenia vyÅŸaduje heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zariadenie zamkol správca"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zariadenie bolo uzamknuté ruÄne"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznané"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 383153b..c761799 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatno varnost raje uporabite vzorec."</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatno varnost raje uporabite kodo PIN."</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatno varnost raje uporabite geslo."</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Zaradi dodatne varnosti morate vnesti kodo PIN"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Zaradi dodatne varnosti morate vnesti vzorec"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Zaradi dodatne varnosti morate vnesti geslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Napravo je zaklenil skrbnik"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Naprava je bila roÄno zaklenjena"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ni prepoznano"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 9f291f3..be1d4aa 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Për më shumë siguri, përdor motivin më mirë"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Për më shumë siguri, përdor kodin PIN më mirë"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Për më shumë siguri, përdor fjalëkalimin më mirë"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Kërkohet kodi PIN për më shumë siguri"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Kërkohet motivi për më shumë siguri"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Kërkohet fjalëkalimi për më shumë siguri"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Pajisja është e kyçur nga administratori"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Pajisja është kyçur manualisht"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nuk njihet"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 404ff9d..34c9311 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ðа ЎПЎаÑÐœÑ Ð±ÐµÐ·Ð±ÐµÐŽÐœÐŸÑÑ ÐºÐŸÑОÑÑОÑе ÑаблПМ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ðа ЎПЎаÑÐœÑ Ð±ÐµÐ·Ð±ÐµÐŽÐœÐŸÑÑ ÐºÐŸÑОÑÑОÑе PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ðа ЎПЎаÑÐœÑ Ð±ÐµÐ·Ð±ÐµÐŽÐœÐŸÑÑ ÐºÐŸÑОÑÑОÑе лПзОМкÑ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ТÑеба Ўа ÑМеÑеÑе PIN ÑаЎО ЎПЎаÑМе безбеЎМПÑÑО"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ТÑеба Ўа ÑМеÑеÑе ÑаблПМ ÑаЎО ЎПЎаÑМе безбеЎМПÑÑО"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ТÑеба Ўа ÑМеÑеÑе Ð»ÐŸÐ·ÐžÐœÐºÑ ÑаЎО ЎПЎаÑМе безбеЎМПÑÑО"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÐЎЌОМОÑÑÑаÑÐŸÑ Ñе закÑÑÑаП ÑÑеÑаÑ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"УÑеÑÐ°Ñ Ñе ÑÑÑМП закÑÑÑаМ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ÐОÑе пÑепПзМаÑ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index b891de7..3a89ff5 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"För ytterligare säkerhet använder du mönstret i stället"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"För ytterligare säkerhet använder du pinkoden i stället"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"För ytterligare säkerhet använder du lösenordet i stället"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Du måste ange en pinkod för ytterligare säkerhet"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Du måste ange ett mönster för ytterligare säkerhet"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Du måste ange ett lösenord för ytterligare säkerhet"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten har låsts manuellt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Identifierades inte"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 7dd3180..20080a3 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kwa usalama wa ziada, tumia mchoro badala yake"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kwa usalama wa ziada, tumia PIN badala yake"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kwa usalama wa ziada, tumia nenosiri badala yake"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN inahitajika ili kuongeza usalama"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Mchoro unahitajika ili kuongeza usalama"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Nenosiri linahitajika ili kuongeza usalama"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Msimamizi amefunga kifaa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Umefunga kifaa mwenyewe"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Haitambuliwi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 14969d5..60f60c4 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®ªà¯ பà¯à®à¯à®à®°à¯à®©à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à®µà¯à®®à¯"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®ªà¯ பினà¯à®©à¯ (PIN) பயனà¯à®ªà®à¯à®€à¯à®€à®µà¯à®®à¯"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®à¯ à®à®à®µà¯à®à¯à®à¯à®²à¯à®²à¯à®ªà¯ பயனà¯à®ªà®à¯à®€à¯à®€à®µà¯à®®à¯"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®ªà¯ பின௠஀à¯à®µà¯"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®ªà¯ பà¯à®à¯à®à®°à¯à®©à¯ ஀à¯à®µà¯"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à®à¯à®à¯à®€à®²à¯ பட஀à¯à®à®Ÿà®ªà¯à®ªà®¿à®±à¯à®à¯à®à¯ à®à®à®µà¯à®à¯à®à¯à®²à¯ ஀à¯à®µà¯"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"சிரà¯à®µà®Ÿà®à®¿ à®à®Ÿà®€à®©à®€à¯à®€à¯à®ªà¯ பà¯à®à¯à®à®¿à®¯à¯à®³à¯à®³à®Ÿà®°à¯"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"பயனர௠à®à®Ÿà®€à®©à®€à¯à®€à¯à®ªà¯ பà¯à®à¯à®à®¿à®¯à¯à®³à¯à®³à®Ÿà®°à¯"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à®
à®à¯à®¯à®Ÿà®³à®à¯à®à®Ÿà®£à®ªà®à®µà®¿à®²à¯à®²à¯"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index a117a5c..0a6476fc 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà°, బఊà±à°²à±à°à°Ÿ à°à°à±à°€à°¿à°šà°¿ à°à°ªà°¯à±à°à°¿à°à°à°à°¡à°¿"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà°, బఊà±à°²à±à°à°Ÿ PINà°šà± à°à°ªà°¯à±à°à°¿à°à°à°à°¡à°¿"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà°, బఊà±à°²à±à°à°Ÿ పటఞà±à°µà°°à±à°¡à±à°šà± à°à°ªà°¯à±à°à°¿à°à°à°à°¡à°¿"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà° PIN à°à°à°à°°à± à°à±à°¯à°Ÿà°²à°¿"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà° à°à°à±à°€à°¿ à°
వఞరà°"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"à°
ఊచపౠఞà±à°à±à°¯à±à°°à°¿à°à± à°à±à°žà° పటఞà±à°µà°°à±à°¡à±à°šà± à°à°à°à°°à± à°à±à°¯à°Ÿà°²à°¿"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"పరిà°à°°à° à°šà°¿à°°à±à°µà°Ÿà°¹à°à±à°² à°Šà±à°µà°Ÿà°°à°Ÿ లటà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"పరిà°à°°à° మటచà±à°¯à±à°µà°²à±à°à°Ÿ లటà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à°à±à°°à±à°€à°¿à°à°à°²à±à°Šà±"</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index d9f8d99..96b3a46 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"à¹àžà¹àž£àž¹àžà¹àžàžà¹àžàžà¹àžàž·à¹àžà¹àžàžŽà¹àž¡àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"à¹àžà¹ PIN à¹àžàžà¹àžàž·à¹àžà¹àžàžŽà¹àž¡àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"à¹àžà¹àž£àž«àž±àžªàžà¹àž²àžà¹àžàžà¹àžàž·à¹àžà¹àžàžŽà¹àž¡àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"àžà¹àžàžàž£àž°àžàžž PIN à¹àžàž·à¹àžà¹àžà¹àžàžàž²àž£àž£àž±àžàž©àž²àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢à¹àžàžŽà¹àž¡à¹àžàžŽàž¡"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"àžà¹àžàžà¹àžà¹àž£àž¹àžà¹àžàžà¹àžàž·à¹àžà¹àžà¹àžàžàž²àž£àž£àž±àžàž©àž²àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢à¹àžàžŽà¹àž¡à¹àžàžŽàž¡"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"àžà¹àžàžàžà¹àžàžàž£àž«àž±àžªàžà¹àž²àžà¹àžàž·à¹àžà¹àžà¹àžàžàž²àž£àž£àž±àžàž©àž²àžàž§àž²àž¡àžàž¥àžàžàž àž±àž¢à¹àžàžŽà¹àž¡à¹àžàžŽàž¡"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"àžàž¹à¹àžàž¹à¹àž¥àž£àž°àžàžàž¥à¹àžàžàžàžžàžàžàž£àžà¹"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"àž¡àžµàžàž²àž£àž¥à¹àžàžàžàžžàžàžàž£àžà¹àžà¹àž§àž¢àžàž±àž§à¹àžàž"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"à¹àž¡à¹àž£àž¹à¹àžàž±àžàž¥àž²àž¢àžàžŽà¹àž§àž¡àž·àž"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index e23d036..84c32ee 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ek güvenlik için bunun yerine desen kullanın"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ek güvenlik için bunun yerine PIN kullanın"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ek güvenlik için bunun yerine Åifre kullanın"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Ek güvenlik için PIN gerekir"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Ek güvenlik için desen gerekir"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Ek güvenlik için Åifre gerekir"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz, yönetici tarafından kilitlendi"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihazın manuel olarak kilitlendi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmadı"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index d519601..6e8c11f 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ð ÐŒÑÑкÑÐ²Ð°ÐœÑ ÐŽÐŸÐŽÐ°ÑÐºÐŸÐ²ÐŸÑ Ð±ÐµÐ·Ð¿ÐµÐºÐž ÑкПÑОÑÑайÑеÑÑ ÐºÐ»ÑÑеЌ"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ð ÐŒÑÑкÑÐ²Ð°ÐœÑ ÐŽÐŸÐŽÐ°ÑÐºÐŸÐ²ÐŸÑ Ð±ÐµÐ·Ð¿ÐµÐºÐž ÑкПÑОÑÑайÑеÑÑ PIN-кПЎПЌ"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ð ÐŒÑÑкÑÐ²Ð°ÐœÑ ÐŽÐŸÐŽÐ°ÑÐºÐŸÐ²ÐŸÑ Ð±ÐµÐ·Ð¿ÐµÐºÐž ÑкПÑОÑÑайÑеÑÑ Ð¿Ð°ÑПлеЌ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ÐÐ»Ñ ÐŽÐŸÐŽÐ°ÑкПвПгП заÑ
ОÑÑÑ Ð¿ÐŸÑÑÑбМП ввеÑÑО PIN-кПЎ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"ÐÐ»Ñ ÐŽÐŸÐŽÐ°ÑкПвПгП заÑ
ОÑÑÑ Ð¿ÐŸÑÑÑбМП ввеÑÑО клÑÑ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ÐÐ»Ñ ÐŽÐŸÐŽÐ°ÑкПвПгП заÑ
ОÑÑÑ Ð¿ÐŸÑÑÑбМП ввеÑÑО паÑПлÑ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ÐÐŽÐŒÑМÑÑÑÑаÑÐŸÑ Ð·Ð°Ð±Ð»ÐŸÐºÑвав пÑОÑÑÑÑй"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ÐÑОÑÑÑÑй заблПкПваМП вÑÑÑМÑ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ðе ÑПзпÑзМаМП"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 27d422f..fa2a234 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©Û ÙØŠÛØ Ø§Ø³ Ú©Û ØšØ¬Ø§ØŠÛ ÙŸÛٹر٠استعÙ
ا٠کرÛÚº"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©Û ÙØŠÛØ Ø§Ø³ Ú©Û ØšØ¬Ø§ØŠÛ PIN استعÙ
ا٠کرÛÚº"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©Û ÙØŠÛØ Ø§Ø³ Ú©Û ØšØ¬Ø§ØŠÛ ÙŸØ§Ø³ ÙØ±Ú استعÙ
ا٠کرÛÚº"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©ÛÙØŠÛ PIN درکار ÛÛ"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©ÛÙØŠÛ ÙŸÛٹر٠درکار ÛÛ"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"اضاÙÛ Ø³ÛÚ©ÛÙØ±Ù¹Û Ú©ÛÙØŠÛ ٟاس ÙØ±Ú درکار ÛÛ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Ø¢ÙÛ Ù
ÙØªØžÙ
Ú©Û Ø¬Ø§ÙØš Ø³Û Ù
ÙÙÙ ÛÛ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ø¢ÙÛ Ú©Ù Ø¯Ø³ØªÛ Ø·ÙØ± ٟر Ù
ÙÙÙ Ú©ÛØ§ Ú¯ÛØ§ تڟا"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"تسÙÛÙ
ØŽØ¯Û ÙÛÛÚº ÛÛ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index c34619f..85eb52f 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Qoʻshimcha xavfsizlik maqsadida oʻrniga grafik kalitdan foydalaning"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Qoʻshimcha xavfsizlik maqsadida oʻrniga PIN koddan foydalaning"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Qoʻshimcha xavfsizlik maqsadida oʻrniga paroldan foydalaning"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Qoʻshimcha xavfsizlik chorasi sifatida PIN kod talab qilinadi"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Qoʻshimcha xavfsizlik chorasi sifatida grafik kalit talab qilinadi"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Qoʻshimcha xavfsizlik chorasi sifatida parol talab qilinadi"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Qurilma administrator tomonidan bloklangan"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Qurilma qo‘lda qulflangan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Aniqlanmadi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 52b71a7..bbd319c3 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Äá» tÄng cưá»ng bảo máºt, hãy sá» dụng hình má» khoá"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Äá» tÄng cưá»ng bảo máºt, hãy sá» dụng mã PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Äá» tÄng cưá»ng bảo máºt, hãy sá» dụng máºt khẩu"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Yêu cầu mã PIN Äá» tÄng cưá»ng bảo máºt"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Yêu cầu hình má» khoá Äá» tÄng cưá»ng bảo máºt"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Yêu cầu máºt khẩu Äá» tÄng cưá»ng bảo máºt"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Thiết bá» Äã bá» quản trá» viên khóa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Thiết bá» Äã bá» khóa theo cách thá»§ công"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Không nháºn dạng ÄÆ°á»£c"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 70a9117..a316e8c 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"䞺å¢åŒºå®å
šæ§ïŒè¯·æ¹çšåŸæ¡"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"䞺å¢åŒºå®å
šæ§ïŒè¯·æ¹çš PIN ç "</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"䞺å¢åŒºå®å
šæ§ïŒè¯·æ¹çšå¯ç "</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"éèŠèŸå
¥ PIN ç 以è¿äžæ¥ç¡®ä¿å®å
š"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"éèŠç»å¶è§£éåŸæ¡ä»¥è¿äžæ¥ç¡®ä¿å®å
š"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"éèŠèŸå
¥å¯ç 以è¿äžæ¥ç¡®ä¿å®å
š"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管çåå·²éå®è®Ÿå€"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"æ€è®Ÿå€å·²æåšéå®"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"æ æ³è¯å«"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index d1e70f4..abef8df 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"çºæåå®å
šæ§ïŒè«æ¹çšåæ¡"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"çºæåå®å
šæ§ïŒè«æ¹çš PIN"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"çºæåå®å
šæ§ïŒè«æ¹çšå¯ç¢Œ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"è«åå¿
茞å
¥ PINïŒä»¥é²äžæ¥ç¢ºä¿å®å
š"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"è«åå¿
ç«åºäžéåæ¡ïŒä»¥é²äžæ¥ç¢ºä¿å®å
š"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"è«åå¿
茞å
¥å¯ç¢ŒïŒä»¥é²äžæ¥ç¢ºä¿å®å
š"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"è£çœ®å·²ç±ç®¡çå¡éå®"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"䜿çšè
å·²æåå°è£çœ®äžé"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"æªèœèå¥"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index bd223d6..7e5ae10 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"çºåŒ·åå®å
šæ§ïŒè«æ¹çšè§£éåæ¡"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"çºåŒ·åå®å
šæ§ïŒè«æ¹çš PIN 碌"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"çºåŒ·åå®å
šæ§ïŒè«æ¹çšå¯ç¢Œ"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"è«èŒžå
¥ PIN 碌ïŒå 匷å®å
šé²è·"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"è«ç«åºè§£éåæ¡ïŒå 匷å®å
šé²è·"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"è«èŒžå
¥å¯ç¢ŒïŒå 匷å®å
šé²è·"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管çå¡å·²éå®è£çœ®"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"è£çœ®å·²æåéå®"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ç¡æ³èå¥"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index ccc1606..e4c3cbf 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -111,12 +111,9 @@
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphetheni esikhundleni salokho"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa i-PIN esikhundleni salokho"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphasiwedi esikhundleni salokho"</string>
- <!-- no translation found for kg_prompt_added_security_pin (5487992065995475528) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_pattern (1017068086102168544) -->
- <skip />
- <!-- no translation found for kg_prompt_added_security_password (6053156069765029006) -->
- <skip />
+ <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Kudingeka iphinikhodi ngokuvikeleka okwengeziwe"</string>
+ <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Kudingeka iphethini ngokuvikeleka okwengeziwe"</string>
+ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Iphasiwedi idingelwa ukuvikeleka okwengeziwe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Idivayisi ikhiywe ngumlawuli"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Idivayisi ikhiywe ngokwenza"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Akwaziwa"</string>
diff --git a/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml b/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml
new file mode 100644
index 0000000..fdafe6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
+ <corners android:radius="@dimen/biometric_prompt_content_corner_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml
index 24222f7..1517f83 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml
@@ -53,6 +53,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+ <LinearLayout
+ android:id="@+id/customized_view_container"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_below="@id/subtitle"
+ android:layout_alignParentLeft="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
</RelativeLayout>
<FrameLayout
diff --git a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
index d5af377..dd0c584 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
@@ -60,6 +60,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
+ <LinearLayout
+ android:id="@+id/customized_view_container"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_below="@id/subtitle"
+ android:layout_alignParentLeft="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
<TextView
android:id="@+id/error"
style="?errorTextAppearanceLand"
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index 2d63c8d..1777bdf 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -2,6 +2,8 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+android:id="@+id/biometric_prompt_constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -19,7 +21,7 @@
android:id="@+id/panel"
android:layout_width="0dp"
android:layout_height="0dp"
- android:background="?android:attr/colorBackgroundFloating"
+ android:background="?androidprv:attr/materialColorSurfaceBright"
android:clickable="true"
android:clipToOutline="true"
android:importantForAccessibility="no"
@@ -74,8 +76,9 @@
<ImageView
android:id="@+id/logo"
- android:layout_width="@dimen/biometric_auth_icon_size"
- android:layout_height="@dimen/biometric_auth_icon_size"
+ android:contentDescription="@string/biometric_dialog_logo"
+ android:layout_width="@dimen/biometric_prompt_logo_size"
+ android:layout_height="@dimen/biometric_prompt_logo_size"
android:layout_gravity="center"
android:scaleType="fitXY"
android:visibility="visible"
@@ -84,12 +87,9 @@
<TextView
android:id="@+id/logo_description"
+ style="@style/TextAppearance.AuthCredential.LogoDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:marqueeRepeatLimit="1"
- android:singleLine="true"
android:textAlignment="viewStart"
android:paddingLeft="8dp"
app:layout_constraintBottom_toBottomOf="@+id/logo"
@@ -97,12 +97,6 @@
app:layout_constraintStart_toEndOf="@+id/logo"
app:layout_constraintTop_toTopOf="@+id/logo" />
- <Space
- android:id="@+id/space_above_content"
- android:layout_width="match_parent"
- android:layout_height="@dimen/biometric_prompt_space_above_content"
- android:visibility="gone" />
-
<TextView
android:id="@+id/title"
style="@style/TextAppearance.AuthCredential.Title"
@@ -137,11 +131,10 @@
<LinearLayout
android:id="@+id/customized_view_container"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical"
- android:paddingHorizontal="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -165,7 +158,6 @@
app:layout_constraintTop_toBottomOf="@+id/subtitle"
app:layout_constraintVertical_bias="0.0" />
-
<androidx.constraintlayout.widget.Barrier
android:id="@+id/contentBarrier"
android:layout_width="wrap_content"
@@ -179,16 +171,14 @@
<TextView
android:id="@+id/indicator"
+ style="@style/TextAppearance.AuthCredential.Indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:accessibilityLiveRegion="polite"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
- android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
- android:textColor="@color/biometric_dialog_gray"
- android:textSize="12sp"
app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
index 329fc46..8b886a7 100644
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -2,6 +2,8 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/biometric_prompt_constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -19,7 +21,7 @@
android:id="@+id/panel"
android:layout_width="0dp"
android:layout_height="0dp"
- android:background="?android:attr/colorBackgroundFloating"
+ android:background="?androidprv:attr/materialColorSurfaceBright"
android:clickable="true"
android:clipToOutline="true"
android:importantForAccessibility="no"
@@ -61,8 +63,9 @@
<ImageView
android:id="@+id/logo"
- android:layout_width="@dimen/biometric_auth_icon_size"
- android:layout_height="@dimen/biometric_auth_icon_size"
+ android:contentDescription="@string/biometric_dialog_logo"
+ android:layout_width="@dimen/biometric_prompt_logo_size"
+ android:layout_height="@dimen/biometric_prompt_logo_size"
android:layout_gravity="center"
android:scaleType="fitXY"
android:visibility="visible"
@@ -73,24 +76,14 @@
<TextView
android:id="@+id/logo_description"
+ style="@style/TextAppearance.AuthCredential.LogoDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:marqueeRepeatLimit="1"
- android:singleLine="true"
- android:paddingTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/logo" />
- <Space
- android:id="@+id/space_above_content"
- android:layout_width="match_parent"
- android:layout_height="@dimen/biometric_prompt_space_above_content"
- android:visibility="gone" />
-
<TextView
android:id="@+id/title"
style="@style/TextAppearance.AuthCredential.Title"
@@ -117,11 +110,10 @@
<LinearLayout
android:id="@+id/customized_view_container"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical"
- android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -153,16 +145,14 @@
<!-- Cancel Button, replaces negative button when biometric is accepted -->
<TextView
android:id="@+id/indicator"
+ style="@style/TextAppearance.AuthCredential.Indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:accessibilityLiveRegion="polite"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
- android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
- android:textColor="@color/biometric_dialog_gray"
- android:textSize="12sp"
app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
app:layout_constraintEnd_toEndOf="@+id/panel"
app:layout_constraintStart_toStartOf="@+id/panel"
diff --git a/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml
index 11284fd..9f4fcb3 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml
@@ -55,6 +55,13 @@
android:layout_height="wrap_content"
android:layout_below="@id/subtitle" />
+ <LinearLayout
+ android:id="@+id/customized_view_container"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_below="@id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
</RelativeLayout>
</ScrollView>
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 59828fd..baeb94e 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -56,6 +56,14 @@
android:layout_below="@id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
+
+ <LinearLayout
+ android:id="@+id/customized_view_container"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:layout_below="@id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
</RelativeLayout>
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index 6391813..74bf318 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -2,6 +2,8 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/biometric_prompt_constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -19,7 +21,7 @@
android:id="@+id/panel"
android:layout_width="0dp"
android:layout_height="0dp"
- android:background="?android:attr/colorBackgroundFloating"
+ android:background="?androidprv:attr/materialColorSurfaceBright"
android:clickable="true"
android:clipToOutline="true"
android:importantForAccessibility="no"
@@ -61,8 +63,9 @@
<ImageView
android:id="@+id/logo"
- android:layout_width="@dimen/biometric_auth_icon_size"
- android:layout_height="@dimen/biometric_auth_icon_size"
+ android:contentDescription="@string/biometric_dialog_logo"
+ android:layout_width="@dimen/biometric_prompt_logo_size"
+ android:layout_height="@dimen/biometric_prompt_logo_size"
android:layout_gravity="center"
android:scaleType="fitXY"
app:layout_constraintBottom_toTopOf="@+id/logo_description"
@@ -73,21 +76,14 @@
<TextView
android:id="@+id/logo_description"
+ style="@style/TextAppearance.AuthCredential.LogoDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:singleLine="true"
app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/logo" />
- <Space
- android:id="@+id/space_above_content"
- android:layout_width="match_parent"
- android:layout_height="@dimen/biometric_prompt_space_above_content"
- android:visibility="gone" />
-
<TextView
android:id="@+id/title"
style="@style/TextAppearance.AuthCredential.Title"
@@ -119,7 +115,7 @@
android:gravity="center_vertical"
android:orientation="vertical"
android:visibility="gone"
- android:paddingTop="8dp"
+ android:paddingTop="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -131,7 +127,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
- android:paddingTop="16dp"
+ android:paddingTop="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -150,6 +146,7 @@
<TextView
android:id="@+id/indicator"
+ style="@style/TextAppearance.AuthCredential.Indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
@@ -229,5 +226,4 @@
app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
app:layout_constraintStart_toStartOf="@+id/biometric_icon"
app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
-
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml b/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml
index e39f60f..bc82708 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml
@@ -17,5 +17,5 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TextAppearance.AuthCredential.ContentViewListItem"
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_weight="1.0" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml
index 6c86736..f0125b6 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml
@@ -16,6 +16,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="@dimen/biometric_prompt_content_list_row_height"
+ android:layout_height="wrap_content"
android:gravity="center_vertical|start"
android:orientation="horizontal" />
diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_content_with_button_layout.xml
similarity index 64%
copy from packages/SystemUI/res/layout/biometric_prompt_content_layout.xml
copy to packages/SystemUI/res/layout/biometric_prompt_content_with_button_layout.xml
index 3908757..81f4bcc 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_content_with_button_layout.xml
@@ -17,16 +17,19 @@
android:id="@+id/customized_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- style="@style/AuthCredentialContentLayoutStyle">
+ style="@style/AuthCredentialContentViewStyle">
<TextView
- android:id="@+id/customized_view_title"
- style="@style/TextAppearance.AuthCredential.ContentViewTitle"
+ android:id="@+id/customized_view_description"
+ style="@style/TextAppearance.AuthCredential.ContentViewWithButtonDescription"
+ android:paddingBottom="16dp"
android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/customized_view_more_options_button"
+ style="@style/AuthCredentialContentViewMoreOptionsButtonStyle"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="1"
- android:singleLine="true" />
+ android:text="@string/biometric_dialog_content_view_more_options_button"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index 9842109..ff89ed9 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
@@ -44,7 +44,7 @@
android:singleLine="true"
android:marqueeRepeatLimit="1"
android:ellipsize="marquee"
- style="@style/TextAppearance.AuthCredential.Title"/>
+ style="@style/TextAppearance.AuthCredential.OldTitle"/>
<TextView
android:id="@+id/subtitle"
@@ -54,20 +54,21 @@
android:singleLine="true"
android:marqueeRepeatLimit="1"
android:ellipsize="marquee"
- style="@style/TextAppearance.AuthCredential.Subtitle"/>
+ style="@style/TextAppearance.AuthCredential.OldSubtitle"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="@integer/biometric_dialog_text_gravity"
android:scrollbars ="vertical"
android:importantForAccessibility="no"
- style="@style/TextAppearance.AuthCredential.Description"/>
+ style="@style/TextAppearance.AuthCredential.OldDescription"/>
<Space
android:id="@+id/space_above_content"
android:layout_width="match_parent"
- android:layout_height="@dimen/biometric_prompt_space_above_content"
+ android:layout_height="24dp"
android:visibility="gone" />
<LinearLayout
@@ -77,7 +78,6 @@
android:fadeScrollbars="false"
android:gravity="center_vertical"
android:orientation="vertical"
- android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
android:scrollbars="vertical"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_vertical_list_content_layout.xml
similarity index 70%
rename from packages/SystemUI/res/layout/biometric_prompt_content_layout.xml
rename to packages/SystemUI/res/layout/biometric_prompt_vertical_list_content_layout.xml
index 3908757..a754cb4 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_vertical_list_content_layout.xml
@@ -17,16 +17,11 @@
android:id="@+id/customized_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- style="@style/AuthCredentialContentLayoutStyle">
+ style="@style/AuthCredentialVerticalListContentViewStyle">
<TextView
- android:id="@+id/customized_view_title"
- style="@style/TextAppearance.AuthCredential.ContentViewTitle"
+ android:id="@+id/customized_view_description"
+ style="@style/TextAppearance.AuthCredential.VerticalListContentViewDescription"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="1"
- android:singleLine="true" />
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 91550b3..e95c6a7 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -34,6 +34,5 @@
android:paddingEnd="0dp"
android:progressDrawable="@drawable/brightness_progress_drawable"
android:splitTrack="false"
- android:clickable="true"
/>
</com.android.systemui.settings.brightness.BrightnessSliderView>
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
new file mode 100644
index 0000000..ef1a21f
--- /dev/null
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<com.android.systemui.screenshot.ui.ScreenshotShelfView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/actions_container_background"
+ android:visibility="gone"
+ android:layout_height="0dp"
+ android:layout_width="0dp"
+ android:elevation="4dp"
+ android:background="@drawable/action_chip_container_background"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"
+ app:layout_constraintBottom_toTopOf="@id/guideline"/>
+ <HorizontalScrollView
+ android:id="@+id/actions_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:paddingEnd="@dimen/overlay_action_container_padding_end"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
+ android:elevation="4dp"
+ android:scrollbars="none"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintWidth_percent="1.0"
+ app:layout_constraintWidth_max="wrap"
+ app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background">
+ <LinearLayout
+ android:id="@+id/screenshot_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <include layout="@layout/overlay_action_chip"
+ android:id="@+id/screenshot_share_chip"/>
+ <include layout="@layout/overlay_action_chip"
+ android:id="@+id/screenshot_edit_chip"/>
+ <include layout="@layout/overlay_action_chip"
+ android:id="@+id/screenshot_scroll_chip"
+ android:visibility="gone" />
+ </LinearLayout>
+ </HorizontalScrollView>
+ <View
+ android:id="@+id/screenshot_preview_border"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="@dimen/overlay_border_width_neg"
+ android:layout_marginEnd="@dimen/overlay_border_width_neg"
+ android:layout_marginBottom="14dp"
+ android:elevation="8dp"
+ android:background="@drawable/overlay_border"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+ app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
+ app:layout_constraintBottom_toBottomOf="parent"/>
+ <ImageView
+ android:id="@+id/screenshot_preview"
+ android:layout_width="@dimen/overlay_x_scale"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overlay_border_width"
+ android:layout_marginBottom="@dimen/overlay_border_width"
+ android:layout_gravity="center"
+ android:elevation="8dp"
+ android:contentDescription="@string/screenshot_edit_description"
+ android:scaleType="fitEnd"
+ android:background="@drawable/overlay_preview_background"
+ android:adjustViewBounds="true"
+ android:clickable="true"
+ app:layout_constraintStart_toStartOf="@id/screenshot_preview_border"
+ app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"/>
+ <ImageView
+ android:id="@+id/screenshot_badge"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:visibility="gone"
+ android:elevation="9dp"
+ app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
+ app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"/>
+ <FrameLayout
+ android:id="@+id/screenshot_dismiss_button"
+ android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
+ android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
+ android:elevation="11dp"
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/screenshot_preview"
+ app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
+ app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+ app:layout_constraintBottom_toTopOf="@id/screenshot_preview"
+ android:contentDescription="@string/screenshot_dismiss_description">
+ <ImageView
+ android:id="@+id/screenshot_dismiss_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/overlay_dismiss_button_margin"
+ android:background="@drawable/circular_background"
+ android:backgroundTint="?androidprv:attr/materialColorPrimary"
+ android:tint="?androidprv:attr/materialColorOnPrimary"
+ android:padding="4dp"
+ android:src="@drawable/ic_close"/>
+ </FrameLayout>
+ <ImageView
+ android:id="@+id/screenshot_scrollable_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="matrix"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/screenshot_preview"
+ app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+ android:elevation="7dp"/>
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_end="0dp" />
+
+ <FrameLayout
+ android:id="@+id/screenshot_message_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
+ android:paddingHorizontal="@dimen/overlay_action_container_padding_end"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
+ android:elevation="4dp"
+ android:background="@drawable/action_chip_container_background"
+ android:visibility="gone"
+ app:layout_constraintTop_toBottomOf="@id/guideline"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintWidth_max="450dp"
+ app:layout_constraintHorizontal_bias="0">
+ <include layout="@layout/screenshot_work_profile_first_run" />
+ <include layout="@layout/screenshot_detection_notice" />
+ </FrameLayout>
+</com.android.systemui.screenshot.ui.ScreenshotShelfView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9bc1445..b1b4748 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Die neem van skermskote word deur jou IT-admin geblokkeer"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Wysig"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Wysig skermkiekie"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Deel skermskoot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Vang meer vas"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Maak skermkiekie toe"</string>
@@ -289,7 +291,7 @@
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Geblokkeer"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediatoestel"</string>
<string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string>
- <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
<string name="quick_settings_networks_available" msgid="1875138606855420438">"Netwerke is beskikbaar"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netwerke is nie beskikbaar nie"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Hierdie toestel word deur jou ouer bestuur. Jou ouer kan inligting sien en bestuur soos die programme wat jy gebruik, jou ligging en jou skermtyd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontsluit gehou deur TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Diefstalbeskerming\nToestel gesluit; te veel pogings om te ontsluit"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Klankinstellings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Gee outomaties mediaopskrifte"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Demp"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Saai uit"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Onbeskikbaar omdat luitoon gedemp is"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Onbeskikbaar want Moenie Steur Nie is aan"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Onbeskikbaar want Moenie Steur Nie is aan"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om te ontdemp."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s volumekontroles"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Oproepe en kennisgewings sal lui (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Voer uitsetinstellings in"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volumeglyers is uitgevou"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volumeglyers is ingevou"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"demp %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ontdemp %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> speel tans op"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Oudio sal speel op"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Stelsel-UI-ontvanger"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Beweeg vorentoe deur onlangse apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Beweeg terug deur onlangse apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Maak appslys oop"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Wys taakbalk"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Maak instellings oop"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Maak Assistent oop"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Sluit skerm"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Gaan by verdeelde skerm in met huidige app aan die regterkant"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Gaan by verdeelde skerm in met huidige app aan die linkerkant"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Skakel oor van verdeelde skerm na volskerm"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tydens verdeelde skerm: verplaas ’n app van een skerm na ’n ander"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Invoer"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skakel oor na volgende taal"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera is geblokkeer"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera en mikrofoon is geblokkeer"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoon is geblokkeer"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Moenie steur nie"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikerteenwoordigheid is bespeur"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
<string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c333483..8daa20e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"á
áœá á³á áá
á¥áá³ááœá ááá³áµ á á¥ááµá á áá² á áµá°á³á³áª á³áá·á"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"á ááµá á«áµáá"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"á
áœá á³á áá
ááá³á á ááµá á«áµáá"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"á
áœá á³á áá
á¥áá³á á«áá©"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"á°ášá᪠áá
ášá¹"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"á
áœá á³á áá
ááá³á á á°áá¥áµ"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"áá
áá£áªá« á á¥ááµá ááá
ášáá°á³á°á ááᢠááá
á ášáá ááá£ážáá áá°áá áªá«ááœá£ á á«á£á¢áá á¥á ášáá« áá
áááá ášáá³á°á áášáááœá áášáµ á¥á ááµá°á³á°á ááœááá¢"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"á TrustAgent á¥áá°á°ášáá° ááá·á"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ášáµáááµ áášáášá«\náá³áªá« á°ááááᣠá á£á á¥á ášááááµ áášá«ááœ"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>ᢠ<xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ášáµáá
á
áá¥á®áœ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"á«áµá°á ášá¥áá áááá« áœááá áá²á«"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"áµááž-ášá á áµáá"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ášá¥áª áµáᜠáµáá°áá á áááá"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"á áµášá¥áœ áµáá á« á áááá"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"á áµášá¥áœ áµáá á« á áááá"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sᢠáµááž-ášá áááµášá áá³ á«áµáá"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sᢠáá° ááášáµ ááááá á áá³ á«áµááᢠášá°á°á«áœááµ á ááááá¶áœ áµááž-ášá áá°ášáá£ážá ááœááá¢"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sᢠáµááž-ášá áááµášá áá³ á«áµááᢠášá°á°á«áœááµ á ááááá¶áœ áµááž-ášá áá°ášáá£ážá ááœááá¢"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ááá"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ášáµáá
ááá£á áªá«ááœ"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"á¥áªáᜠá¥á áá³ááá«áᜠ(<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>) áá áá°ááá"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ášááœááµ á
áá¥á®áœá á«áµáá¡"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ášáµáᜠá°áážá«á³áŸáœ á°áááá·á"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ášáµáᜠá°áážá«á³áŸáœ á°á°á¥áµá§á"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s áá áµáá-ášá á áµáá"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"áš%s áµáá-ášá á áá³"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> á¥ášá°á«áá° á«áá á "</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"áŠá²á® áá«áá³á á "</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ášáµáááµ á áááᜠááá"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ášá
áᥠáá áá°áá áªá«áᜠáá áá° ááµ áá°áµ ááµášáá¢"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ášá
áᥠáá áá°áá áªá«áᜠáá áá° áá áá°áµ ááµášáá¢"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ášáá°áá áªá« áááá áááµ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ášá°áá£á á ááá á á³á"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"á
áá¥á®áœá áááµ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ášá³áµá áááµ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"áá« áá
ááá"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"áá áá€áœá€áµ á á áá áá°áá áªá« áá° ášá°ášáá áá« áᜠáá£"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"áá€áá€áœá€áµ á á áá áá°áá áªá« áá° ášá°ášáá áá« áᜠááá¡"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ášášá°ášáá áá« áᜠáá° áá áᜠááá³ ááá"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"á á°ášáá áá« áᜠáá
áµá¡- áá°áá áªá«á ášá áá± áá° ááá á°á«"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"áá€áµ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"áá° áá£á© ááá ááá"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"á«áá« á³áá·á"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"á«áá« á¥á áááá®áá á³áá°áá"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"áááá®áá á³áá·á"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"á áµášá¥áœ"</string>
<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>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 9a36bcf..8cfbf6a 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ØÙØžÙØ± Ù
؎ر٠تÙÙÙÙÙØ¬Ùا اÙÙ
عÙÙÙ
ات عÙ
ÙÙØ© أخذ ÙÙØ·Ø§Øª ÙÙØŽØ§ØŽØ©."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"تعدÙÙ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"تعدÙÙ ÙÙØ·Ø© Ø§ÙØŽØ§ØŽØ©"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Ù
ØŽØ§Ø±ÙØ© ÙÙØ·Ø© Ø§ÙØŽØ§ØŽØ©"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Ø§ÙØªÙاط اÙÙ
Ø²ÙØ¯ Ù
٠اÙÙ
ØØªÙÙ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ø¥ØºÙØ§Ù ÙÙØ·Ø© Ø§ÙØŽØ§ØŽØ©"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÙØªÙÙÙÙ Ø£ØØ¯ اÙÙØ§ÙدÙ٠إدارة ÙØ°Ø§ Ø§ÙØ¬Ùاز. ÙÙ
ÙÙ ÙÙÙØ§ÙدÙ٠عرض ÙØ¥Ø¯Ø§Ø±Ø© Ù
عÙÙÙ
Ø§ØªÙØ Ù
Ø«ÙØ§Ù Ø§ÙØªØ·ØšÙÙØ§Øª Ø§ÙØªÙ تستخدÙ
ÙØ§ ÙÙ
ÙÙØ¹Ù Ø§ÙØ¬ØºØ±Ø§ÙÙ ÙÙÙØª اÙÙØžØ± Ø¥ÙÙ Ø§ÙØŽØ§ØŽØ©."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"ØŽØšÙØ© Ø§ÙØªØ±Ø§Ø¶ÙØ© خاصة"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ÙØªØ اÙÙÙ٠ؚاستÙ
رار ØšÙØ§Ø³Ø·Ø© TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"تÙ
ÙÙÙ Ø§ÙØ¬Ùاز\nÙØÙ
Ø§ÙØªÙ Ù
Ù Ø§ÙØ³Ø±ÙØ© ؚسؚؚ إجراء Ø§ÙØ¹Ø¯Ùد Ù
Ù Ù
ØØ§ÙÙØ§Øª Ø¥ÙØºØ§Ø¡ اÙÙÙÙ."</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"إعدادات Ø§ÙØµÙت"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ØŽØ±Ø ØªÙÙØ§ØŠÙ ÙÙÙØ³Ø§ØŠØ·"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ÙØªÙ
Ø§ÙØµÙت"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Ø§ÙØšØ«Ù"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÙØªØ¹Ø°Ùر Ø§ÙØªØºÙÙØ± ؚسؚؚ ÙØªÙ
ØµÙØª Ø§ÙØ±ÙÙÙ."</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ù
ستÙÙ Ø§ÙØµÙت ØºÙØ± Ù
ØªØ§Ø ØšØ³ØšØš ØªÙØ¹ÙÙ ÙØ¶Ø¹ \"عدÙ
Ø§ÙØ¥Ø²Ø¹Ø§Ø¬\""</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ù
ستÙÙ Ø§ÙØµÙت ØºÙØ± Ù
ØªØ§Ø ØšØ³ØšØš ØªÙØ¹ÙÙ ÙØ¶Ø¹ \"عدÙ
Ø§ÙØ¥Ø²Ø¹Ø§Ø¬\""</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. اÙÙØ± ÙØ¥Ùغاء Ø§ÙØªØ¬Ø§ÙÙ."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. اÙÙØ± ÙÙØªØ¹ÙÙ٠عÙÙ Ø§ÙØ§Ùتزاز. ÙØ¯ ÙØªÙ
تجاÙ٠خدÙ
ات \"سÙÙÙØ© Ø§ÙØ§Ø³ØªØ®Ø¯Ø§Ù
\"."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. اÙÙØ± ÙÙØªØ¬Ø§ÙÙ. ÙØ¯ ÙØªÙ
تجاÙ٠خدÙ
ات \"سÙÙÙØ© Ø§ÙØ§Ø³ØªØ®Ø¯Ø§Ù
\"."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"Ø§ÙØªØ²Ø§Ø²"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s Ø¹ÙØµØ± ÙÙØªØÙÙ
ÙÙ Ù
ستÙÙ Ø§ÙØµÙت"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Ø³ÙØµØ¯Ø± اÙÙØ§ØªÙ رÙÙÙÙØ§ Ø¹ÙØ¯ تÙÙ٠اÙÙ
ÙØ§ÙÙ
ات ÙØ§Ùإ؎عارات (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)."</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ø§ÙØ¯Ø®Ù٠إÙ٠إعدادات إخراج Ø§ÙØµÙت"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"تÙ
ØªÙØ³Ùع أ؎رطة تÙ
Ø±ÙØ± Ø§ÙØµÙت"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"تÙ
ØªØµØºÙØ± أ؎رطة تÙ
Ø±ÙØ± Ø§ÙØµÙت"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ÙØªÙ
ØµÙØª \"%s\""</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"إعادة ØµÙØª \"%s\""</string>
<string name="media_output_label_title" msgid="872824698593182505">"ت؎غÙÙ <xliff:g id="LABEL">%s</xliff:g> عÙÙ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ø³ÙØªÙ
ت؎غÙÙ Ø§ÙØµÙت عÙÙ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"أداة ضؚط ÙØ§Ø¬ÙØ© Ù
ستخدÙ
اÙÙØžØ§Ù
"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Ø§ÙØªÙÙÙÙ ÙÙØ£Ù
اÙ
ØšÙÙ Ø§ÙØªØ·ØšÙÙØ§Øª اÙÙ
ÙØ³ØªØ®Ø¯ÙÙ
Ø© Ù
Ø€Ø®Ø±ÙØ§"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Ø§ÙØªÙÙÙÙ ÙÙÙØ±Ø§Ø¡ ØšÙÙ Ø§ÙØªØ·ØšÙÙØ§Øª اÙÙ
ÙØ³ØªØ®Ø¯ÙÙ
Ø© Ù
Ø€Ø®Ø±ÙØ§"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÙØªØ ÙØ§ØŠÙ
Ø© Ø§ÙØªØ·ØšÙÙØ§Øª"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"عرض ØŽØ±ÙØ· Ø§ÙØªØ·ØšÙÙØ§Øª"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÙØªØ Ø§ÙØ¥Ø¹Ø¯Ø§Ø¯Ø§Øª"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÙØªØ \"Ù
ساعد Google\""</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"؎ا؎ة اÙÙÙÙ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ØªÙØ¹ÙÙ ÙØ¶Ø¹ \"ØªÙØ³ÙÙ
Ø§ÙØŽØ§ØŽØ©\" Ù
ع عرض Ø§ÙØªØ·ØšÙÙ Ø§ÙØØ§Ù٠عÙÙ ÙØ³Ø§Ø± Ø§ÙØŽØ§ØŽØ©"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ØªÙØ¹ÙÙ ÙØ¶Ø¹ \"ØªÙØ³ÙÙ
Ø§ÙØŽØ§ØŽØ©\" Ù
ع عرض Ø§ÙØªØ·ØšÙÙ Ø§ÙØØ§Ù٠عÙÙ ÙÙ
ÙÙ Ø§ÙØŽØ§ØŽØ©"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Ø§ÙØªØšØ¯ÙÙ Ù
Ù ÙØ¶Ø¹ \"ØªÙØ³ÙÙ
Ø§ÙØŽØ§ØŽØ©\" Ø¥ÙÙ ÙØ¶Ø¹ \"Ù
ÙØ¡ Ø§ÙØŽØ§ØŽØ©\""</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"استؚدا٠تطؚÙ٠ؚآخر ÙÙ ÙØ¶Ø¹ \"ØªÙØ³ÙÙ
Ø§ÙØŽØ§ØŽØ©\""</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"إدخاÙ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Ø§ÙØªØšØ¯Ù٠إÙ٠اÙÙØºØ© Ø§ÙØªØ§ÙÙØ©"</string>
@@ -1165,7 +1166,7 @@
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ù
ØªØµÙØ© ØšØ§ÙØ¥ÙØªØ±ÙØª"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ù
ØªØµÙØ© Ù
Ø€ÙØªÙا"</string>
<string name="mobile_data_poor_connection" msgid="819617772268371434">"Ø§ÙØ§ØªØµØ§Ù ضعÙÙ"</string>
- <string name="mobile_data_off_summary" msgid="3663995422004150567">"ÙÙ ÙØªÙ
تÙÙØ§ØŠÙÙØ§ Ø§ÙØ§ØªØµØ§Ù ØšØšÙØ§Ùات Ø§ÙØ¬ÙÙØ§Ù."</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"ÙÙ ÙØªÙ
تÙÙØ§ØŠÙÙØ§ Ø§ÙØ§ØªØµØ§Ù ØšØšÙØ§Ùات Ø§ÙØ¬ÙÙØ§Ù"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ÙØ§ ÙØªÙÙÙØ± Ø§ØªØµØ§Ù ØšØ§ÙØ¥ÙØªØ±ÙØª"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ÙØ§ تتÙÙÙØ± ØŽØšÙØ§Øª أخرÙ."</string>
<string name="all_network_unavailable" msgid="4112774339909373349">"ÙØ§ تتÙÙÙØ± Ø£Ù ØŽØšÙØ§Øª."</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخداÙ
اÙÙØ§Ù
ÙØ±Ø§ Ù
ØØžÙر."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخداÙ
اÙÙØ§Ù
ÙØ±Ø§ ÙØ§ÙÙ
ÙÙØ±ÙÙÙÙ Ù
ØØžÙر."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخداÙ
اÙÙ
ÙÙØ±ÙÙÙÙ Ù
ØØžÙر."</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"عدÙ
Ø§ÙØ¥Ø²Ø¹Ø§Ø¬"</string>
<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>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a211d1e..b621ce88 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àŠžà§àŠà§à§°à§àŠšàŠ¶à§àŠ¬àŠ àŠ²à§à§±àŠŸàŠà§ àŠàŠªà§àŠšàŠŸà§° àŠàŠàŠàŠ¿ àŠªà§à§°àŠ¶àŠŸàŠžàŠà§ àŠ
ৱৰà§àЧ àŠà§°àŠ¿àŠà§"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"àŠžàŠ®à§àŠªàŠŸàŠŠàŠšàŠŸ àŠà§°àŠ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"àŠžà§àŠà§à§°à§àŠšàŠ¶à§àŠ¬àŠ àŠžàŠ®à§àŠªàŠŸàŠŠàŠšàŠŸ àŠà§°àŠ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"àŠžà§àŠà§à§°à§àŠšàŠ¶à§àŠ¬àŠ àŠ¶à§àЬà§àŠ¯àŠŒàŠŸà§° àŠà§°àŠ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àŠ
àŠ§àŠ¿àŠ àŠà§àŠªàŠàŠŸà§° àŠà§°àŠ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àŠžà§àŠà§à§°à§àŠšàŠ¶à§àŠ¬àŠ àŠ
àŠà§à§°àŠŸàŠ¹à§àН àŠà§°àŠ"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àŠàŠ àŠ¡àŠ¿àŠàŠŸàŠàŠàŠà§ àŠàŠªà§àŠšàŠŸà§° àŠ
àŠàŠ¿àŠàŠŸà§±àŠà§ àŠªà§°àŠ¿àŠàŠŸàŠ²àŠšàŠŸ àŠà§°à§à¥€ àŠàŠªà§àŠšàŠŸà§° àŠ
àŠàŠ¿àŠàŠŸà§±àŠà§ àŠàŠªà§àŠšàŠ¿ àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠŸ àŠàŠªà§, àŠàŠªà§àŠšàŠŸà§° àŠ
à§±àŠžà§àŠ¥àŠŸàŠš àŠà§°à§ àŠàŠªà§àŠšàŠ¿ àŠ¡àŠ¿àŠàŠŸàŠàŠàŠ€ àŠ
àŠ€àŠ¿àŠ¬àŠŸàŠ¹àŠ¿àŠ€ àŠà§°àŠŸ àŠžàŠ®àŠ¯àŠŒà§° àŠŠà§°à§ àŠ€àŠ¥à§àН àŠàŠŸàŠ¬ àŠà§°à§ àŠªà§°àŠ¿àŠàŠŸàŠ²àŠšàŠŸ àŠà§°àŠ¿àŠ¬ àŠªàŠŸà§°à§à¥€"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"àŠàŠ¿àŠªàŠ¿àŠàŠš"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgentàŠ àŠàŠšàŠ²àŠ àŠà§°àŠ¿ à§°àŠŸàŠàŠ¿àŠà§"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àŠà§à§°àŠ¿à§° àŠªà§°àŠŸ àŠžà§à§°àŠà§àŠ·àŠŸ\nàŠ¡àŠ¿àŠàŠŸàŠàŠ àŠ²àŠ àŠàŠà§, àŠ¬àŠ¹à§àŠ¬àŠŸà§° àŠàŠšàŠ²àŠà§° àŠà§àŠ·à§àŠàŠŸ àŠà§°àŠŸ àŠ¹à§àŠà§"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àŠ§à§àŠ¬àŠšàŠ¿à§° àŠà§àŠàŠ¿àŠ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"àŠžà§àŠ¬àŠ¯àŠŒàŠàŠà§à§°àŠ¿àŠ¯àŠŒ àŠà§àŠªàŠ¶à§àŠ¬àŠš àŠ®àŠ¿àŠ¡àŠ¿àŠ¯àŠŒàŠŸ"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àŠ®àŠ¿àŠàŠ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"àŠàŠŸàŠ·à§àŠ àŠà§°àŠ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à§°àŠ¿àŠ àŠ®àŠ¿àŠàŠ àŠà§°àŠ¿ àŠ¥à§à§±àŠŸà§° àŠ¬àŠŸàŠ¬à§ àŠàŠªàŠ²àŠ¬à§àЧ àŠšàŠ¹àŠ¯àŠŒ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"àŠ
àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠšàŠ¿àŠŠàŠ¿àŠ¬ àŠ
àŠš àŠ¥àŠàŠŸà§° àŠàŠŸà§°àŠ£à§ àŠàŠªàŠ²àŠ¬à§àЧ àŠšàŠ¹àŠ¯àŠŒ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"àŠ
àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠšàŠ¿àŠŠàŠ¿àŠ¬ àŠ
àŠš àŠ¥àŠàŠŸà§° àŠàŠŸà§°àŠ£à§ àŠàŠªàŠ²àŠ¬à§àЧ àŠšàŠ¹àŠ¯àŠŒ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sी àŠàŠšàŠ®àŠ¿àŠàŠ àŠà§°àŠ¿àŠ¬à§° àŠ¬àŠŸàŠ¬à§ àŠàŠ¿àŠªàŠà¥€"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sी àŠàŠ®à§àŠªàŠšà§° àŠ¬àŠŸàŠ¬à§ àŠàŠ¿àŠªàŠà¥€ àŠŠàŠ¿àŠ¬à§àŠ¯àŠŒàŠŸàŠàŠàŠžàŠàŠ²à§° àŠ¬àŠŸàŠ¬à§ àŠ¥àŠàŠŸ àŠžà§à§±àŠŸ àŠ®àŠ¿àŠàŠ àŠ¹à§ àŠ¥àŠŸàŠàŠ¿àŠ¬ àŠªàŠŸà§°à§à¥€"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sी àŠ®àŠ¿àŠàŠ àŠà§°àŠ¿àŠ¬àŠ²à§ àŠàŠ¿àŠªàŠà¥€ àŠŠàŠ¿àŠ¬à§àŠ¯àŠŒàŠŸàŠàŠàŠžàŠàŠ²à§° àŠ¬àŠŸàŠ¬à§ àŠ¥àŠàŠŸ àŠžà§à§±àŠŸ àŠ®àŠ¿àŠàŠ àŠ¹à§ àŠ¥àŠŸàŠàŠ¿àŠ¬ àŠªàŠŸà§°à§à¥€"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"àŠàŠ®à§àŠªàŠš àŠà§°àŠ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s àŠ§à§àŠ¬àŠšàŠ¿ àŠšàŠ¿àŠ¯àŠŒàŠšà§àŠ€à§à§°àŠ£àŠžàŠ®à§àй"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àŠàв àŠà§°à§ àŠàŠŸàŠšàŠšà§àЬà§à§° àŠàŠ®àŠŸàŠš àŠàŠ²àŠ¿àŠàŠ®àŠ€ àŠ¬àŠŸàŠàŠ¿àŠ¬ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"àŠàŠàŠàŠªà§àŠ àŠà§àŠàŠ¿àŠ àŠà§àвàŠ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àŠàŠ²àŠ¿àŠàŠ®à§° àŠ¶à§àŠ²àŠŸàŠàŠ¡àŠŸà§° àŠ¬àŠ¿àŠžà§àŠ€àŠŸà§° àŠà§°àŠŸ àŠàŠà§"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"àŠàŠ²àŠ¿àŠàŠ®à§° àŠ¶à§àŠ²àŠŸàŠàŠ¡àŠŸà§° àŠžàŠàŠà§àŠàŠš àŠà§°àŠŸ àŠàŠà§"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s àŠ®àŠ¿àŠàŠ àŠà§°àŠ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s àŠàŠšàŠ®àŠ¿àŠàŠ àŠà§°àŠ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"àŠàŠ¯àŠŒàŠŸàŠ€ <xliff:g id="LABEL">%s</xliff:g> àŠªà§àŠ²à§’ àŠ¹à§ àŠàŠà§"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"àŠ
àŠ¡àŠ¿àŠ
’ àŠàŠ¯àŠŒàŠŸàŠ€ àŠªà§àŠ²à§’ àŠ¹’àŠ¬"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"àŠ¶à§àŠ¹àŠ€à§àŠ¯àŠŒàŠŸ àŠàŠªà§àŠžàŠ®à§àй àŠàŠàŠ²à§ àŠàŠàŠŸ àŠàŠàŠŸàŠà§ àŠàŠŸàŠàŠ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"àŠ¶à§àŠ¹àŠ€à§àŠ¯àŠŒàŠŸ àŠàŠªà§àŠžàŠ®à§àй àŠªàŠ¿àŠàŠ²à§ àŠàŠàŠŸ àŠàŠàŠŸàŠà§ àŠàŠŸàŠàŠ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"àŠàŠªà§° àŠžà§àŠà§ àŠà§àвàŠ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"àŠàŠŸàŠžà§àŠàŠ¬àŠŸà§° àŠŠà§àŠà§à§±àŠŸàŠàŠ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"àŠà§àŠàŠ¿àŠ àŠà§àвàŠ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant àŠà§àвàŠ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"àŠ²àŠ àŠžà§àŠà§à§°à§àŠš"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"àŠ¬à§°à§àŠ€àŠ®àŠŸàŠšà§° àŠàŠªà§° àŠà§°àŠ¿àŠ¯àŠŒàŠ€à§ àŠ¬àŠ¿àŠàŠŸàŠàŠ¿àŠ€ àŠžà§àŠà§à§°à§àŠšà§° àŠžà§àŠàŠ«àŠŸàŠ²à§° àŠžà§àŠà§à§°à§àŠšàŠàŠšàŠ€ àŠžà§àŠ®àŠŸàŠàŠ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"àŠ¬à§°à§àŠ€àŠ®àŠŸàŠšà§° àŠàŠªà§° àŠà§°àŠ¿àŠ¯àŠŒàŠ€à§ àŠ¬àŠ¿àŠàŠŸàŠàŠ¿àŠ€ àŠžà§àŠà§à§°à§àŠšà§° àŠ¬àŠŸàŠàŠàŠ«àŠŸàŠ²à§° àŠžà§àŠà§à§°à§àŠšàŠàŠšàŠ€ àŠžà§àŠ®àŠŸàŠàŠ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"àŠ¬àŠ¿àŠàŠŸàŠàŠ¿àŠ€ àŠžà§àŠà§à§°à§àŠšà§° àŠªà§°àŠŸ àŠªà§à§°à§àŠ£ àŠžà§àŠà§à§°à§àŠšàŠ²à§ àŠžàŠ²àŠšàŠ¿ àŠà§°àŠ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"àŠ¬àŠ¿àŠàŠŸàŠàŠ¿àŠ€ àŠžà§àŠà§à§°à§àŠšà§° àŠ¬à§àŠ¯à§±àŠ¹àŠŸà§° àŠà§°àŠŸà§° àŠžàŠ®àŠ¯àŠŒàŠ€: àŠà§àŠšà§ àŠàŠªà§ àŠàŠàŠš àŠžà§àŠà§à§°à§àŠšà§° àŠªà§°àŠŸ àŠàŠšàŠàŠšàŠ²à§ àŠšàŠ¿àŠ¯àŠŒàŠ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àŠàŠšàŠªà§àŠ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"àŠªà§°à§±à§°à§àŠ€à§ àŠàŠŸàŠ·àŠŸàŠà§àŠ²à§ àŠžàŠ²àŠšàŠ¿ àŠà§°àŠ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àŠà§àŠ®à§à§°àŠŸ àŠ
ৱৰà§àЧ àŠà§°àŠŸ àŠàŠà§"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àŠà§àŠ®à§à§°àŠŸ àŠà§°à§ àŠ®àŠŸàŠàŠà§à§°’àŠ«’àŠš àŠ
ৱৰà§àЧ àŠà§°àŠŸ àŠàŠà§"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"àŠ®àŠŸàŠàŠà§à§°’àŠ«’àŠš àŠ
ৱৰà§àЧ àŠà§°àŠŸ àŠàŠà§"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àŠ
àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠšàŠ¿àŠŠàŠ¿àŠ¬"</string>
<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>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 0b0788a..0fbab20 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"SkrinÅot çÉkilmÉsi İT admininiz tÉrÉfindÉn bloklanıb"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"RedaktÉ edin"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"SkrinÅota düzÉliÅ edin"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"SkrinÅotu paylaÅın"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"GeniÅlÉndirin"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran ÅÉklini ötürün"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu cihaz valideyniniz tÉrÉfindÉn idarÉ olunur. Valideyniniz iÅlÉtdiyiniz tÉtbiqlÉr, mÉkanınız vÉ ekran vaxtınız kimi bilgilÉri görÉ vÉ idarÉ edÉ bilÉr."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN (Virtual ÅÉxsi ÅÉbÉkÉlÉr)"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ilÉ açıq saxlayın"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"OÄurluqdan qoruma\nCihaz kilidlÉndi. Çoxlu kilidaçma cÉhdi"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"SÉs ayarları"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Avtomatik baÅlıq mediası"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Susdurun"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Yayım"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ZÉng sÉssiz edildiyi üçün Élçatan deyil"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Narahat EtmÉyin aktiv olduÄu üçün Élçatan deyil"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Narahat EtmÉyin aktiv olduÄu üçün Élçatan deyil"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. SÉsli etmÉk üçün tıklayın."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Ælçatımlılıq xidmÉtlÉri sÉssiz edilmiÅ ola bilÉr."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. SÉssiz etmÉk üçün tıklayın. Ælçatımlılıq xidmÉtlÉri sÉssiz edilmiÅ ola bilÉr."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s sÉs nÉzarÉtlÉri"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÇaÄrı vÉ bildiriÅlÉr zÉng çalacaq (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÇıxıŠayarlarını daxil edin"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"SÉs slayderlÉri geniÅlÉndirildi"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"SÉs slayderlÉri yıÄcamlaÅdırıldı"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s seçimini sÉssiz edin"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s seçimini sÉssiz rejimdÉn çıxarın"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> tÉtbiqindÉ oxudulur"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio oxudulacaq"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Son tÉtbiqlÉr boyunca irÉli keçin"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Son tÉtbiqlÉr boyunca geri keçin"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"TÉtbiq siyahısını açın"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"İÅlÉmÉ panelini göstÉrin"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ayarları açın"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistenti açın"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Kilid ekranı"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Cari tÉtbiq saÄda olmaqla bölünmüÅ ekrana daxil olun"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Cari tÉtbiq solda olmaqla bölünmüÅ ekrana daxil olun"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"BölünmüÅ ekrandan tam ekrana keçin"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"BölünmüÅ ekran rejimindÉ: tÉtbiqi birindÉn digÉrinÉ dÉyiÅin"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"DaxiletmÉ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"NövbÉti dilÉ keçin"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklanıb"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera vÉ mikrofon bloklanıb"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklanıb"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Narahat etmÉyin"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"İstifadÉçi mövcudluÄu aÅkarlandı"</string>
<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>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 48caa06..18d010c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT administrator blokira pravljenje snimaka ekrana"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Izmeni"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Izmenite snimak ekrana"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Delite snimak ekrana"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite još"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim ureÄajem upravlja roditelj. Roditelj moÅŸe da vidi informacije, kao što su aplikacije koje koristiš, tvoju lokaciju i vreme ispred ekrana, i da upravlja njima."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent spreÄava zakljuÄavanje"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Zaštita od kraÄe\nZaklj. ureÄaj, previše pokušaja otkljuÄavanja"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"UreÄaj je zakljuÄan, previše pokušaja potvrde identiteta"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"UreÄaj je zakljuÄan\nPotvrda identiteta nije uspela"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Podešavanja zvuka"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatski titl za medije"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"IskljuÄi zvuk"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Prebacivanje"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvuk iskljuÄen"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je ukljuÄen reÅŸim Ne uznemiravaj"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je ukljuÄen reÅŸim Ne uznemiravaj"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste ukljuÄili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupaÄnosti Äe moÅŸda biti iskljuÄen."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste iskljuÄili zvuk. Zvuk usluga pristupaÄnosti Äe moÅŸda biti iskljuÄen."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Kontrole za jaÄinu zvuka za %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Melodija zvona za pozive i obaveštenja je ukljuÄena (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unesite podešavanja izlaznog signala"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"KlizaÄi za jaÄinu zvuka su prošireni"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"KlizaÄi za jaÄinu zvuka su skupljeni"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"iskljuÄite zvuk za: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ukljuÄite zvuk za: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> se pušta na"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk se pušta na"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Tjuner za korisniÄki interfejs sistema"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Pregledaj nedavno korišÄene aplikacije unapred"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Pregledaj nedavno korišÄene aplikacije unazad"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvori listu aplikacija"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"PrikaÅŸi traku zadataka"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvori podešavanja"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvori pomoÄnika"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ZakljuÄavanje ekrana"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Pokreni podeljeni ekran za aktuelnu aplikaciju na desnoj strani"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Pokreni podeljeni ekran za aktuelnu aplikaciju na levoj strani"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"PreÄi sa podeljenog ekrana na ceo ekran"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"U reÅŸimu podeljenog ekrana: zamena jedne aplikacije drugom"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"PreÄi na sledeÄi jezik"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne uznemiravaj"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Prisustvo korisnika moÅŸe da se otkrije"</string>
<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>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index cf35a24..217a6fe 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"СÑваÑÑММе зЎÑÐŒÐºÐ°Ñ ÑкÑаМа заблакÑÑаваМа IT-аЎЌÑМÑÑÑÑаÑаÑаЌ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÐÐŒÑМÑÑÑ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÐÐŒÑМÑÑÑ Ð·ÐŽÑЌак ÑкÑаМа"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÐбагÑлÑÑÑ Ð·ÐŽÑЌак ÑкÑаМа"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÐаÑ
апÑÑÑ Ð±ÐŸÐ»ÑÑ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐÐŽÑ
ÑлÑÑÑ Ð·ÐŽÑЌак ÑкÑаМа"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÐÑÑа пÑÑлаЎа зМаÑ
ПЎзÑÑÑа паЎ каМÑÑПлеЌ баÑÑкПÑ. ÐаÑÑÐºÑ ÐŒÐŸÐ³ÑÑÑ Ð¿ÑаглÑЎаÑÑ Ñ ÐºÐ°ÐœÑÑалÑваÑÑ ÑÐ²Ð°Ñ ÑМÑаÑЌаÑÑÑ, МапÑÑклаЎ пÑа пÑагÑаЌÑ, ÑкÑÑ ÑÑ Ð²ÑкаÑÑÑÑПÑваеÑ, ЎаМÑÑ Ð¿Ñа ÑÐ²Ð°Ñ ÐŒÐµÑÑазМаÑ
ПЎжаММе Ñ ÑÐ°Ñ ÐºÐ°ÑÑÑÑÐ°ÐœÐœÑ Ð¿ÑÑлаЎай."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"РазблакÑÑаваМа з ЎапаЌПгай TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐбаÑПМа аЎ кÑаЎзÑжÑ\nÐÑÑлаЎа заблакÑÑаваМа з-за МÑÑЎалÑÑ
ÑпÑПб"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ÐÑÑлаЎа заблакÑÑаваМа, бП бÑлП заМаЎÑа ЌМПга ÑпÑПб аÑÑÑМÑÑÑÑкаÑÑÑ"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ÐÑÑлаЎа заблакÑÑаваМа\nÐÑÑÑМÑÑÑÑкаÑÑÑ ÐœÐµ пÑПйЎзеМа"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐÐ°Ð»Ð°ÐŽÑ Ð³ÑкÑ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐÑÑаЌаÑÑÑМÑÑ ÑÑбÑÑÑÑÑ"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ÐÑк вÑклÑÑаМÑ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ТÑаМÑлÑÑÑÑ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÐеЎаÑÑÑпМа, бП вÑклÑÑÐ°ÐœÑ Ð³Ñк вÑклÑкаÑ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐеЎаÑÑÑпМа, бП ÑклÑÑÐ°ÐœÑ ÑÑжÑÐŒ \"Ðе ÑÑÑбаваÑÑ\""</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐеЎаÑÑÑпМа, бП ÑклÑÑÐ°ÐœÑ ÑÑжÑÐŒ \"Ðе ÑÑÑбаваÑÑ\""</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐакÑаМÑÑеÑÑ, каб ÑклÑÑÑÑÑ Ð³Ñк."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐакÑаМÑÑеÑÑ, каб ÑклÑÑÑÑÑ Ð²ÑбÑаÑÑÑ. ÐПжа бÑÑÑ Ð°ÐŽÐºÐ»ÑÑÐ°ÐœÑ Ð³Ñк ÑлÑÐ¶Ð±Ð°Ñ ÑпеÑÑÑлÑМÑÑ
ЌагÑÑЌаÑÑей."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐакÑаМÑÑеÑÑ, каб аЎклÑÑÑÑÑ Ð³Ñк. ÐПжа бÑÑÑ Ð°ÐŽÐºÐ»ÑÑÐ°ÐœÑ Ð³Ñк ÑлÑÐ¶Ð±Ð°Ñ ÑпеÑÑÑлÑМÑÑ
ЌагÑÑЌаÑÑей."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вÑбÑÑÑаваÑÑ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Ð ÑгÑлÑÑÐ°Ñ Ð³ÑÑМаÑÑÑ %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐÐ»Ñ Ð²ÑклÑÐºÐ°Ñ Ñ Ð°Ð¿Ð°Ð²ÑÑÑÑММÑÑ ÑклÑÑÐ°ÐœÑ Ð³Ñк (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÐеÑайÑÑÑ ÐŽÐ° МалаЎ вÑваЎÑ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐÐµÐœÑ Ð· паÑзÑÐœÐºÐ°ÐŒÑ Ð³ÑÑМаÑÑÑ ÑазгПÑМÑÑа"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐÐµÐœÑ Ð· паÑзÑÐœÐºÐ°ÐŒÑ Ð³ÑÑМаÑÑÑ Ð·Ð³ÐŸÑМÑÑа"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"вÑклÑÑÑÑÑ Ð³Ñк (%s)"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ÑклÑÑÑÑÑ Ð³Ñк (%s)"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> пÑайгÑаеÑÑа ÑÑÑ:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑÐŽÑÑвÑÑ
аЎ:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ÐалаЎка ÑÑÑÑÑЌМага ÑМÑÑÑÑейÑÑ ÐºÐ°ÑÑÑÑалÑМÑка"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐеÑаÑ
ПЎзÑÑÑ Ð¿Ð°ÐŒÑж МÑЎаÑМÑÐŒÑ Ð¿ÑагÑаЌаЌÑ, пеÑаЌÑÑÑаÑÑÑÑÑ ÑпеÑаЎ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐеÑаÑ
ПЎзÑÑÑ Ð¿Ð°ÐŒÑж МÑЎаÑМÑÐŒÑ Ð¿ÑагÑаЌаЌÑ, пеÑаЌÑÑÑаÑÑÑÑÑ ÐœÐ°Ð·Ð°ÐŽ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐЎкÑÑÑÑ ÑпÑÑ Ð¿ÑагÑаЌ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐаказаÑÑ Ð¿Ð°ÐœÑÐ»Ñ Ð·Ð°ÐŽÐ°Ñ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐЎкÑÑÑÑ ÐœÐ°Ð»Ð°ÐŽÑ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑклÑкаÑÑ ÐаЌПÑМÑка"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐкÑаМ блакÑÑПÑкÑ"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐеÑайÑÑÑ Ñ ÑÑжÑÐŒ паЎзелеМага ÑкÑаМа з бÑгÑÑай пÑагÑаЌай ÑпÑава"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐеÑайÑÑÑ Ñ ÑÑжÑÐŒ паЎзелеМага ÑкÑаМа з бÑгÑÑай пÑагÑаЌай злева"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐеÑаклÑÑÑÑÑа з ÑÑжÑÐŒÑ Ð¿Ð°ÐŽÐ·ÐµÐ»ÐµÐœÐ°Ð³Ð° ÑкÑаМа Ма пПÑМаÑкÑÐ°ÐœÐœÑ ÑÑжÑÐŒ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"У ÑÑжÑЌе паЎзелеМага ÑкÑаМа заЌÑМÑÑÑ Ð°ÐŽÐœÑ Ð¿ÑагÑÐ°ÐŒÑ ÐœÐ° ÑМÑÑÑ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"УвПЎ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐеÑаклÑÑÑÑÑа Ма МаÑÑÑпМÑÑ ÐŒÐŸÐ²Ñ"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑа заблакÑÑаваМа"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑа Ñ ÐŒÑкÑаÑПМ заблакÑÑаваМÑ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐÑкÑаÑПМ заблакÑÑаваМÑ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе ÑÑÑбаваÑÑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c8539e6..62c95b2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ÐÑавеМеÑП Ма екÑаММО ÑМОЌкО е блПкОÑаМП ÐŸÑ ÑОÑÑÐµÐŒÐœÐžÑ Ð²Ðž аЎЌОМОÑÑÑаÑПÑ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"РеЎакÑОÑаМе"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"РеЎакÑОÑаМе Ма екÑаММаÑа ÑМОЌка"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"СпПЎелÑМе Ма екÑаММаÑа ÑМОЌка"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÐаÑМеЌаМе Ма ПÑе"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐÑÑ
вÑÑлÑМе Ма екÑаММаÑа ÑМОЌка"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ТПва ÑÑÑÑПйÑÑвП Ñе ÑпÑавлÑва ÐŸÑ ÑПЎОÑÐµÐ»Ñ Ð²Ðž. ТПй ЌПже Ўа вОжЎа О ÑпÑавлÑва ОМÑПÑЌаÑОÑ, каÑП МапÑÐžÐŒÐµÑ Ð¿ÑОлПжеМОÑÑа, кПОÑП ОзпПлзваÑе, ЌеÑÑПпПлПжеМОеÑП вО О вÑеЌеÑП Ма пПлзваМе."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ÐПЎЎÑÑжа Ñе ПÑклÑÑеМП ÐŸÑ ÐœÐ°ÐŽÐµÐ¶ÐŽÐµÐœ агеМÑ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐаÑОÑа ÐŸÑ ÐºÑажба\nУ-вПÑП е закл., ÑвÑÑЎе ЌМПгП ПпОÑО за ПÑкл."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"УÑÑÑПйÑÑвПÑП бе заклÑÑеМП. ТвÑÑЎе ЌМПгП ПпОÑО за ÑЎПÑÑПвеÑÑваМе"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"УÑÑÑПйÑÑвПÑП е заклÑÑеМП\nÐеÑÑпеÑМП ÑЎПÑÑПвеÑÑваМе"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐаÑÑÑПйкО за звÑка"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐÐµÐŽÐžÑ Ñ Ð°Ð²ÑПЌаÑОÑМО МаЎпОÑО"</string>
@@ -752,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐÑевÑÑÑаМе МапÑеЎ пÑез ÑкПÑПÑМОÑе пÑОлПжеМОÑ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐÑевÑÑÑаМе МазаЎ пÑез ÑкПÑПÑМОÑе пÑОлПжеМОÑ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐÑваÑÑМе Ма ÑпОÑÑка Ñ Ð¿ÑОлПжеМОÑ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐПказваМе Ма леМÑаÑа Ма заЎаÑОÑе"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐÑваÑÑМе Ма МаÑÑÑПйкОÑе"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑваÑÑМе Ма ÐÑОÑÑеМÑ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐаклÑÑваМе Ма екÑаМа"</string>
@@ -761,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐÑеЌОМаваМе кÑÐŒ ÑазЎелеМ екÑаМ Ñ ÑекÑÑПÑП пÑОлПжеМОе ПÑÐŽÑÑМП"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐÑеЌОМаваМе кÑÐŒ ÑазЎелеМ екÑаМ Ñ ÑекÑÑПÑП пÑОлПжеМОе ПÑлÑвП"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐÑевклÑÑваМе ÐŸÑ ÑазЎелеМ кÑÐŒ ÑÑл екÑаМ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐÑО ÑазЎелеМ екÑаМ: заЌÑМа Ма ЎаЎеМП пÑОлПжеМОе Ñ ÐŽÑÑгП"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐÑвежЎаМе"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐÑевклÑÑваМе кÑÐŒ ÑлеЎваÑÐžÑ ÐµÐ·ÐžÐº"</string>
@@ -1259,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐПÑÑÑпÑÑ ÐŽÐŸ каЌеÑаÑа е блПкОÑаМ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐПÑÑÑпÑÑ ÐŽÐŸ каЌеÑаÑа О ЌОкÑПÑПМа е блПкОÑаМ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐПÑÑÑпÑÑ ÐŽÐŸ ЌОкÑПÑПМа е блПкОÑаМ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе безпПкПйÑе"</string>
<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>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index dac69cb..abfbfcc 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àŠàŠªàŠšàŠŸàŠ° àŠàŠàŠàŠ¿ àŠ
à§àŠ¯àŠŸàŠ¡àŠ®àŠ¿àŠš àŠžà§àŠà§àŠ°àŠ¿àŠšàŠ¶àŠ àŠšà§àŠàŠ¯àŠŒàŠŸàŠ° àŠžà§àŠ¬àŠ¿àŠ§àŠŸ àŠ¬à§àŠ²àŠ àŠàаà§àŠà§àŠš"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"àŠàŠ¡àŠ¿àŠ àŠàаà§àŠš"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"àŠžà§àŠà§àŠ°àŠ¿àŠšàŠ¶àŠ àŠàŠ¡àŠ¿àŠ àŠàаà§àŠš"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"àŠžà§àŠà§àŠ°àŠ¿àŠšàŠ¶àŠ àŠ¶à§àŠ¯àŠŒàŠŸàŠ° àŠàаà§àŠš"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àŠàŠ°àŠ àŠ¬à§àŠ¶àŠ¿ àŠà§àŠ¯àŠŸàŠªàŠàŠŸàŠ° àŠàаà§àŠš"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àŠžà§àŠà§àŠ°àŠ¿àŠšàŠ¶àŠ àŠ¬àŠŸàŠ€àŠ¿àŠ² àŠàаà§àŠš"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"àŠ²àŠ àŠžà§àŠà§àŠ°àŠ¿àŠšà§ àŠ¯à§àŠà§àŠšàŠ àŠàŠàŠà§àŠàŠà§ àŠ
àŠšà§àŠ®àŠ€àŠ¿ àŠŠà§àЬà§àŠš?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"àŠžà§àŠàŠ¿àŠàŠž àŠà§àвà§àŠš"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"àŠ
àŠ«àŠ¿àŠžà§àа àŠ
à§àŠ¯àŠŸàŠª àŠàŠšàŠªàŠ àŠàŠ°àŠ€à§ àŠàŠŸàŠš?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"àŠàŠšàŠªàŠ àŠàаà§àŠš"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ°àŠàŠŸàŠ°à§ àŠªàŠŸàŠ²à§àŠà§ àŠŠàŠ¿àŠš"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àŠàŠªàŠšàŠŸàŠ° àŠ
àŠàŠ¿àŠàŠŸàŠ¬àŠ àŠàŠ àŠ¡àŠ¿àŠàŠŸàŠàŠž àŠ®à§àŠ¯àŠŸàŠšà§àŠ àŠàаà§àŠšà¥€ àŠàŠªàŠšàŠŸàŠ° àŠ
àŠàŠ¿àŠàŠŸàŠ¬àŠ àŠàŠªàŠšàŠŸàŠ° àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°àŠŸ àŠ
à§àŠ¯àŠŸàŠª, àŠ²à§àŠà§àŠ¶àŠš àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš àŠàŠŸàŠàŠ®à§àа àŠ®àŠ€à§ àŠ€àŠ¥à§àНàŠà§àŠ²àŠ¿ àŠŠà§àŠàŠ€à§ àŠàŠ¬àŠ àŠ®à§àŠ¯àŠŸàŠšà§àŠ àŠàŠ°àŠ€à§ àŠªàŠŸàŠ°à§àŠšà¥€"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent àŠŠàŠ¿àŠ¯àŠŒà§ àŠàŠšàŠ²àŠ àŠàŠ°à§ àŠ°àŠŸàŠàŠŸ àŠ¹àŠ¯àŠŒà§àŠà§"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àŠà§àŠ°àŠ¿ àŠ¥à§àŠà§ àŠžà§àаàŠà§àŠ·àŠŸ\nàŠ¡àŠ¿àŠàŠŸàŠàŠž àŠ²àŠ àŠàŠ°àŠŸ àŠàŠà§, àŠàŠšàŠ²àŠ àŠàŠ°àŠŸàŠ° àŠàŠšà§àН àŠ
àŠšà§àŠàŠ¬àŠŸàŠ° àŠà§àŠ·à§àŠàŠŸ àŠàŠ°àŠŸ àŠ¹àŠ¯àŠŒà§àŠà§"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àŠžàŠŸàŠàŠšà§àŠ¡ àŠžà§àŠàŠ¿àŠàŠž"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"àŠ
àŠà§àŠ®à§àŠàŠ¿àŠ àŠ®àŠ¿àŠ¡àŠ¿àŠ¯àŠŒàŠŸ àŠà§àŠ¯àŠŸàŠªàŠ¶àŠš àŠŠà§àŠà§àŠš"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àŠ®àŠ¿àŠàŠ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"àŠàŠŸàŠžà§àŠ àŠàаà§àŠš"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"àŠ°àŠ¿àŠ àŠ®àŠ¿àŠàŠ àŠàŠ°àŠŸ àŠ¹àŠ¯àŠŒà§àŠà§ àŠ¬àŠ²à§ àŠàŠªàŠ²àŠà§àН àŠšà§àŠ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'àŠ¬àŠ¿àŠ°àŠà§àŠ€ àŠàŠ°àŠ¬à§ àŠšàŠŸ\' àŠ®à§àŠ¡ àŠàŠŸàŠ²à§ àŠ¥àŠŸàŠàŠŸàŠ° àŠàŠšà§àН àŠàŠªàŠ²àŠà§àН àŠšà§àŠ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"\'àŠ¬àŠ¿àŠ°àŠà§àŠ€ àŠàŠ°àŠ¬à§ àŠšàŠŸ\' àŠ®à§àŠ¡ àŠàŠŸàŠ²à§ àŠ¥àŠŸàŠàŠŸàŠ° àŠàŠšà§àН àŠàŠªàŠ²àŠà§àН àŠšà§àŠ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sी àŠžàŠ¶àŠ¬à§àŠŠ àŠàŠ°àŠ€à§ àŠàŠ²àŠ€à§ àŠàŠŸàŠªà§àŠšà¥€"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sी àŠàŠ®à§àŠªàŠš àŠ àŠžà§àŠ àŠàŠ°àŠ€à§ àŠàŠ²àŠ€à§ àŠàŠŸàŠªà§àŠšà¥€ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠžàŠ¯à§àŠà§àŠ¯àŠ€àŠŸàŠ° àŠªàŠ°àŠ¿àŠ·à§àŠ¬àŠŸàŠà§àŠ²àŠ¿àŠà§ àŠ®àŠ¿àŠàŠ àŠàŠ°àŠŸ àŠ¹àŠ€à§ àŠªàŠŸàŠ°à§à¥€"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sी àŠ®àŠ¿àŠàŠ àŠàŠ°àŠ€à§ àŠàŠ²àŠ€à§ àŠàŠŸàŠªà§àŠšà¥€ àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠžàŠ¯à§àŠà§àŠ¯àŠ€àŠŸàŠ° àŠªàŠ°àŠ¿àŠ·à§àŠ¬àŠŸàŠà§àŠ²àŠ¿àŠà§ àŠ®àŠ¿àŠàŠ àŠàŠ°àŠŸ àŠ¹àŠ€à§ àŠªàŠŸàŠ°à§à¥€"</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"àŠàŠŸàŠàЬà§àаà§àŠ àŠàŠ°àŠŸàŠš"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s àŠàŠ²àŠ¿àŠàŠ® àŠšàŠ¿àŠ¯àŠŒàŠšà§àŠ€à§àŠ°àŠ£"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àŠàв àŠàŠ¬àŠ àŠ¬àŠ¿àŠà§àŠàŠªà§àŠ€àŠ¿àŠ° àŠ°àŠ¿àŠ àŠ¹àŠ¬à§ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"àŠàŠàŠàŠªà§àŠ àŠžà§àŠàŠ¿àŠàŠž àŠ²àŠ¿àŠà§àŠš"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àŠàŠ²àŠ¿àŠàŠ® àŠžà§àŠ²àŠŸàŠàŠ¡àŠŸàŠ° àŠ¬àŠ¡àŠŒ àŠàŠ°àŠŸ àŠ¹àŠ¯àŠŒà§àŠà§"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"àŠàŠ²àŠ¿àŠàŠ® àŠžà§àŠ²àŠŸàŠàŠ¡àŠŸàŠ° àŠàŠ¡àŠŒàŠŸàŠ² àŠàŠ°àŠŸ àŠ¹àŠ¯àŠŒà§àŠà§"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s àŠ®àŠ¿àŠàŠ àŠàаà§àŠš"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s àŠàŠšàŠ®àŠ¿àŠàŠ àŠàаà§àŠš"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>-àŠ àŠªà§àŠ²à§ àŠàŠ°àŠŸ àŠ¹àŠà§àŠà§"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"àŠ
àŠ¡àŠ¿àŠ àŠªà§àŠ²à§ àŠàŠ°àŠŸ àŠ¹àŠ¬à§"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"àŠžàŠ¿àŠžà§àŠà§àŠ® UI àŠàŠ¿àŠàŠšàŠŸàŠ°"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"àŠžàŠŸàŠ®à§àŠªà§àŠ°àŠ€àŠ¿àŠ àŠ
à§àŠ¯àŠŸàŠªà§àа àŠ®àŠŸàŠ§à§àŠ¯àŠ®à§ àŠªàŠ°àŠ¬àŠ°à§àŠ€à§ àŠàŠŸàŠ¯àŠŒàŠàŠŸàŠ¯àŠŒ àŠ¯àŠŸàŠš"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"àŠžàŠŸàŠ®à§àŠªà§àŠ°àŠ€àŠ¿àŠ àŠ
à§àŠ¯àŠŸàŠªà§àа àŠ®àŠŸàŠ§à§àŠ¯àŠ®à§ àŠàŠà§àа àŠàŠŸàŠ¯àŠŒàŠàŠŸàŠ¯àŠŒ àŠ«àŠ¿àŠ°à§àŠš"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"àŠ
à§àŠ¯àŠŸàŠªà§àа àŠ€àŠŸàŠ²àŠ¿àŠàŠŸ àŠà§àвà§àŠš"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"àŠàŠŸàŠžà§àŠàŠ¬àŠŸàŠ° àŠŠà§àŠà§àŠš"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"àŠžà§àŠàŠ¿àŠàŠž àŠà§àвà§àŠš"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant àŠà§àвà§àŠš"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"àŠ²àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"àŠ¡àŠŸàŠšàŠŠàŠ¿àŠà§ àŠ¥àŠŸàŠàŠŸ àŠ¬àŠ°à§àŠ€àŠ®àŠŸàŠš àŠ
à§àŠ¯àŠŸàŠª àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°à§ \'àŠžà§àŠªà§àŠ²àŠ¿àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš\' àŠ¯à§àŠ àŠàаà§àŠš"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"àŠ¬àŠŸàŠàŠŠàŠ¿àŠà§ àŠ¥àŠŸàŠàŠŸ àŠ¬àŠ°à§àŠ€àŠ®àŠŸàŠš àŠ
à§àŠ¯àŠŸàŠª àŠ¬à§àŠ¯àŠ¬àŠ¹àŠŸàŠ° àŠàŠ°à§ \'àŠžà§àŠªà§àŠ²àŠ¿àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš\' àŠ¯à§àŠ àŠàаà§àŠš"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"\'àŠžà§àŠªà§àŠ²àŠ¿àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš\' àŠ¥à§àŠà§ àŠ«à§àв àŠžà§àŠà§àŠ°àŠ¿àŠšà§ àŠªàŠŸàŠ²à§àŠàŠŸàŠš"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"\'àŠžà§àŠªà§àŠ²àŠ¿àŠ àŠžà§àŠà§àŠ°àŠ¿àŠš\' àŠ¥àŠŸàŠàŠŸàŠàŠŸàŠ²à§àŠš: àŠàŠàŠàŠ¿ àŠ
à§àŠ¯àŠŸàŠª àŠ¥à§àŠà§ àŠ
àŠšà§àНàŠàŠ¿àŠ€à§ àŠªàŠŸàŠ²à§àŠàŠŸàŠš"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àŠàŠšàŠªà§àŠ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"àŠªàŠ°àŠ¬àŠ°à§àŠ€à§ àŠàŠŸàŠ·àŠŸàŠ¯àŠŒ àŠªàŠŸàŠ²à§àŠàŠŸàŠš"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àŠà§àŠ¯àŠŸàŠ®à§àŠ°àŠŸàŠ° àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠ¬à§àŠ²àŠ àŠàŠ°àŠŸ àŠàŠà§"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àŠà§àŠ¯àŠŸàŠ®à§àŠ°àŠŸ àŠàŠ¬àŠ àŠ®àŠŸàŠàŠà§àаà§àŠ«à§àŠšà§àа àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠ¬à§àŠ²àŠ àŠàŠ°àŠŸ àŠàŠà§"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"àŠ®àŠŸàŠàŠà§àаà§àŠ«à§àŠšà§àа àŠ
à§àŠ¯àŠŸàŠà§àŠžà§àŠž àŠ¬à§àŠ²àŠ àŠàŠ°àŠŸ àŠàŠà§"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àŠ¬àŠ¿àŠ°àŠà§àŠ€ àŠàŠ°àŠ¬à§ àŠšàŠŸ"</string>
<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>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index dd4fee0..75a2f94 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Snimanje ekrana je blokirao IT administrator"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredite"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Uredite snimak ekrana"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Dijeljenje snimka ekrana"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimi više"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
@@ -437,7 +439,7 @@
<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="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Åœelite li dopustiti bilo koji widget na zakljuÄanom zaslonu?"</string>
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Dozvoliti bilo koji vidÅŸet na zakljuÄanom ekranu?"</string>
<string name="button_text_to_open_settings" msgid="1987729256950941628">"Otvori postavke"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"Pokrenuti poslovne aplikacije?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"Ponovo pokreni"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim ureÄajem upravlja tvoj roditelj. Roditelj moÅŸe vidjeti i upravljati informacijama kao što su aplikacije koje koristiš, lokacija i vrijeme korištenja ureÄaja."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent spreÄava zakljuÄavanje"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Zaštita od kraÄe\nUreÄaj je zakljuÄan, previše pokušaja otkljuÄ."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"UreÄaj je bio zakljuÄan zbog previše pokušaja autentifikacije"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"UreÄaj je zakljuÄan\nAutentifikacija nije uspjela"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Postavke zvuka"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatski titlovi za medije"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"IskljuÄi zvuk"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Emitiraj"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno zbog iskljuÄenog zvona"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je funkcija Ne ometaj ukljuÄena"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je funkcija Ne ometaj ukljuÄena"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da ukljuÄite zvukove."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite za postavljanje vibracije. Zvukovi usluga pristupaÄnosti mogu biti iskljuÄeni."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da iskljuÄite zvuk. Zvukovi usluga pristupaÄnosti mogu biti iskljuÄeni."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Kontrole glasnoÄe za %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Pozivi i obavještenja Äe zvoniti jaÄinom (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unos postavki izlaza"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"KlizaÄi jaÄine zvuka su prošireni"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"KlizaÄi jaÄine zvuka su suÅŸeni"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"iskljuÄivanje parametra %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ukljuÄivanje parametra %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproduciranje: <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk Äe se reprod. na:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"PodešavaÄ za korisniÄki interfejs sistema"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"KruÅŸenje kroz nedavne aplikacije unaprijed"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"KruÅŸenje kroz nedavne aplikacije unazad"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvaranje liste aplikacija"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Prikaz trake zadataka"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvaranje postavki"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvaranje Asistenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ZakljuÄavanje ekrana"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Otvaranje podijeljenog ekrana s trenutnom aplikacijom na desnoj strani"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Otvaranje podijeljenog ekrana s trenutnom aplikacijom na lijevoj strani"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Prebacivanje s podijeljenog ekrana na prikaz preko cijelog ekrana"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Za vrijeme podijeljenog ekrana: zamjena jedne aplikacije drugom"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Prebacivanje na sljedeÄi jezik"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne ometaj"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkriveno je prisustvo korisnika"</string>
<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>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bf5e58c..d31fb06 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"El teu administrador de TI ha bloquejat les captures de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edita"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edita la captura de pantalla"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Comparteix la captura de pantalla"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Captura més"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora la captura de pantalla"</string>
@@ -272,7 +274,7 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activa"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Torna\'l a activar automàticament demà"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="8267380591344023327">"Funcions com ara Quick Share, Troba el meu dispositiu i la ubicació del dispositiu utilitzen el Bluetooth"</string>
- <string name="turn_on_bluetooth_auto_info_enabled" msgid="4802071533678400330">"Bluetooth s\'activarà a les 5:00 h demà"</string>
+ <string name="turn_on_bluetooth_auto_info_enabled" msgid="4802071533678400330">"El Bluetooth s\'activarà demà a les 5:00 h"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloquejat per TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protecció antirobatoris\nDispositiu bloquejat; massa intents"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Configuració del so"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Subtitula el contingut multimèdia automàticament"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silencia"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Emet"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible perquè el so està silenciat"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible perquè No molestis està activat"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible perquè No molestis està activat"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca per activar el so."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controls de volum %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Les trucades i les notificacions sonaran (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introdueix opcions de configuració de sortida"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Els controls lliscants de volum s\'han desplegat"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Els controls lliscants de volum s\'han replegat"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silencia %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"deixa de silenciar %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"S\'està reproduint <xliff:g id="LABEL">%s</xliff:g> a"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Es reproduirà a"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Personalitzador d\'interfície d\'usuari"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Desplaça\'t cap endavant per les aplicacions recents"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Desplaça\'t cap enrere per les aplicacions recents"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Obre la llista d\'aplicacions"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostra la barra de tasques"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Obre la configuració"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Obre l\'Assistent"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueig"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Entra al mode de pantalla dividida amb l\'aplicació actual a la dreta"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Entra al mode de pantalla dividida amb l\'aplicació actual a l\'esquerra"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Canvia de pantalla dividida a pantalla completa"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durant el mode de pantalla dividida: substitueix una app per una altra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Canvia a l\'idioma següent"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"No molestis"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"S\'ha detectat la presència d\'usuaris"</string>
<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>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5e8acfa..995d994 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"PoÅizování snímků obrazovky je blokováno administrátorem IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Upravit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Upravit snímek obrazovky"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Sdílet snímek obrazovky"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ZvÄtšit zábÄr snímku"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ZavÅít snímek obrazovky"</string>
@@ -100,7 +102,7 @@
<string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> objevila tento snímek obrazovky."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ostatní otevÅené aplikace objevily tento snímek obrazovky."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"PÅidat do poznámky"</string>
- <string name="screenrecord_title" msgid="4257171601439507792">"Rekordér obrazovky"</string>
+ <string name="screenrecord_title" msgid="4257171601439507792">"Nahrávání obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
<string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"ZaÄít nahrávat?"</string>
@@ -291,7 +293,7 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"UÅŸivatel"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <string name="quick_settings_networks_available" msgid="1875138606855420438">"SítÄ jsou k dispozici"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"SítÄ k dispozici"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"SítÄ nejsou k dispozici"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Åœádné sítÄ Wi-Fi nejsou k dispozici"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Zapínání…"</string>
@@ -341,7 +343,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
- <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekordér obrazovky"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Nahrávání 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>
<string name="qs_record_issue_label" msgid="8166290137285529059">"Zaznamenat problém"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Toto zaÅízení spravuje rodiÄ. RodiÄ můşe zobrazit údaje, jako jsou pouÅŸívané aplikace, tvá poloha a Äas strávený na zaÅízení."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odemknutí udrÅŸováno funkcí TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ochrana pÅed odcizením\nZamknuto, moc pokusů o odemknutí"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ZaÅízení uzamÄeno, pÅíliš mnoho pokusů o ovÄÅení"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ZaÅízení uzamÄeno\nOvÄÅení se nezdaÅilo"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Nastavení zvuku"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatické pÅepisy médií"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ztlumení"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Odesílání"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, protoÅŸe vyzvánÄní je ztlumené"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupné, protoÅŸe je zapnutý reÅŸim Nerušit"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupné, protoÅŸe je zapnutý reÅŸim Nerušit"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnete zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujete reÅŸim vibrací. SluÅŸby pÅístupnosti mohou být ztlumeny."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. SluÅŸby pÅístupnosti mohou být ztlumeny."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Ovládací prvky hlasitosti %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Volání a oznámení budou vyzvánÄt (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"OtevÅít nastavení výstupu"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Posuvníky hlasitosti jsou rozbalené"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Posuvníky hlasitosti jsou sbalené"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ztlumíte %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"zapnete zvuk %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"PÅehrávání <xliff:g id="LABEL">%s</xliff:g> na"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk se pÅehraje na"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Nástroj na ladÄní uÅŸivatelského rozhraní systému"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Procházet nedávné aplikace smÄrem vpÅed"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Procházet nedávné aplikace smÄrem zpÄt"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"OtevÅít seznam aplikací"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Zobrazit panel aplikací"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"OtevÅít nastavení"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"OtevÅít Asistenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknout obrazovku"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"PÅepnout na rozdÄlenou obrazovku s aktuálními aplikacemi napravo"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"PÅepnout na rozdÄlenou obrazovku s aktuálními aplikacemi nalevo"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"PÅepnout z rozdÄlené obrazovky na celou obrazovku"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"V reÅŸimu rozdÄlené obrazovky: nahradit jednu aplikaci druhou"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vstup"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"PÅepnout na další jazyk"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokována"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokován"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ReÅŸim Nerušit"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Je zjištÄna pÅítomnost uÅŸivatele"</string>
<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>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8e178e8..32f8336 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Din it-administrator har blokeret screenshot-funktionen"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Del screenshottet"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Medtag mere"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Luk screenshot"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Denne enhed administreres af din forælder. Din forælder kan se og administrere oplysninger såsom de apps, du bruger, din lokation og din skærmtid."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes oplåst af TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Tyveribeskyttelse\nLåst enhed (for mange oplåsningsforsøg)"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Enheden er låst efter for mange forsøg på godkendelse"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Enheden er låst\nGodkendelsen mislykkedes"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Lydindstillinger"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Undertekster til medier"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Slå lyden fra"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ikke muligt, da ringetonen er slået fra"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ikke tilgængelig, fordi Forstyr ikke er aktiveret"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ikke tilgængelig, fordi Forstyr ikke er aktiveret"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryk for at slå lyden til."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s lydstyrkeknapper"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Der afspilles lyd ved opkald og notifikationer (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Angiv indstillinger for output"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Lydstyrkeskydere er udvidet"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Lydstyrkeskydere er skjult"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"slå lyden fra for %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå lyden til for %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Afspiller <xliff:g id="LABEL">%s</xliff:g> på"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Lyden afspilles på"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Gå frem i dine seneste apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Gå tilbage i dine seneste apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Åbn appfortegnelse"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Vis proceslinje"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Åbn indstillinger"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Åbn Assistent"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skærm"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Start opdelt skærm med aktuel app til højre"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Start opdelt skærm med aktuel app til venstre"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Skift fra opdelt skærm til fuld skærm"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ved opdelt skærm: Udskift én app med en anden"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skift til næste sprog"</string>
@@ -1008,8 +1007,8 @@
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Angivet som favorit"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Angivet som favorit. Position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjernet fra favoritter"</string>
- <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"markér som favorit"</string>
- <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"fjern fra favoritter"</string>
+ <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"markere som favorit"</string>
+ <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"fjerne som favorit"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Flyt til position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Betjeningselementer"</string>
<string name="controls_favorite_subtitle" msgid="5818709315630850796">"Vælg, hvilke enhedsindstillinger du vil have hurtig adgang til"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Forstyr ikke"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Brugertilstedeværelse er registreret"</string>
<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>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a61e802..6768608 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Dein IT-Administrator hat das Erstellen von Screenshots blockiert"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Bearbeiten"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bearbeiten"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Screenshot teilen"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mehr aufnehmen"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dieses Gerät wird von deinen Eltern verwaltet. Sie können unter anderem Informationen über deine genutzten Apps, deinen Standort und deine Bildschirmzeit einsehen und verwalten."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Durch TrustAgent entsperrt"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Diebstahlschutz\nGerät gesperrt – zu viele Entsperrversuche"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Toneinstellungen"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Medien autom. untertiteln"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Stummschalten"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Stream"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nicht verfügbar, da Klingelton stumm"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nicht verfügbar, weil „Bitte nicht stören“ an ist"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nicht verfügbar, weil „Bitte nicht stören“ an ist"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"Vibrieren lassen"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Lautstärkeregler von %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Gerät klingelt bei Anrufen und Benachrichtigungen (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ausgabeeinstellungen angeben"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Lautstärkeregler maximiert"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Lautstärkeregler minimiert"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s stummzuschalten"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"Stummschaltung von %s aufzuheben"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Wiedergabe von <xliff:g id="LABEL">%s</xliff:g> über"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audiowiedergabe über"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Zuletzt verwendete Apps vorwärts durchgehen"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Zuletzt verwendete Apps rückwärts durchgehen"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Liste der Apps öffnen"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Taskleiste anzeigen"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Einstellungen öffnen"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant öffnen"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Sperrbildschirm"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Splitscreen aktivieren, aktuelle App rechts"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Splitscreen aktivieren, aktuelle App links"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Vom Splitscreen zum Vollbild wechseln"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Im Splitscreen: eine App durch eine andere ersetzen"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Eingabe"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Zur nächsten Sprache wechseln"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blockiert"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera und Mikrofon blockiert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon blockiert"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Bitte nicht stören"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Anwesenheit des Nutzers wurde erkannt"</string>
<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>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3167843..c7d4825 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Η λήψη στιγμιÏτυπων οθÏνης Îχει αποκλειστεί απÏ τον διαχειριστή IT."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Επεξεργασία"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Επεξεργασία στιγμιÏτυπου οθÏνης"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Κοινοποίηση στιγμιÏτυπου οθÏνης"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ΠερισσÏτερα"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Παράβλεψη στιγμιÏτυπου οθÏνης"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Αυτή η συσκευή είναι διαχειριζÏμενη απÏ τον γονÎα σου. Ο γονÎας σου μπορεί να βλÎπει και να διαχειρίζεται πληροφορίες Ïπως οι εφαρμογÎς που χρησιμοποιείς, η τοποθεσία σου και ο χρÏνος χρήσης."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Διατήρηση ξεκλειδÏματος με TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Προστασία απÏ κλοπή\nΗ συσκ. κλειδ., πάρα πολλÎς προσπ. ξεκλ."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Η συσκευή ήταν κλειδωμÎνη, πάρα πολλÎς προσπάθειες ελÎγχου ταυτÏτητας"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Η συσκευή είναι κλειδωμÎνη\nΟ Îλεγχος ταυτÏτητας απÎτυχε"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ρυθμίσεις ήχου"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ΑυτÏματοι υπÏτιτλοι στο μÎσο"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Σίγαση"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Μετάδοση"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Μη διαθÎσιμο λÏγω σίγασης ήχου κλήσης"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Μη διαθ. επειδή η λειτ. Μην ενοχλείτε είναι ενεργή"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Μη διαθ. επειδή η λειτ. Μην ενοχλείτε είναι ενεργή"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Πατήστε για ενεργοποιήσετε τη δÏνηση. Οι υπηρεσίες προσβασιμÏτητας ενδÎχεται να τεθοÏν σε σίγαση."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμÏτητας ενδÎχεται να τεθοÏν σε σίγαση."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δÏνηση"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s στοιχεία ελÎγχου Îντασης ήχου"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Θα υπάρχει ηχητική ειδοποίηση για κλήσεις και ειδοποιήσεις (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Εισαγωγή ρυθμίσεων εξÏδου"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Τα ρυθμιστικά Îντασης ήχου αναπτÏχθηκαν"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Τα ρυθμιστικά Îντασης ήχου συμπτÏχθηκαν"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"σίγαση %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"κατάργηση σίγασης %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Αναπαραγωγή <xliff:g id="LABEL">%s</xliff:g> σε"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ο Î®χος θα παίξει σε"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Περιήγηση προς τα εμπρÏς σε πρÏσφατες εφαρμογÎς"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Περιήγηση προς τα πίσω σε πρÏσφατες εφαρμογÎς"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Îνοιγμα λίστας εφαρμογÏν"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Εμφάνιση γραμμής εργαλείων"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Îνοιγμα ρυθμίσεων"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Îνοιγμα ΒοηθοÏ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Κλείδωμα οθÏνης"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Ενεργοποίηση διαχωρισμοÏ οθÏνης με την τρÎχουσα εφαρμογή στα δεξιά"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Ενεργοποίηση διαχωρισμοÏ οθÏνης με την τρÎχουσα εφαρμογή στα αριστερά"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Εναλλαγή απÏ διαχωρισμÏ οθÏνης σε πλήρη οθÏνη"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Κατά τον διαχωρισμÏ οθÏνης: αντικατάσταση μιας εφαρμογής με άλλη"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Είσοδος"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Εναλλαγή στην επÏμενη γλÏσσα"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Η κάμερα Îχει αποκλειστεί"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Η κάμερα και το μικρÏφωνο Îχουν αποκλειστεί"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Το μικρÏφωνο Îχει αποκλειστεί"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Μην ενοχλείτε"</string>
<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>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 6d79b47..ed9e816 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nDevice locked, too many unlock attempts"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatically caption media"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s volume controls"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Calls and notifications will ring (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cycle forwards through recent apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cycle backwards through recent apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Open apps list"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Show taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Open settings"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Do not disturb"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<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>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 62e0e57..99b3e31 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Share"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
@@ -538,7 +539,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps you use, your location, and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nDevice locked, too many unlock attempts"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatically caption media"</string>
@@ -752,7 +754,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cycle forward through recent apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cycle backward through recent apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Open apps list"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Show taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Open settings"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>
@@ -761,6 +762,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to app on right or below while using split screen"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to app on left or above while using split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: replace an app from one to another"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6d79b47..ed9e816 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nDevice locked, too many unlock attempts"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatically caption media"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s volume controls"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Calls and notifications will ring (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cycle forwards through recent apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cycle backwards through recent apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Open apps list"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Show taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Open settings"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Do not disturb"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<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>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 6d79b47..ed9e816 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nDevice locked, too many unlock attempts"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatically caption media"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Unavailable because Do Not Disturb is on"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Unavailable because Do Not Disturb is on"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s volume controls"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Calls and notifications will ring (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cycle forwards through recent apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cycle backwards through recent apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Open apps list"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Show taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Open settings"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Do not disturb"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<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>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 8b3a37f..fc7f605 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Taking screenshots is blocked by your IT admin"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Share"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Share screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
@@ -538,7 +539,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps you use, your location, and your screen time."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nDevice locked, too many unlock attempts"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatically caption media"</string>
@@ -752,7 +754,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cycle forward through recent apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cycle backward through recent apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Open apps list"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Show taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Open settings"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>
@@ -761,6 +762,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to app on right or below while using split screen"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to app on left or above while using split screen"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: replace an app from one to another"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Switch to next language"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ddeae20..129987e 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Tu administrador de TI bloquea las capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Descartar captura de pantalla"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tu padre o madre administra este dispositivo. Esa persona puede ver y administrar información, como las apps que usas, tu ubicación y el tiempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent lo mantiene desbloqueado"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protección antirrobo\nDispositivo bloqueado; muchos intentos"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Se bloqueó el dispositivo; demasiados intentos de autenticación"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Dispositivo bloqueado\nFalló la autenticación"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Configuración de sonido"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Muestra subtítulos automáticos"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmisión"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible por timbre silenciado"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible si está activado No interrumpir"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible si está activado No interrumpir"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Presiona para dejar de silenciar."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controles de volumen %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Sonarán las llamadas y notificaciones (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ingresar configuración de salida"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes del volumen expandidos"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes del volumen colapsados"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activar sonido %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproduciendo <xliff:g id="LABEL">%s</xliff:g> en"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Se reproducirá en"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador de IU del sistema"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Desplazar por las apps recientes (adelante)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Desplazar por las apps recientes (atrás)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de apps"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar Barra de tareas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configuración"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Asistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Bloquear la pantalla"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Activar pantalla dividida con la app actual en el lado derecho (RHS)"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Activar pantalla dividida con la app actual en el lado izquierdo (LHS)"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durante pantalla dividida: Reemplaza una app con otra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar al próximo idioma"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"No interrumpir"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Se detectó la presencia del usuario"</string>
<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>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index db65640..c01a44f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Tu administrador de TI ha bloqueado las capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cerrar captura de pantalla"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"¿Permitir cualquier widget en la pantalla de bloqueo?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"Abrir ajustes"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"¿Reactivar apps de trabajo?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"Reactivar"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tu padre o madre gestionan este dispositivo y pueden ver y controlar cierta información, como las aplicaciones que utilizas, tu ubicación y tu tiempo de pantalla."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protección antirrobo\nDispositivo bloqueado por nº de intentos"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ajustes de sonido"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Subtitular automáticamente"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Enviar"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible (el tono está silenciado)"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"No disponible porque No molestar está activado"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"No disponible porque No molestar está activado"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar el sonido."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controles de volumen %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Las llamadas y las notificaciones sonarán (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introducir los ajustes de salida"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volumen desplegados"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volumen contraídos"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"dejar de silenciar %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproduciendo <xliff:g id="LABEL">%s</xliff:g> en"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Se reproducirá en"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Configurador de UI del sistema"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Desplazarse por aplicaciones recientes (adelante)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Desplazarse por aplicaciones recientes (atrás)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de aplicaciones"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar barra de tareas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir ajustes"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir el Asistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Iniciar pantalla dividida con esta aplicación en el lado derecho"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Iniciar pantalla dividida con esta aplicación en el lado izquierdo"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Con pantalla dividida: reemplazar una aplicación por otra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar a siguiente idioma"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"No molestar"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Se ha detectado la presencia de usuarios"</string>
<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>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 04a2a9c..ff07693 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT-administraator on ekraanipiltide jäädvustamise blokeerinud"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Muutmine"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Ekraanipildi muutmine"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Jaga"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Jaga ekraanipilti"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Jäädvusta rohkem"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekraanipildist loobumine"</string>
@@ -538,7 +539,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Seda seadet haldab sinu vanem. Sinu vanem näeb ja saab hallata teavet, näiteks kasutatavaid rakendusi, sinu asukohta ja ekraaniaega."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Avatuna hoiab TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Vargusvastane kaitse\nSeade lukus – liiga palju avamiskatseid"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Heliseaded"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automaatsed subtiitrid"</string>
@@ -583,10 +587,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Vaigistatud"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Ülekandmine"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Pole saadaval, kuna helin on vaigistatud"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Pole saadaval, kuna reÅŸiim Mitte segada on sees"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Pole saadaval, kuna reÅŸiim Mitte segada on sees"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Puudutage värinareÅŸiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
@@ -603,16 +605,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Helitugevuse juhtnupud: %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Kõnede ja märguannete puhul telefon heliseb (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Sisestage väljundseaded"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Helitugevuse liugurid laiendatud"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Helitugevuse liugurid ahendatud"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"vaigistab %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"tühistab %s vaigistuse"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Esitamine jätkub seadmes <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Heli esitamine jätkub"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Süsteemi kasutajaliidese tuuner"</string>
@@ -759,7 +756,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Hiljutiste rakenduste hulgas edasi liikumine"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Hiljutiste rakenduste hulgas tagasi liikumine"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Rakenduste loendi avamine"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Tegumiriba kuvamine"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Seadete avamine"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistendi avamine"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lukustuskuva"</string>
@@ -768,6 +764,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Ekraanikuva jagamine, nii et praegune rakendus on paremal"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Ekraanikuva jagamine, nii et praegune rakendus on vasakul"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Jagatud ekraanikuvalt täisekraanile lülitamine"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Paremale või alumisele rakendusele lülitamine jagatud ekraani ajal"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vasakule või ülemisele rakendusele lülitamine jagatud ekraani ajal"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ekraanikuva jagamise ajal: ühe rakenduse asendamine teisega"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Sisend"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Järgmisele keelele lülitamine"</string>
@@ -1266,8 +1264,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Mitte segada"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Tuvastati kasutaja kohalolu"</string>
<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>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index faffa93..caed3b5 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IKT saileko administratzaileak blokeatu egin dizu pantaila-argazkiak ateratzeko aukera"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editatu"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editatu pantaila-argazkia"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Partekatu pantaila-argazkia"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Kapturatu eduki gehiago"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Baztertu pantaila-argazkia"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Pantaila blokeatuan edozein widget erakusteko baimena eman nahi duzu?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"Ireki ezarpenak"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"Laneko aplikazioak berraktibatu?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"Berraktibatu"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Zure gurasoak kudeatzen du gailua. Zure gurasoak gailuko informazioa ikusi eta kudea dezake; besteak beste, zer aplikazio erabiltzen dituzun, zure kokapena zein den eta pantaila aurrean zenbat eta noiz egoten zaren."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPNa"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent bidez desblokeatuta"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Lapurreten aurkako babesa\nGailua blokeatuta dago, desblokeatzeko saiakera gehiegi"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Soinuaren ezarpenak"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Ezarri azpitituluak automatikoki"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ez jo tonua"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Igorri"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ez dago erabilgarri, tonua desaktibatuta dagoelako"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ez dago erabilgarri, ez molestatzeko modua aktibatuta baitago"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ez dago erabilgarri, ez molestatzeko modua aktibatuta baitago"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sakatu audioa aktibatzeko."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s gailuaren bolumena kontrolatzeko aukerak"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Tonuak jo egingo du deiak eta jakinarazpenak jasotzean (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ireki emaitzaren ezarpenak"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Bolumenaren botoi lerrakorrak zabalduta daude"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Bolumenaren botoi lerrakorrak tolestuta daude"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desaktibatu honen audioa: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"aktibatu honen audioa: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> hemen erreproduzitzen:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audioa erreproduzitzen jarraituko du"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sistemaren erabiltzaile-interfazearen konfiguratzailea"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Ikusi azken aplikazioak banan-banan (aurrerantz)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Ikusi azken aplikazioak banan-banan (atzerantz)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ireki aplikazioen zerrenda"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Erakutsi zereginen barra"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ireki ezarpenak"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ireki Laguntzailea"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Blokeatu pantaila"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Sartu pantaila zatituaren eskuineko aldean oraingo aplikazioarekin"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Sartu pantaila zatituaren ezkerreko aldean oraingo aplikazioarekin"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Aldatu pantaila zatitutik pantaila osora"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Pantaila zatituan zaudela, ordeztu aplikazio bat beste batekin"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Sarrera"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Aldatu hurrengo hizkuntzara"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blokeatuta dago"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera eta mikrofonoa blokeatuta daude"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonoa blokeatuta dago"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ez molestatzeko modua"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Erabiltzailearen presentzia hauteman da"</string>
<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>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1e24158..03566d6 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"سرٟرست ÙÙØ§ÙØ±Û Ø§Ø·ÙØ§Ø¹Ø§Øª Ú¯Ø±ÙØªÙ ÙÙ
Ø§Ú¯Ø±ÙØª را Ù
Ø³Ø¯ÙØ¯ کرد٠است"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÙÛØ±Ø§ÛØŽ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÙÛØ±Ø§ÛØŽ ÙÙ
Ø§Ú¯Ø±ÙØª"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÙÙ
رساÙÛ ÙÙ
Ø§Ú¯Ø±ÙØª"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ضؚط Ù
ØØªÙØ§Û ØšÛØŽØªØ±"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کرد٠ÙÙ
Ø§Ú¯Ø±ÙØª"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"اÛ٠دستگا٠را ÙÙÛØªØ§Ù Ù
Ø¯ÛØ±Ûت Ù
ÛÚ©ÙØ¯. ÙÙÛØªØ§Ù Ù
ÛØªÙØ§ÙØ¯ Ø§Ø·ÙØ§Ø¹Ø§ØªÛ Ù
Ø«Ù ØšØ±ÙØ§Ù
ÙÙØ§ÛÛ Ú©Ù Ø§Ø³ØªÙØ§Ø¯Ù Ù
ÛÚ©ÙÛØ¯Ø Ù
Ú©Ø§ÙØªØ§ÙØ Ù Ù
دت تÙ
Ø§ØŽØ§Û ØµÙØÙØªØ§Ù را ؚؚÛÙØ¯ Ù Ù
Ø¯ÛØ±Ûت Ú©ÙØ¯."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ؚا TrustAgent ÙÙ٠را ؚاز ÙÚ¯ÙØ¯Ø§Ø±Ûد"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ù
ØØ§Ù؞ت درؚراؚر Ø³Ø±ÙØª\nدستگا٠ÙÙÙ ØŽØ¯Ø ØªØ¹Ø¯Ø§Ø¯ ØªÙØ§ØŽÙا ÙÙÙگ؎اÛÛ Ø§Ø² ØØ¯ Ù
جاز ØšÛØŽØªØ± ØšÙØ¯"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ØªÙØžÛÙ
ات صدا"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"رساÙÙ Ø²ÛØ±ÙÙÛØ³ Ø®ÙØ¯Ú©Ø§Ø±"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"صاÙ
ت"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ارسا٠Ù
ØØªÙا"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"دردسترس ÙÛØ³ØªØ ÚÙ٠زÙÚ¯ ØšÛØµØ¯Ø§ ؎د٠است"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"دردسترس ÙÛØ³Øª Ø²ÛØ±Ø§ «Ù
زاØÙ
ÙØŽÙÛØ¯» Ø±ÙØŽÙ است"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"دردسترس ÙÛØ³Øª Ø²ÛØ±Ø§ «Ù
زاØÙ
ÙØŽÙÛØ¯» Ø±ÙØŽÙ است"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ØšØ±Ø§Û ØšØ§ØµØ¯Ø§ کرد٠ضرؚ٠ؚزÙÛØ¯."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ØšØ±Ø§Û ØªÙØžÛÙ
رÙÛ ÙØ±Ø²ØŽ ضرؚ٠ؚزÙÛØ¯. Ù
Ù
ک٠است سرÙÛØ³ÙØ§Û Ø¯Ø³ØªØ±Ø³ÙŸØ°ÛØ±Û ØšÛØµØ¯Ø§ ØŽÙÙØ¯."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ØšØ±Ø§Û ØµØ§Ù
ت کرد٠ضرؚ٠ؚزÙÛØ¯. Ù
Ù
ک٠است سرÙÛØ³ÙØ§Û Ø¯Ø³ØªØ±Ø³ÙŸØ°ÛØ±Û صاÙ
ت ØŽÙØ¯."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÙØ±Ø²ØŽ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s Ú©ÙØªØ±ÙÙØ§Û Ù
ÛØ²Ø§Ù صدا"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"تÙ
Ø§Ø³ÙØ§ Ù Ø§Ø¹ÙØ§ÙÙØ§ زÙÚ¯ Ù
ÛØ®ÙØ±ÙØ¯ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ØªÙØžÛÙ
ات Ø®Ø±ÙØ¬Û را ÙØ§Ø±Ø¯ Ú©ÙÛØ¯"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÙØºØ²ÙدÙÙØ§Û صدا ازÙÙ
ؚاز ØŽØ¯ÙØ¯"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÙØºØ²ÙدÙÙØ§Û صدا جÙ
ع ØŽØ¯ÙØ¯"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ØšÛØµØ¯Ø§ کرد٠%s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ؚاصدا کرد٠%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Ø¯Ø±ØØ§Ù ٟخ؎ <xliff:g id="LABEL">%s</xliff:g> در"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"صدا ٟخ؎ Ù
ÛØŽÙد در"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ØªÙØžÛÙ
Ú©ÙÙØ¯Ù ÙØ§Ø³Ø· Ú©Ø§Ø±ØšØ±Û Ø³ÛØ³ØªÙ
"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÚØ±Ø®ØŽ ؚ٠جÙ٠در ØšØ±ÙØ§Ù
ÙÙØ§Û Ø§Ø®ÛØ±"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÚØ±Ø®ØŽ ØšÙ Ø¹ÙØš Ø¯Ø± ØšØ±ÙØ§Ù
ÙÙØ§Û Ø§Ø®ÛØ±"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ؚاز کرد٠ÙÙØ±Ø³Øª ØšØ±ÙØ§Ù
ÙÙØ§"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÙÙ
Ø§ÛØŽ ÙÙØ§Ø± ÙØžÛÙÙ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ؚاز Ú©Ø±Ø¯Ù ØªÙØžÛÙ
ات"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ؚاز کرد٠«Ø¯Ø³ØªÛار»"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÙÙÙ ØµÙØÙ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÙØ§Ø±Ø¯ ØŽØ¯Ù ØšÙ ØµÙØÙ٠دÙÙÛÙ
٠ؚا ØšØ±ÙØ§Ù
Ù ÙØ¹ÙÛ Ø¯Ø± سÙ
ت راست"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÙØ§Ø±Ø¯ ØŽØ¯Ù ØšÙ ØµÙØÙ٠دÙÙÛÙ
٠ؚا ØšØ±ÙØ§Ù
Ù ÙØ¹ÙÛ Ø¯Ø± سÙ
ت ÚÙŸ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Ø¬Ø§ØšÙØ¬Ø§ÛÛ Ø§Ø² ØµÙØÙ٠دÙÙÛÙ
٠ؚ٠تÙ
اÙ
ØµÙØÙ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"درØÛÙ ØµÙØÙ٠دÙÙÛÙ
Ù: ØšØ±ÙØ§Ù
ÙØ§Û را ؚا دÛÚ¯Ø±Û Ø¬Ø§ØšÙØ¬Ø§ Ù
ÛÚ©ÙØ¯"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÙØ±ÙدÛ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Ø±ÙØªÙ ؚ٠زؚا٠ؚعدÛ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ø¯ÙØ±ØšÛÙ Ù
Ø³Ø¯ÙØ¯ ؎د٠است"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ø¯ÙØ±ØšÛÙ Ù Ù
ÛکرÙÙÙÙ Ù
Ø³Ø¯ÙØ¯ ØŽØ¯ÙØ§Ùد"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Ù
ÛکرÙÙÙÙ Ù
Ø³Ø¯ÙØ¯ ؎د٠است"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ù
زاØÙ
ÙØŽÙÛØ¯"</string>
<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>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 26d7bcb..ee36315 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT-järjestelmänvalvoja on estänyt kuvakaappauksien ottamisen."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Muuta"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Muokkaa kuvakaappausta"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Jaa kuvakaappaus"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Kuvaa enemmän"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hylkää kuvakaappaus"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Vanhempasi ylläpitää tätä laitetta. Vanhempasi voi nähdä ja ylläpitää tietoja, esim. käyttämiäsi sovelluksia, sijaintiasi ja käyttöaikaasi."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent pitää lukitusta avattuna"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Varkaussuoja\nLaite lukittu, liian monta avausyritystä"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Laite lukittiin, liian monta todennusyritystä"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Laite lukittu\nTodennus epäonnistui"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ääniasetukset"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Tekstitä media automaatt."</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Äänetön"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Striimaa"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ei käytettävissä, soittoääni mykistetty"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ei saatavilla, koska Älä häiritse on päällä"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ei saatavilla, koska Älä häiritse on päällä"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Poista mykistys koskettamalla."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Äänenvoimakkuuden säädin: %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Puhelut ja ilmoitukset soivat (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Lisää tuloasetukset"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Äänenvoimakkuuden liukusäätimet laajennettu"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Äänenvoimakkuuden liukusäätimet tiivistetty"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mykistä: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"poista mykistys: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Toistetaan: <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audiota toistetaan laitteella"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Siirry eteenpäin viimeaikaisten sovellusten kautta"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Siirry takaisin viimeaikaisten sovellusten kautta"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Avaa sovelluslista"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Näytä tehtäväpalkki"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Avaa asetukset"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Avaa Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lukitusnäyttö"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Siirry jaettuun näyttöön (sovellus oikeanpuoleiseen näyttöön)"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Siirry jaettuun näyttöön (sovellus vasemmanpuoleiseen näyttöön)"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Vaihda jaetusta näytöstä koko näyttöön"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Jaetun näytön aikana: korvaa sovellus toisella"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Syöttötapa"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Vaihda seuraavaan kieleen"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera estetty"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni estetty"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Älä häiritse"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Käyttäjän läsnäolo havaittu"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
<string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d6aaf08..5c534cb 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"La prise de captures d\'écran est bloquée par votre administrateur informatique"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Partagez la capture d\'écran"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Autoriser n\'importe quel widget sur l\'écran de verrouillage?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"Ouvrir les paramètres"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"Réactiver les applis pros?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"Réactiver"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
@@ -540,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par ton parent. Ton parent peut voir et gérer de l\'information, comme les applications que tu utilises, ta position et ton temps d\'utilisation des écrans."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"RPV"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protection c. le vol\nAppareil verrouillé, trop de tentatives"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé, trop de tentatives d\'authentification"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Appareil verrouillé\nÉchec de l\'authentification"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Paramètres sonores"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sous-titrer automatiquement"</string>
@@ -585,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sonnerie désactivée"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Diffuser"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Inaccessible : sonnerie en sourdine"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Inaccessible parce que Ne pas déranger est activée"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Inaccessible parce que Ne pas déranger est activée"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Touchez pour réactiver le son."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
@@ -605,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Commandes de volume de %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Les appels et les notifications seront annoncés par une sonnerie (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Entrer les paramètres de sortie"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Curseurs de volume développés"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Curseurs de volume réduits"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"Désactivez le son de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"Réactivez le son de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Lecture de <xliff:g id="LABEL">%s</xliff:g> sur"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Lecture audio sur"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -761,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Parcourir les applications récentes"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Parcourir les applications récentes en sens inverse"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ouvrir la liste des applications"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Afficher la barre des tâches"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ouvrir les paramètres"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ouvrir l\'Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Écran de verrouillage"</string>
@@ -770,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Passer à l\'écran divisé avec l\'application actuelle à droite"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Passer à l\'écran divisé avec l\'application actuelle à gauche"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Passer de l\'écran divisé au plein écran"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une application par une autre"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrée"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passer à la langue suivante"</string>
@@ -1268,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Appareil photo bloqué"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne pas déranger"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string>
<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>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7f6bdda..35c8e7e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"La capture d\'écran est bloquée par votre administrateur informatique"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Partager la capture d\'écran"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par tes parents. Ils peuvent voir et gérer certaines informations, telles que les applications que tu utilises, ta position et ton temps d\'utilisation de l\'appareil."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protection contre le vol\nAppareil verrouillé, trop de tentatives de déverrouillage"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé, trop de tentatives d\'authentification"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Appareil verrouillé\nÉchec de l\'authentification"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Paramètres audio"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sous-titrer automatiquement"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Couper le son"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Caster"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponible, car la sonnerie est coupée"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponible car Ne pas déranger est activé"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponible car Ne pas déranger est activé"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Appuyez pour ne plus ignorer."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Commandes de volume %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Les appels et les notifications sonneront (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Accéder aux paramètres de sortie"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Curseurs de volume développés"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Curseurs de volume réduits"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"couper le son de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"réactiver le son de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Diffusion de <xliff:g id="LABEL">%s</xliff:g> sur"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"L\'audio se mettra en marche"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Avancer dans les applications récentes"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Revenir sur les applications récentes"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ouvrir la liste d\'applications"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Afficher la barre des tâches"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ouvrir les paramètres"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ouvrir l\'Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Verrouiller l\'écran"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Passer en écran partagé avec l\'appli actuelle affichée à droite"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Passer en écran partagé avec l\'appli actuelle affichée à gauche"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Passer de l\'écran partagé au plein écran"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"En mode écran partagé : Remplacer une appli par une autre"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Saisie"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passer à la langue suivante"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne pas déranger"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence de l\'utilisateur est détectée"</string>
<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>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 97980e5..c0694e6 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"O teu administrador de TI bloqueou a opción de facer capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar a captura de pantalla"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Compartir"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar máis"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar a captura de pantalla"</string>
@@ -538,7 +539,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"O teu pai ou nai xestiona este dispositivo e pode ver e xestionar información como as aplicacións que usas, a túa localización e o tempo diante da pantalla."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por un axente de confianza"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protección antirroubo\nDisp. bloq., demasiados intentos desb."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Bloqueouse o dispositivo por un exceso de intentos de autenticación"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Bloqueouse o dispositivo\nProduciuse un erro na autenticación"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Configuración do son"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Crear subtítulos automáticos"</string>
@@ -583,10 +585,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Emitir"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Non dispoñible (o son está silenciado)"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Non dispoñible porque está activado Non molestar"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Non dispoñible porque está activado Non molestar"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar o son."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
@@ -603,16 +603,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controis de volume de %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"As chamadas e as notificacións soarán (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introducir a configuración de saída"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controis desprazables de volume despregados"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controis desprazables de volume contraídos"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activar o son de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproducindo <xliff:g id="LABEL">%s</xliff:g> en"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio reproducido en"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Configurador da IU do sistema"</string>
@@ -759,7 +754,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Percorrer aplicacións recentes cara adiante"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Percorrer aplicacións recentes cara atrás"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de aplicacións"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar barra de tarefas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configuración"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Asistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string>
@@ -768,6 +762,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Activar pantalla dividida con esta aplicación no lado dereito"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Activar pantalla dividida con esta aplicación no lado esquerdo"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar á aplicación da dereita ou de abaixo coa pantalla dividida"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar á aplicación da esquerda ou de arriba coa pantalla dividida"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"En modo de pantalla dividida: Substituír unha aplicación por outra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar ao seguinte idioma"</string>
@@ -1266,8 +1262,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Modo Non molestar"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Detectouse a presenza de usuarios"</string>
<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>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e47b324..9913d04 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"઀મટરટ IT àªàª¡àª®àª¿àªš ઊà«àªµàªŸàª°àªŸ ઞà«àªà«àª°à«àªšàª¶à«àª લà«àªµàªŸàªšà« ઞà«àªµàª¿àª§àªŸ બà«àª²à«àª àªàª°àªµàªŸàª®àªŸàª àªàªµà« àªà«"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ફà«àª°àª«àªŸàª° àªàª°à«"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ઞà«àªà«àª°à«àªšàª¶à«àªàª®àªŸàª ફà«àª°àª«àªŸàª° àªàª°à«"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ઞà«àªà«àª°à«àªšàª¶à«àª શà«àª° àªàª°à«"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"વધૠàªà«
પà«àªàª° àªàª°à«"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ઞà«àªà«àª°à«àªšàª¶à«àª àªà«àª¡à« ઊà«"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"લà«àª ઞà«àªà«àª°à«àªš પર àªà«àªàªªàª£ વિàªà«àªàªšà« મàªàªà«àª°à« àªàªªà«àª?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"ઞà«àªàª¿àªàª àªà«àª²à«"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"àªàª«àª¿àªžàªšà« થà«àªàªŸàªµà«àª²à« àªàªª àªàªŸàª²à« àªàª°à«àª?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"ફરૠàªàªŸàª²à« àªàª°à«"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરટશàªàª°à«àª€àªŸ ઞà«àªµàª¿àª àªàª°à«"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ઠડિવટàªàªž ઀મટરટ મટ઀ટપિ઀ટ ઊà«àªµàªŸàª°àªŸ મà«àªšà«àª àªàª°àªµàªŸàª®àªŸàª àªàªµà« àªà«. ઀મૠàªà«àªšà« àªàªªàª¯à«àª àªàª°à« àªà« ઀ૠàªàªª, ઀મટરà«àª ઞà«àª¥àªŸàªš àª
ચૠ઀મટરટ ઞà«àªà«àª°à«àªš ઞમય àªà«àªµà« મટહિ઀à«àªšà« ઀મટરટ મટ઀ટપિ઀ટ àªà«àª àª
ચૠમà«àªšà«àª àªàª°à« શàªà« àªà«."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ઊà«àªµàªŸàª°àªŸ àª
ચલà«àª રટàªà«àª²à«àª"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àªà«àª°à«àª¥à« ઞà«àª°àªà«àª·àªŸ\nડિવટàªàªž àª
ચલà«àª àªàª°à«àª¯à«àª, àª
ચલà«àª àªàª°àªµàªŸàªšàªŸ àªàª£àªŸ પà«àª°àª¯àªŸàªžà«"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ઞટàªàªšà«àª¡ ઞà«àªàª¿àªàª"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"મà«àª¡àª¿àª¯àªŸàª®àªŸàª àªà«
પà«àª¶àªš àªàªà«àª®à«
àªàª¿àª રà«àª€à« àªàª®à«àª°à«"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"મà«àª¯à«àª àªàª°à«"</string>
<string name="media_device_cast" msgid="4786241789687569892">"àªàªŸàªžà«àª àªàª°à«"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"રિàªàª મà«àª¯à«àª àªàª°à« હà«àªµàªŸàªšàªŸ àªàªŸàª°àª£à« àª
ચà«àªªàª²àª¬à«àª§ àªà«"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"àªàªªàª²àª¬à«àª§ ચથà«, àªàªŸàª°àª£ àªà« àªàª²à«àª² પટડશૠચહà«àª મà«àª¡ àªàªŸàª²à« àªà«"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"àªàªªàª²àª¬à«àª§ ચથà«, àªàªŸàª°àª£ àªà« àªàª²à«àª² પટડશૠચહà«àª મà«àª¡ àªàªŸàª²à« àªà«"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. àª
ચમà«àª¯à«àª àªàª°àªµàªŸ મટàªà« àªà«
પ àªàª°à«."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. વટàªàª¬à«àª°à«àª પર ઞà«àª àªàª°àªµàªŸ મટàªà« àªà«
પ àªàª°à«. àªàªà«àªžà«àªžàª¿àª¬àª¿àª²àª¿àªà« ઞà«àªµàªŸàª મà«àª¯à«àª àªàª°àªµàªŸàª®àªŸàª àªàªµà« શàªà« àªà«."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મà«àª¯à«àª àªàª°àªµàªŸ મટàªà« àªà«
પ àªàª°à«. àªàªà«àªžà«àªžàª¿àª¬àª¿àª²àª¿àªà« ઞà«àªµàªŸàª મà«àª¯à«àª àªàª°àªµàªŸàª®àªŸàª àªàªµà« શàªà« àªà«."</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વટàªàª¬à«àª°à«àª"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s વà«àª²à«àª¯à«àª® ચિયàªàª€à«àª°àª£à«"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àªà«àª² àª
ચૠચà«àªàª¿àª«àª¿àªà«àª¶àªšàªšà« રિàªàª (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>) પર વટàªàª¶à«"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"àªàªàªàªªà«àªàªšàªŸ ઞà«àªàª¿àªàª ઊટàªàª² àªàª°à«"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"વà«àª²à«àª¯à«àª®àªšàªŸ ઞà«àª²àªŸàªàª¡àª° મà«àªàªŸ àªàª°àªµàªŸàª®àªŸàª àªàªµà«àª¯àªŸ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"વà«àª²à«àª¯à«àª®àªšàªŸ ઞà«àª²àªŸàªàª¡àª° ચટચટ àªàª°àªµàªŸàª®àªŸàª àªàªµà«àª¯àªŸ"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sચૠમà«àª¯à«àª àªàª°à«"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sચૠàª
ચમà«àª¯à«àª àªàª°à«"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> વàªàªŸàª¡à« રહà«àª¯àªŸàª àªà«àª"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"àªàª¡àª¿àª¯à« àªàªšà« પર વટàªàª¶à«"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ઞિઞà«àªàª® UI àªà«àª¯à«àªšàª°"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"઀ટàªà«àª€àª°àªšà« àªàªª પર àªàªàª³ àªàªŸàª"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"઀ટàªà«àª€àª°àªšà« àªàªª પર પટàªàª³ àªàªŸàª"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"àªàªªàªšà« ઞà«àªàª¿ àªà«àª²à«"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"àªàªŸàªžà«àªàª¬àªŸàª° બ઀ટવà«"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ઞà«àªàª¿àªàª àªà«àª²à«"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant àªà«àª²à«"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"લà«àª ઞà«àªà«àª°à«àªš"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"àªàª®àª£à« બટàªà« પર હટલચૠàªàªª ઞટથૠવિàªàªŸàªàª¿àª€ ઞà«àªà«àª°à«àªšàª®àªŸàª ઊટàªàª² થટàª"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ડટબૠબટàªà« પર હટલચૠàªàªª ઞટથૠવિàªàªŸàªàª¿àª€ ઞà«àªà«àª°à«àªšàª®àªŸàª ઊટàªàª² થટàª"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"વિàªàªŸàªàª¿àª€ ઞà«àªà«àª°à«àªšàª¥à« પà«àª°à«àª£ ઞà«àªà«àª°à«àªš પર ઞà«àªµàª¿àª àªàª°à«"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"વિàªàªŸàªàª¿àª€ ઞà«àªà«àª°à«àªš ઊરમિયટચ: àªàª àªàªªàªšà« બà«àªà« àªàªªàª®àªŸàª બઊલà«"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àªàªšàªªà«àª"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"àªàªàª²à« àªàªŸàª·àªŸ પર ઞà«àªµàª¿àª àªàª°à«"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àªà«
મà«àª°àªŸ બà«àª²à«àª àªàª°à«àª²à« àªà«"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àªà«
મà«àª°àªŸ àª
ચૠમટàªàªà«àª°à«àª«à«àªš બà«àª²à«àª àªàª°à«àª²àªŸ àªà«"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"મટàªàªà«àª°à«àª«à«àªš બà«àª²à«àª àªàª°à«àª²à« àªà«"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àªàª²à«àª² પટડશૠચહà«àª"</string>
<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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index c36b6f9..03018c0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"à€à€à€à¥ à€à€¡à€®à€¿à€š à€šà¥ à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€²à¥à€šà¥ à€ªà€° à€°à¥à€ à€²à€à€Ÿà€ à€¹à¥"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à€¬à€Šà€²à€Ÿà€µ à€à€°à¥à€"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€®à¥à€ à€¬à€Šà€²à€Ÿà€µ à€à€°à¥à€"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€¶à¥à€¯à€° à€à€°à¥à€"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€à¥à€šà¥à€à¥à€à€ à€à¥à€ªà¥à€à€° à€à€°à¥à€"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€à¥ à€à€Ÿà€°à€¿à€ à€à€°à¥à€"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à€à€ž à€¡à€¿à€µà€Ÿà€à€ž à€à€Ÿ à€ªà¥à€°à€¬à€à€§à€š à€à€ªà€à¥ à€
à€à€¿à€à€Ÿà€µà€ à€à€°à€€à¥ à€¹à¥à€. à€
à€à€¿à€à€Ÿà€µà€ à€à€ªà€à¥ à€¡à€¿à€µà€Ÿà€à€ž à€žà¥ à€à¥à€¡à€Œà¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€Šà¥à€ à€žà€à€€à¥ à€¹à¥à€. à€žà€Ÿà€¥ à€¹à¥, à€à€žà¥ à€ªà¥à€°à€¬à€à€§à€¿à€€ à€à€° à€žà€à€€à¥ à€¹à¥à€. à€à€šà€®à¥à€ à€à€ªà€à¥ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€¿à€ à€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š, à€à€à€¹ à€à¥ à€à€Ÿà€šà€à€Ÿà€°à¥, à€à€° à€¡à€¿à€µà€Ÿà€à€ž à€à¥ à€à€žà¥à€€à¥à€®à€Ÿà€² à€®à¥à€ à€¬à€¿à€€à€Ÿà€ à€à€ à€žà€®à€¯ à€à¥à€žà¥ à€à€Ÿà€šà€à€Ÿà€°à¥ à€¶à€Ÿà€®à€¿à€² à€¹à¥."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"à€µà¥à€ªà¥à€à€š"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à€à¥ à€µà€à€¹ à€žà¥ à€
à€šà€²à¥à€ à€°à€à€Ÿ à€à€¯à€Ÿ à€¹à¥"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à€à¥à€°à¥ à€žà¥ à€žà¥à€°à€à¥à€·à€Ÿ\nà€¡à€¿à€µà€Ÿà€à€ž à€²à¥à€ à€¹à¥ à€à€¯à€Ÿ, à€
à€šà€²à¥à€ à€à¥ à€à€ à€à¥à€¶à€¿à€¶à¥à€ à€à¥ à€à€à€"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"à€à€ à€¬à€Ÿà€° à€ªà¥à€·à¥à€à€¿ à€à€°à€šà¥ à€à¥ à€à¥à€¶à€¿à€¶ à€à¥ à€µà€à€¹ à€žà¥, à€¡à€¿à€µà€Ÿà€à€ž à€²à¥à€ à€¹à¥"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"à€¡à€¿à€µà€Ÿà€à€ž à€²à¥à€ à€¹à¥\nà€ªà¥à€·à¥à€à€¿ à€šà€¹à¥à€ à€à¥ à€à€Ÿ à€žà€à¥."</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à€žà€Ÿà€à€à€¡ à€žà¥à€à€¿à€à€"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à€à€¡à€¿à€¯à¥-à€µà¥à€¡à€¿à€¯à¥ à€žà¥ à€
à€ªà€šà¥-à€à€ª à€à¥à€ªà¥à€¶à€š à€¬à€šà€šà€Ÿ"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à€à€µà€Ÿà€à€Œ à€¬à€à€Š à€¹à¥"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à€à€Ÿà€žà¥à€ à€à€°à¥à€"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à€°à€¿à€à€ à€®à¥à€¯à¥à€ à€¹à¥à€šà¥ à€žà¥ à€à€µà€Ÿà€à€Œ à€šà€¹à¥à€ à€žà¥à€šà€Ÿà€ à€Šà¥"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à€žà¥à€µà€¿à€§à€Ÿ à€¬à€à€Š à€¹à¥, à€à¥à€¯à¥à€à€à€¿ \'à€ªà€°à¥à€¶à€Ÿà€š à€š à€à€°à¥à€\' à€®à¥à€¡ à€à€Ÿà€²à¥ à€¹à¥"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à€žà¥à€µà€¿à€§à€Ÿ à€¬à€à€Š à€¹à¥, à€à¥à€¯à¥à€à€à€¿ \'à€ªà€°à¥à€¶à€Ÿà€š à€š à€à€°à¥à€\' à€®à¥à€¡ à€à€Ÿà€²à¥ à€¹à¥"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à€
à€šà€®à¥à€¯à¥à€ à€à€°à€šà¥ à€à¥ à€²à€¿à€ à€à¥à€ª à€à€°à¥à€."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à€à€à€ªà€š à€ªà€° à€žà¥à€ à€à€°à€šà¥ à€à¥ à€²à€¿à€ à€à¥à€ª à€à€°à¥à€. à€žà¥à€²à€à€€à€Ÿ à€žà¥à€µà€Ÿà€à€ à€®à¥à€¯à¥à€ à€¹à¥ à€žà€à€€à¥ à€¹à¥à€."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à€®à¥à€¯à¥à€ à€à€°à€šà¥ à€à¥ à€²à€¿à€ à€à¥à€ª à€à€°à¥à€. à€žà¥à€²à€à€€à€Ÿ à€žà¥à€µà€Ÿà€à€ à€®à¥à€¯à¥à€ à€¹à¥ à€žà€à€€à¥ à€¹à¥à€."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à€µà€Ÿà€à€¬à¥à€°à¥à€¶à€š à€à¥ à€žà¥à€µà€¿à€§à€Ÿ à€à€Ÿà€²à¥ à€à€°à¥à€"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s à€à¥ à€à€µà€Ÿà€à€Œ à€à€® à€¯à€Ÿ à€à€Œà¥à€¯à€Ÿà€Šà€Ÿ à€à€°à€šà¥ à€à¥ à€žà¥à€µà€¿à€§à€Ÿ"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à€à¥à€² à€à€° à€žà¥à€à€šà€Ÿà€à€ à€à€šà¥ à€ªà€° à€à€à€à¥ à€¬à€à¥à€à¥ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à€à€à€à€ªà¥à€ à€à¥ à€žà¥à€à€¿à€à€ à€¡à€Ÿà€²à¥à€"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à€à€µà€Ÿà€à€Œ à€à¥ à€žà¥à€²à€Ÿà€à€¡à€° à€à¥ à€¬à€¡à€Œà€Ÿ à€à€¿à€¯à€Ÿ à€à€¯à€Ÿ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à€à€µà€Ÿà€à€Œ à€à¥ à€žà¥à€²à€Ÿà€à€¡à€° à€à¥ à€à¥à€à€Ÿ à€à€¿à€¯à€Ÿ à€à€¯à€Ÿ"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s à€à¥ à€®à¥à€¯à¥à€ à€à€°à¥à€"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à€à¥ à€
à€šà€®à¥à€¯à¥à€ à€à€°à¥à€"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> à€à¥ à€à€²à€Ÿà€¯à€Ÿ à€à€Ÿ à€°à€¹à€Ÿ à€¹à¥"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à€à€¡à€¿à€¯à¥ à€à€žà€®à¥à€ à€à€²à¥à€à€Ÿ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"à€žà€¿à€žà¥à€à€® à€¯à¥à€à€Œà€° à€à€à€à€°à€«à€Œà¥à€ž (à€¯à¥à€à€) à€à¥à€¯à¥à€šà€°"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à€¹à€Ÿà€² à€¹à¥ à€®à¥à€ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€¿à€ à€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€
à€à€²à¥ à€ªà¥à€ à€ªà€° à€à€Ÿà€šà¥ à€à¥ à€²à€¿à€"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à€¹à€Ÿà€² à€¹à¥ à€®à¥à€ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€¿à€ à€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€ªà€¿à€à€²à¥ à€ªà¥à€ à€ªà€° à€à€Ÿà€šà¥ à€à¥ à€²à€¿à€"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€žà¥à€à¥ à€à¥à€²à€šà¥ à€à¥ à€²à€¿à€"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à€à€Ÿà€žà¥à€à€¬à€Ÿà€° à€Šà€¿à€à€Ÿà€šà¥ à€à¥ à€²à€¿à€"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à€žà¥à€à€¿à€à€ à€à¥à€²à€šà¥ à€à¥ à€²à€¿à€"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Google Assistant à€à¥à€²à€šà¥ à€à¥ à€²à€¿à€"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"à€²à¥à€ à€žà¥à€à¥à€°à¥à€š"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€š à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€à¥, à€®à¥à€à¥à€Šà€Ÿ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€Šà€Ÿà€à€ à€à€° à€²à¥ à€à€Ÿà€à€"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€š à€à€Ÿ à€à€žà¥à€€à¥à€®à€Ÿà€² à€à€°à€à¥, à€®à¥à€à¥à€Šà€Ÿ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€¬à€Ÿà€à€ à€à€° à€²à¥ à€à€Ÿà€à€"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€š à€žà¥ à€«à€Œà¥à€² à€žà¥à€à¥à€°à¥à€š à€®à¥à€¡ à€ªà€° à€žà¥à€µà€¿à€ à€à€°à€šà¥ à€à¥ à€²à€¿à€"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€š à€à¥ à€Šà¥à€°à€Ÿà€š: à€à€ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€à¥ à€Šà¥à€žà€°à¥ à€à€ªà¥à€²à€¿à€à¥à€¶à€š à€žà¥ à€¬à€Šà€²à¥à€"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à€à€šà€ªà¥à€"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à€
à€à€²à¥ à€à€Ÿà€·à€Ÿ à€ªà€° à€žà¥à€µà€¿à€ à€à€°à€šà¥ à€à¥ à€²à€¿à€"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à€à¥à€®à€°à¥ à€à€Ÿ à€à€à¥à€žà¥à€ž à€šà€¹à¥à€ à€¹à¥"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à€à¥à€®à€°à¥ à€à€° à€®à€Ÿà€à€à¥à€°à¥à€«à€Œà¥à€š à€à€Ÿ à€à€à¥à€žà¥à€ž à€šà€¹à¥à€ à€¹à¥"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à€®à€Ÿà€à€à¥à€°à¥à€«à€Œà¥à€š à€à€Ÿ à€à€à¥à€žà¥à€ž à€šà€¹à¥à€ à€¹à¥"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"\'à€ªà€°à¥à€¶à€Ÿà€š à€š à€à€°à¥à€\' à€®à¥à€¡"</string>
<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>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2d44e1c..dde688c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Izradu snimki zaslona blokirao je IT administrator"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"UreÄivanje snimke zaslona"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Podijeli snimku zaslona"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimi više"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacivanje snimke zaslona"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim ureÄajem upravlja tvoj roditelj. Tvoj roditelj moÅŸe vidjeti podatke kao što su aplikacije kojima se koristiš, lokaciju i vrijeme upotrebe te upravljati njima."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"OtkljuÄano odrÅŸava TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Zaštita od kraÄe\nUreÄaj zakljuÄan, previše pokušaja otkljuÄavanja"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"UreÄaj je bio zakljuÄan zbog previše pokušaja autentifikacije"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"UreÄaj je zakljuÄan\nAutentifikacija nije uspjela"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Postavke zvuka"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatski titlovi za medije"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Zvuk je iskljuÄen"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Emitiraj"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvono utišano"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupno jer je ukljuÄen naÄin Ne uznemiravaj"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupno jer je ukljuÄen naÄin Ne uznemiravaj"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste ukljuÄili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupaÄnosti moÅŸda neÄe imati zvuk."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste iskljuÄili zvuk. Usluge pristupaÄnosti moÅŸda neÄe imati zvuk."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Kontrole glasnoÄe – %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Telefon Äe zvoniti za pozive i obavijesti (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unesite postavke izlaza"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Proširivanje klizaÄa za glasnoÄu"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"SaÅŸimanje klizaÄa za glasnoÄu"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"iskljuÄili zvuk za sljedeÄe: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ukljuÄili zvuk za sljedeÄe: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproducira se – <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk Äe se reproducirati"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"UgaÄanje korisniÄkog suÄelja sustava"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"KruÅŸi unaprijed kroz nedavne aplikacije"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"KruÅŸi unatrag kroz nedavne aplikacije"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvori popis aplikacija"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"PokaÅŸi traku sa zadacima"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvori postavke"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvori Asistenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ZakljuÄavanje zaslona"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Otvori podijeljeni zaslon s trenutaÄnom aplikacijom s desne strane"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Otvori podijeljeni zaslon s trenutaÄnom aplikacijom s lijeve strane"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"PrijeÄi s podijeljenog zaslona na cijeli zaslon"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tijekom podijeljenog zaslona: zamijeni aplikaciju drugom"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"PrijeÄi na sljedeÄi jezik"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Blokirani su kamera i mikrofon"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne uznemiravaj"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkrivena je prisutnost korisnika"</string>
<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>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 98565c0..8b32095 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"A képernyÅkép készítésének lehetÅségét a rendszergazda letiltotta"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Szerkesztés"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"KépernyÅkép szerkesztése"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"KépernyÅkép megosztása"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Több rögzítése"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"KépernyÅkép elvetése"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Az eszközt a szülÅd felügyeli. A szülÅd megtekintheti és kezelheti például a használt alkalmazásokra, a tartózkodási helyre és a képernyÅidÅre vonatkozó adatokat."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Feloldva tartva TrustAgent által"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Lopásgátlás\nTúl sok feloldási kísérlet, eszköz zárolva"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Hangbeállítások"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatikus feliratozás"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Néma"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Átküldés"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nem lehetséges, a csörgés le van némítva"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nem működik, mert be van kapcsolva a Ne zavarjanak"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nem működik, mert be van kapcsolva a Ne zavarjanak"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Koppintson a rezgés beállításához. ElÅfordulhat, hogy a kisegítÅ lehetÅségek szolgáltatásai le vannak némítva."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. ElÅfordulhat, hogy a kisegítÅ lehetÅségek szolgáltatásai le vannak némítva."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s hangerÅszabályzók"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"A hívásoknál és értesítéseknél csörög a telefon (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Kimenet beállításainak megadása"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"HangerÅ-szabályozók kibontva"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"HangerÅ-szabályozók összecsukva"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s némítása"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s némításának feloldása"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> lejátszása itt:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Hang lejátszása itt:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"KezelÅfelület-hangoló"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Lépegetés elÅrefelé a legutóbbi alkalmazások között"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Lépegetés visszafelé a legutóbbi alkalmazások között"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Alkalmazáslista megnyitása"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Feladatsáv megjelenítése"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Beállítások megnyitása"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"A Segéd megnyitása"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lezárási képernyÅ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Osztott képernyÅ aktiválása; az aktuális alkalmazás kerüljön jobbra"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Osztott képernyÅ aktiválása; az aktuális alkalmazás kerüljön balra"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Váltás osztott képernyÅrÅl teljes képernyÅre"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Osztott képernyÅn: az egyik alkalmazás lecserélése egy másikra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Bevitel"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Váltás a következÅ nyelvre"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne zavarjanak"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Felhasználói jelenlét észlelve"</string>
<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>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 5d88e0d..8151686 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ÕÕ¥Ö ÕÕ Õ¡Õ€ÕŽÕ«Õ¶Õ«ÕœÕ¿ÖÕ¡Õ¿ÕžÖÕ¶ Õ¡ÖÕ£Õ¥Õ¬Õ¡ÖÕ¡Õ¯Õ¥Õ¬ Õ§ ÕœÖÖÕ«Õ¶Õ·ÕžÕ©Õ¶Õ¥Ö Õ¡Õ¶Õ¥Õ¬ÕžÖ Õ°Õ¶Õ¡ÖÕ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õš"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÕÕžÖÕžÕÕ¥Õ¬"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÕÕžÖÕžÕÕ¥Õ¬ ÕœÖÖÕ«Õ¶Õ·ÕžÕ©Õš"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÕÖÕ²Õ¡ÖÕ¯Õ¥Õ¬ ÕœÖÖÕ«Õ¶Õ·ÕžÕ©"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÕÕ¥Õ®Õ¡ÖÕ¶Õ¥Õ¬ ÕœÖÖÕ«Õ¶Õ·ÕžÕ©Õ« Õ¿Õ¡ÖÕ¡Õ®ÖÕš"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÕÕ¡Õ¯Õ¥Õ¬ ÕœÖÖÕ«Õ¶Õ·ÕžÕ©Õš"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ô±ÕµÕœ ՜աÖÖÕš կաՌա՟աÖÕžÖÕŽ Õ§ Õ±Õ¥Ö Õ®Õ¶ÕžÕ²ÕšÖ ÕÕ¡ Õ¯Õ¡ÖÕžÕ² Õ§ Õ€Õ«Õ¿Õ¥Õ¬ Ö ÖÕžÖÕžÕÕ¥Õ¬ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¿Õ¥Õ²Õ¥Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö, Ö
ÖÕ«Õ¶Õ¡Õ¯Õ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕš, ÕžÖÕžÕ¶Ö Õ€ÕžÖÖ Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕžÖÕŽ Õ¥Ö, Õ±Õ¥Ö Õ¿Õ¥Õ²Õ¡Õ€ÖÕžÖÕ©ÕµÕžÖÕ¶Õš Ö ÕœÕ¡ÖÖÕ« Ö
Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕŽÕ¡Õ¶ ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯ÕšÖ"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ô±ÕºÕ¡Õ¯ÕžÕ²ÕºÕŸÕžÖÕŽ Õ§ TrustAgent-Õ« ÕŽÕ«Õ»ÕžÖÕžÕŸ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ô³ÕžÕ²ÕžÖÕ©ÕµÕžÖÕ¶Õ«Ö ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶ÕžÖÕ©ÕµÕžÖÕ¶\nÕÕ¡ÖÖÕš Õ¯ÕžÕ²ÕºÕŸÕ¥Õ¬ Õ§, Õ¡ÕºÕ¡Õ¯ÕžÕ²ÕºÕŽÕ¡Õ¶ Õ·Õ¡Õ¿ ÖÕžÖÕ±Õ¥Ö"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ÕÕ¡ÖÖÕš Õ¯ÕžÕ²ÕºÕŸÕ¥Õ¬ է†ի՜կ՞ÖÕžÕ·ÕŽÕ¡Õ¶ Õ¹Õ¡ÖÕ¡ÕŠÕ¡Õ¶Ö Õ·Õ¡Õ¿ ÖÕžÖÕ±Õ¥Ö Õ¥Õ¶ Õ¡ÖÕŸÕ¥Õ¬"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ÕÕ¡ÖÖÕš Õ¯ÕžÕ²ÕºÕŸÕ¥Õ¬ Õ§\nÕÕ°Õ¡Õ»ÕžÕ²ÕŸÕ¥Ö Õ«ÕœÕ¯ÕžÖÕžÕ·Õ¥Õ¬"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÕÕ¡ÕµÕ¶Õ« Õ¯Õ¡ÖÕ£Õ¡ÕŸÕžÖÕžÖÕŽÕ¶Õ¥Ö"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Ô±ÕŸÕ¿ÕžÕŽÕ¡Õ¿ Õ¡ÕŸÕ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ¥Õ¶Õ©Õ¡Õ£ÖÕ¥Ö"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ô±Õ¶Õ±Õ¡ÕµÕ¶"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ÕեՌաÖÕ±Õ¡Õ¯ÕžÖÕŽ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Õա՜անելի Õ¹Õ§, Õ¥ÖÕ¢ ÕŠÕ¡Õ¶Õ£Õ« Õ±Õ¡ÕµÕ¶Õ¶ Õ¡Õ¶Õ»Õ¡Õ¿ÕŸÕ¡Õ® Õ§"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Õա՜անելի չէ†«Õանհանգ՜տաÖÕ¶Õ¥Õ¬» ՌեժիՎ՚ ÕŽÕ«Õ¡ÖÕŸÕ¡Õ® Õ§"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Õա՜անելի չէ†«Õանհանգ՜տաÖÕ¶Õ¥Õ¬» ՌեժիՎ՚ ÕŽÕ«Õ¡ÖÕŸÕ¡Õ® Õ§"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s: ÕÕºÕ¥ÖÕ Õ±Õ¡ÕµÕ¶Õš ÕŽÕ«Õ¡ÖÕ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s: ÕÕºÕ¥ÖÕ Õ©ÖթՌ՞ÖÕŽÕš ÕŽÕ«Õ¡ÖÕ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö: ÕÕ¡Õ¿Õ¹Õ¥Õ¬Õ«ÕžÖÕ©ÕµÕ¡Õ¶ ծաՌայ՞ÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« Õ±Õ¡ÕµÕ¶Õš Õ¯Õ¡ÖÕžÕ² Õ§ Õ¡Õ¶Õ»Õ¡Õ¿ÕŸÕ¥Õ¬:"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: ÕÕºÕ¥ÖÕ Õ±Õ¡ÕµÕ¶Õ¶ Õ¡Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö: ÕÕ¡Õ¿Õ¹Õ¥Õ¬Õ«ÕžÖÕ©ÕµÕ¡Õ¶ ծաՌայ՞ÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« Õ±Õ¡ÕµÕ¶Õš Õ¯Õ¡ÖÕžÕ² Õ§ Õ¡Õ¶Õ»Õ¡Õ¿ÕŸÕ¥Õ¬:"</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÕŽÕ«Õ¡ÖÕ¶Õ¥Õ¬ Õ©ÖթՌ՞ÖÕš"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"ÕÕ¡ÕµÕ¶Õ« ÕžÖÕªÕ£Õ¶ÕžÖÕ©ÕµÕ¡Õ¶ կաՌա՟աÖÕ¶Õ¥Ö` %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Ô¶Õ¡Õ¶Õ£Õ¥ÖÕ« Ö Õ®Õ¡Õ¶ÕžÖÖÕžÖÕŽÕ¶Õ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö Õ°Õ¥ÕŒÕ¡Õ՞՜ի Õ±Õ¡ÕµÕ¶Õš ÕŽÕ«Õ¡ÖÕŸÕ¡Õ® Õ§ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ô²Õ¡ÖÕ¥Õ¬ Õ¶ÕŸÕ¡Õ£Õ¡ÖÕ¯ÕŽÕ¡Õ¶ Õ¯Õ¡ÖÕ£Õ¡ÕŸÕžÖÕžÖÕŽÕ¶Õ¥ÖÕš"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÕÕ¡ÕµÕ¶Õ« ÕžÖÕªÕ£Õ¶ÕžÖÕ©ÕµÕ¡Õ¶ ՜ահիչնեÖÕš Õ®Õ¡ÕŸÕ¡Õ¬ÕŸÕ¡Õ® Õ¥Õ¶"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÕÕ¡ÕµÕ¶Õ« ÕžÖÕªÕ£Õ¶ÕžÖÕ©ÕµÕ¡Õ¶ ՜ահիչնեÖÕš Õ®Õ¡Õ¬ÕŸÕ¡Õ® Õ¥Õ¶"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"Õ¡Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ Õ±Õ¡ÕµÕ¶Õš (%s)"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ÕŽÕ«Õ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¡ÕµÕ¶Õš (%s)"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>. Õ¶ÕŸÕ¡Õ£Õ¡ÖÕ¯ÕŸÕžÖÕŽ Õ§"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ô±ÕžÖÕ€Õ«ÕžÕ¶ Õ¯Õ¶ÕŸÕ¡Õ£Õ¡ÖÕ¯ÕŸÕ«"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ÕÕ¡ÕŽÕ¡Õ¯Õ¡ÖÕ£Õ« ÕÕ-Õ« Õ¯Õ¡ÖÕ£Õ¡ÕŸÕžÖÕ«Õ¹"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ԱՌաջ Õ¡Õ¶ÖÕ¶Õ¥Õ¬ ÕŸÕ¥ÖÕ»Õ«Õ¶ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕ« ÕŽÕ«Õ»ÕžÕŸ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÕÕ¥Õ¿ Õ¡Õ¶ÖÕ¶Õ¥Õ¬ ÕŸÕ¥ÖÕ»Õ«Õ¶ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕ« ÕŽÕ«Õ»ÕžÕŸ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ô²Õ¡ÖÕ¥Õ¬ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕ« ÖÕ¡Õ¶Õ¯Õš"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÕÕžÖÖÕ¡Õ€ÖÕ¥Õ¬ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶Õ¥ÖÕ« ÕŸÕ¡Õ°Õ¡Õ¶Õ¡Õ¯Õš"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ô²Õ¡ÖÕ¥Õ¬ Õ¯Õ¡ÖÕ£Õ¡ÕŸÕžÖÕžÖÕŽÕ¶Õ¥ÖÕš"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ô²Õ¡ÖÕ¥Õ¬ ÕÕ£Õ¶Õ¡Õ¯Õ¡Õ¶Õš"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ô¿ÕžÕ²ÕºÕ§Õ¯ÖÕ¡Õ¶"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÕÕ«Õ¡ÖÕ¶Õ¥Õ¬ Õ§Õ¯ÖÕ¡Õ¶Õ« Õ¿ÖÕžÕ°ÕžÖÕŽÕšÕ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õ¶ Õ¡Õ» Õ¯ÕžÕ²ÕŽÕžÖÕŽ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÕÕ«Õ¡ÖÕ¶Õ¥Õ¬ Õ§Õ¯ÖÕ¡Õ¶Õ« Õ¿ÖÕžÕ°ÕžÖÕŽÕšÕ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš Õ±Õ¡Õ Õ¯ÕžÕ²ÕŽÕžÖÕŽ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÕÖÕžÕ°ÕŸÕ¡Õ® Õ§Õ¯ÖÕ¡Õ¶Õ«Ö Õ¡Õ¶ÖÕ¶Õ¥Õ¬ Õ¬Õ«Õ¡Õ§Õ¯ÖÕ¡Õ¶ ՌեժիՎ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÕÖÕžÕ°ÕŸÕ¡Õ® Õ§Õ¯ÖÕ¡Õ¶Õ« ՌեժիՎ՞ÖÕŽ ÕŽÕ¥Õ¯ Õ°Õ¡ÕŸÕ¥Õ¬ÕŸÕ¡Õ®Õš ÖÕžÕÕ¡ÖÕ«Õ¶Õ¥Õ¬ ÕŽÕµÕžÖ՜՞՟"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÕÕ¥ÖÕ¡Õ®ÕžÖÕŽ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ°Õ¡Õ»ÕžÖÕ€ Õ¬Õ¥ÕŠÕŸÕ«Õ¶"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Õե՜աÕÖÕ«Õ¯Õ¶ Õ¡ÖÕ£Õ¥Õ¬Õ¡ÖÕ¡Õ¯ÕŸÕ¡Õ® Õ§"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Õե՜աÕÖÕ«Õ¯Õ¶ ÕžÖ Õ՞՜աÖÕžÕ²Õš Õ¡ÖÕ£Õ¥Õ¬Õ¡ÖÕ¡Õ¯ÕŸÕ¡Õ® Õ¥Õ¶"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Ԝ՞՜աÖÕžÕ²Õ¶ Õ¡ÖÕ£Õ¥Õ¬Õ¡ÖÕ¡Õ¯ÕŸÕ¡Õ® Õ§"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Õանհանգ՜տաÖÕ¶Õ¥Õ¬"</string>
<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>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5c3eb53..565eaff 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Mengambil screenshot diblokir oleh admin IT Anda"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Mengedit screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Bagikan screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Ambil screenshot lagi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Menutup screenshot"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Perangkat ini dikelola oleh orang tuamu. Orang tuamu bisa melihat dan mengelola berbagai informasi, seperti aplikasi yang kamu gunakan, lokasimu, dan lama pemakaian perangkat."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Tetap terbuka kuncinya oleh TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Perlindungan pencurian\nPerangkat dikunci, terlalu banyak upaya pembukaan kunci"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Setelan suara"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Otomatis beri teks di media"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Nonaktifkan"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmisi"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia karena volume dering dibisukan"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Tidak tersedia karena fitur Jangan Ganggu aktif"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Tidak tersedia karena fitur Jangan Ganggu aktif"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketuk untuk menyuarakan."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s kontrol volume"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Panggilan telepon dan notifikasi akan berdering (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Masukkan setelan perangkat output"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Penggeser volume diluaskan"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Penggeser volume diciutkan"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"membisukan %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"membunyikan %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Memutar <xliff:g id="LABEL">%s</xliff:g> di"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio akan diputar di"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Penyetel Antarmuka Pengguna Sistem"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Menavigasi maju pada aplikasi terbaru"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Menavigasi mundur pada aplikasi terbaru"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Buka daftar aplikasi"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Tampilkan taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Buka setelan"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buka Asisten"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci layar"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Masuk ke layar terpisah dengan aplikasi saat ini ke RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Masuk ke layar terpisah dengan aplikasi saat ini ke LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Beralih dari layar terpisah ke layar penuh"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Dalam layar terpisah: ganti salah satu aplikasi dengan yang lain"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Beralih ke bahasa berikutnya"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Jangan ganggu"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna terdeteksi"</string>
<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>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index ea0726b..149ba55 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Kerfisstjórinn lokaði á skjámyndatöku"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Breyta"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Breyta skjámynd"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Deila skjámynd"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mynda meira"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Loka skjámynd"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Foreldri þitt stjórnar þessu tæki. Foreldri þitt getur séð og stjórnað upplýsingum eins og forritunum sem þú notar, staðsetningu þinni og skjátímanum."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Haldið opnu af TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Þjófavörn\nTækinu var læst vegna of margra tilrauna til að taka það úr lás"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Tæki var læst, of margar auðkenningartilraunir"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Tæki læst\nAuðkenning mistókst"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Hljóðstillingar"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sjálfvirkir skjátextar"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Hljóð af"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Senda út"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ekki í boði þar sem hringing er þögguð"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ekki í boði vegna þess að kveikt er á „Ónáðið ekki“"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ekki í boði vegna þess að kveikt er á „Ónáðið ekki“"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ýttu til að hætta að þagga."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s stýringar á hljóstyrk"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Símhringingar og tilkynningar heyrast (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Færa inn stillingar úttaks"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Stækkaðir hljóðstyrkssleðar"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Minnkaðir hljóðstyrkssleðar"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"þagga %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"kveikja á hljóði %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Í spilun í <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Hljóð heldur áfram að spilast"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Fínstillingar kerfisviðmóts"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Fletta áfram í gegnum nýleg forrit"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Fletta aftur á bak í gegnum nýleg forrit"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Opna forritalista"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Sýna forritastiku"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Opna stillingar"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Opna Hjálpara"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lásskjár"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Opna skjáskiptingu hægra megin með núverandi forriti"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Opna skjáskiptingu vinstra megin með núverandi forriti"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Skipta úr skjáskiptingu yfir á allan skjáinn"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Í skjáskiptingu: Skipta forriti út fyrir annað forrit"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Innsláttur"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Skipta yfir í næsta tungumál"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ónáðið ekki"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Viðvera notanda greindist"</string>
<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>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index b2eb5f9..f701787 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"L\'acquisizione di screenshot è stata bloccata dall\'amministratore IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifica"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifica screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Condividi screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Acquisisci di più"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora screenshot"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Questo dispositivo è gestito da uno dei tuoi genitori, il quale può visualizzare e gestire informazioni come le app che usi, la tua posizione e il tuo tempo di utilizzo."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Sbloccato da TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protezione da furti\nDisp. bloccato, troppi tentat. di sblocco"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Impostazioni audio"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sottotitoli automatici"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenzia"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Trasmissione"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Non disponibile con l\'audio disattivato"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Non disponibile: modalità Non disturbare attiva"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Non disponibile: modalità Non disturbare attiva"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tocca per riattivare l\'audio."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controlli del volume %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"La suoneria sarà attiva per chiamate e notifiche (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserisci impostazioni di uscita"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Cursori volume espansi"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Cursori volume compressi"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"disattivare audio di %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"riattivare audio di %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> in riproduzione su"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio riprodotto su:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Ottimizzatore UI di sistema"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Spostati avanti tra le app recenti"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Spostati indietro tra le app recenti"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Apri elenco di app"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostra barra delle app"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Apri impostazioni"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Apri l\'assistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Blocca lo schermo"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Attiva lo schermo diviso con l\'app corrente a destra"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Attiva lo schermo diviso con l\'app corrente a sinistra"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Passa da schermo diviso a schermo intero"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Con lo schermo diviso: sostituisci un\'app con un\'altra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Inserimento"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Passa alla lingua successiva"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Non disturbare"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Viene rilevata la presenza dell\'utente"</string>
<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>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2881bad..414f347 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"×׊×ךת ׊××××× ×××¡× × ×ס×× ×¢× ××× ×× ×× ×-IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"עך×××"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"עך××ת ׊×××× ×ס×"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ש×ת××£ ×©× ×Š×××× ×ס×"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"׊×××× ×ª××× × ×סף"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ס××ךת ׊×××× ×ס×"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"××ש×ך ×× ×× ××× ×¢× ××× ××××š× ×©××. ××××š× ×©×× ×ש ×׀שך×ת ×׊׀×ת ×׀ך××× ××× ×××€××ק׊××ת ש×ש×××ש, ××××§×× ×××× ×××¡× ×©××, ××× ×× ××ת×."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"×× ×¢××× × ×× ×¢×ª ×¢× ××× ×¡×××× ××××× ×"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"××× × ××€× × ×× ×××\n×××ש×ך × × ×¢×, ××תך ××× × ×ס××× ×ת ×××××× ×× ×¢×××"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"×××ך×ת ׊×××"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"××ס׀ת ×ת××××ת ××××€× ××××××× ×××××"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"×שתק×"</string>
<string name="media_device_cast" msgid="4786241789687569892">"××€×¢×ת Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"×× ×××× ×× ×׊×׊×× ××שתק"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"×× ×××× ×× ×ת××× × \'× × ×× ××׀ך××¢\' ×××€×¢×ת"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"×× ×××× ×× ×ת××× × \'× × ×× ××׀ך××¢\' ×××€×¢×ת"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ×ש ×××§×ש ××× ×××× ×ת ××שתק×."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ׊ך×× ×××§×ש ××× ×××××ך ך××. ××ת×× ×©×©×ך××ª× ×× ××ש×ת ××שתק××."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ×ש ×××§×ש ××× ××שת××§. ××ת×× ×©×©×ך××ª× ×× ××ש×ת ××שתק×."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ך××"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"××§×š× ×¢×׊×ת ×§×× ×©× %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"××××€×× ×׊××Š× ×ש×תק×××ת ש×××ת ××תך××ת (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"××× × ×©× ×××ך×ת ××€××"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"×€×¡× ××××× ×©× ×¢×׊×ת ××§×× ×××Š× ××ך××"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"×€×¡× ××××× ×©× ×¢×׊×ת ××§×× ×××Š× ×××××¥"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"××©×ª×§× ×©× %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"××××× ×××©×ª×§× ×©× %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"××€×¢×× ×©× <xliff:g id="LABEL">%s</xliff:g> ×××ש×ך"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"×××××× ×××€×¢× ×××ש×ך"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"××€×××£ ×§×××× ×××€××ק׊××ת ×××ך×× ×ת"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"××€×××£ ××××š× ×××€××ק׊××ת ×××ך×× ×ת"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"׀ת××× ×©× ×š×©××ת ×××€××ק׊××ת"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"×׊×ת סך×× ×××€××ק׊××ת"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"׀ת××ת ××××ך×ת"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"×׀ת××ת Google Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"××¡× ×× ×¢×××"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"×× ××¡× ×××¡× ××€××Š× ×¢× ×××€××ק׊×× ×× ××××ת ×-RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"×× ××¡× ×××¡× ××€××Š× ×¢× ×××€××ק׊×× ×× ××××ת ×-LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"××××€× ×××¡× ××€××Š× ×××¡× ×××"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"×ש×××¡× ××€×׊×: ××××€× ××× ××€××ק׊×× ××ת ×××ךת"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"×§××"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"××¢×ך ××©×€× ××××"</string>
@@ -839,15 +840,15 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"×׊×ת ס××× ×תך××ת ××¢×××€×ת × ××××"</string>
<string name="other" msgid="429768510980739978">"××ך"</string>
- <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"×סךת ××ך××"</string>
- <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"××ס׀ת ××ך×× ×ס××£ ×ךש×××"</string>
- <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"××¢×ךת ××ך××"</string>
- <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"××ס׀ת ×ך××"</string>
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"×סךת ×××׊×"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"××ס׀ת ××××Š× ×ס××£ ×ךש×××"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"××¢×ךת ×××׊×"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"××ס׀ת ××׊×"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"××¢××š× ××××§×× <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"×××¡×€× ××××§×× <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"×××§×× <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"××ך×× × ×סף"</string>
- <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"××ך×× ××סך"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"××××Š× × ×סף"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"××××Š× ××סך"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"×¢××š× ×××ך×ת ×××ך×ת."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"×תך××ת <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"׀ת××ת ×××ך×ת."</string>
@@ -1179,9 +1180,9 @@
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"××× ××¢××ך ××× ×š×©×ª×ת, ׊ך×× ×× ×ª×§ ×ת ×××ª×š× ×"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"××× ×ש׀ך ×ת ×××××ת ×ש×××ש ×××ש×ך, ××€××ק׊××ת ×ש×ך×ת×× ××××× ××׀ש ךשת×ת Wi-Fi ××× ×©××, ×× ××שך ×-Wi-Fi ××××. ×׀שך ××©× ×ת ××ת ××××ך×ת ×©× ×××€×ש × ×§×××ת Wi-Fi. "<annotation id="link">"ש×× ××"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"×ש××ª× ×©× ××Š× ××ס×"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"×××€××ק׊×× <xliff:g id="APPNAME">%1$s</xliff:g> ××קשת ×××ס××£ ××××ך×ת ××××ך×ת ×ת ××ך×× ×××"</string>
- <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"××ס׀ת ×ך××"</string>
- <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"×× ×××ס××£ ×ך××"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"××€××ק׊××ת <xliff:g id="APPNAME">%1$s</xliff:g> ××קשת ×××ס××£ ××××ך×ת ××××ך×ת ×ת ××××Š× ×××"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"×××ס××£ ××׊×"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"×× ×××ס××£ ××׊×"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"×××ךת ×שת×ש"</string>
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{××€××ק׊×× ××ת (#) ×€×¢×××}one{# ××€××ק׊××ת ×€×¢×××ת}two{# ××€××ק׊××ת ×€×¢×××ת}other{# ××€××ק׊××ת ×€×¢×××ת}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"××××¢ ××ש"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"××׊××× ×ס×××"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"××׊××× ××××קך××€×× ×ס××××"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"×××קך××€×× ×ס××"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"× × ×× ××׀ך××¢"</string>
<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>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 070713a..78f1df2 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ã¹ã¯ãªãŒã³ã·ã§ããã®æ®åœ±ã¯ IT 管çè
ã«ãã£ãŠãããã¯ãããŠããŸãã"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ç·šé"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ã¹ã¯ãªãŒã³ã·ã§ãããç·šéããŸã"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ã¹ã¯ãªãŒã³ã·ã§ãããå
±æ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ãã£ããã£ç¯å²ãæ¡å€§"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ã¹ã¯ãªãŒã³ã·ã§ãããéããŸã"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ãã®ããã€ã¹ã¯ä¿è·è
ã«ãã£ãŠç®¡çãããŠããŸããä¿è·è
ã¯ãããªãã䜿çšããã¢ããªãããªãã®çŸåšå°ãããã€ã¹ã®å©çšæéãªã©ã®æ
å ±ã確èªãããã管çãããã§ããŸãã"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ä¿¡é ŒãšãŒãžã§ã³ããããã¯è§£é€ã管ç"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"çé£é²æ¢\nããã€ã¹ããã㯠- ããã¯è§£é€ã«ç¹°ãè¿ã倱æ"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"èªèšŒã®è©Šè¡åæ°ãäžéãè¶
ãããããããã€ã¹ãããã¯ãããŸãã"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ããã€ã¹ãããã¯ãããŸãã\nèªèšŒã«å€±æããŸãã"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>ã<xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"é³å£°ã®èšå®"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ã¡ãã£ã¢ã®èªååå¹èµ·ãã"</string>
@@ -752,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"æè¿äœ¿ã£ãã¢ããªã確èªãã"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"æè¿äœ¿ã£ãã¢ããªã確èªããïŒéæ¹åïŒ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ã¢ããªã®äžèЧãéã"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ã¿ã¹ã¯ããŒã衚瀺ãã"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"èšå®ãéã"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ã¢ã·ã¹ã¿ã³ããéã"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ç»é¢ãããã¯"</string>
@@ -761,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"åå²ç»é¢ã«ããŠçŸåšã®ã¢ããªãå³åŽã«èšå®ãã"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"åå²ç»é¢ã«ããŠçŸåšã®ã¢ããªãå·ŠåŽã«èšå®ãã"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"åå²ç»é¢ããå
šç»é¢ã«åãæ¿ãã"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"åå²ç»é¢äž: ã¢ããªãé ã«çœ®æãã"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"å
¥å"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"次ã®èšèªã«åãæ¿ãã"</string>
@@ -1259,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ã«ã¡ã©ã¯ãããã¯ãããŠããŸã"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ã«ã¡ã©ãšãã€ã¯ã¯ãããã¯ãããŠããŸã"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ãã€ã¯ã¯ãããã¯ãããŠããŸã"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ãµã€ã¬ã³ã ã¢ãŒã"</string>
<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>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5a11a75..64478d7 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ááá áááá¡ ááááááááá¡ áááááŠááá áááááááááá áá¥áááá IT ááááááá¡á¢á áá¢áá áá¡ áááá "</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"á áááá¥á¢áá ááá"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ááá áááá¡ ááááááááá¡ á áááá¥á¢áá ááá"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ááá áááá¡ ááááááááá¡ áááááá ááá"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ááá¢áá¡ ááŠáááááá"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ááá áááá¡ ááááááááá¡ ááá®á£á áá"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"áá ááá¬á§áááááááá¡ áá¥áááá áášááááá ááá áááá¡. áá¥áááá áášááááá á®ááááá¡ áá ááá áááá¡ áá¡áá ááá€áá áááªááá¡, á áááá á᪠áá áá¡ áá¥ááá áááá ááááá§ááááá£áá ááááá, áá¥áááá áááááá áááá áá áá¥ááá áááá ááá ááááá ááá¢áá ááá£áá áá á."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ááááááááááá TrustAgent-áá¡ áááá "</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ááááá ááá¡áááá áááªáá\náááááááá áááááááááá¡ áááá á ááªááááááá¡ áááá."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ááá¬á§ááááááá á©ááááá¢á, ááá€áá¥á¡áá áá ááá¢áá ááááªááá¡ ááá¢áá¡ááá¢áá áááá á ááªáááááá"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ááá¬á§ááááááá á©áááá¢áááá\nááá¢áá ááááªáá ááá ášáá¡á á£ááá"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"á®ááá¡ ááá áááá¢á ááá"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"áááááá¡ ááá¢áá. á¡á£áá¢áá¢á áá ááá"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"áááá£áááá"</string>
<string name="media_device_cast" msgid="4786241789687569892">"á¢á ááá¡ááá ááá"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ááá áá¡ áááá£ááááá¡ áááá á®ááááá¡áá¬ááááá áá áá"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ááá£á¬áááááááá, á©áá áá£ááá „áá ášáááá¬á£á®áá“ á ááááá"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ááá£á¬áááááááá, á©áá áá£ááá „áá ášáááá¬á£á®áá“ á ááááá"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ášááá®áá áááá£ááááá¡ ááá¡áá£á¥áááááá."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ášááá®áá áááá ááªáááá ááá¡áá§ááááááá. ášááá«áááá áááá£áááá¡ ááá á¢ááá á¬áááááá¡ á¡áá ááá¡ááááª."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ášááá®áá ááá¡ááá£áááááá. ášááá«áááá áááá£áááá¡ ááá á¢ááá á¬áááááá¡ á¡áá ááá¡ááááª."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"áááá ááªáá"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s-áá¡ á®ááá¡ ááá áááá¡ á¡áášá£ááááááá"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ááá áááá¡á áá ášáá¢á§áááááááááá¡ áááŠáááá¡áá¡ áááá ááááá (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"áá£áááá¡ ááááá¡áááá¡ ááá áááá¢á áááá¡ ááá®á¡áá"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"á®ááá¡ á¡áááááá áááá¡ ááá€áá ááááá"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"á®ááá¡ á¡áááááá áááá¡ á©ááááªáá"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s-áá¡ áááá£áááá"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s-áá¡ áááá£ááááá¡ ááá®á¡áá"</string>
<string name="media_output_label_title" msgid="872824698593182505">"á£áá ááá¡ <xliff:g id="LABEL">%s</xliff:g>:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"áá£ááá áááááá ááá"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"á¡áá¡á¢áááá¡ UI á¢á£ááá á"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"á¬áá ááááá¡ááá áááááá ááááááá áááááá¡ ááášáááááá"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"á£ááá ááááá¡ááá áááááá ááááááá áááááá¡ ááášáááááá"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"áááááá¡ á¡ááá¡ ááá®á¡áá"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ááááªááááá ááááá¡ á©áááááá"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ááá áááá¢á áááá¡ ááá®á¡áá"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"áá¡áá¡á¢ááá¢áá¡ ááá®á¡áá"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"á©áááá¢ááá ááá ááá"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ááá áááá¡ ááá§áá€áá¡ ášáá§áááá áááááááá á áááá RHS-ášá"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ááá áááá¡ ááá§áá€áá¡ ášáá§áááá áááááááá á áááá LHS-ášá"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ááááá ááá ááá áááá¡ ááá§áá€áááá á¡á á£á ááá áááá"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ááá áááá¡ ááá§áá€áá¡ áá áá¡: áá áá áááá¡ áááá áá á©ááááªááááá"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ášáá§áááá"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ášááááá ááááá ááááá ááá"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ááááá á áááááááááá"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ááááá á áá áááá áá€ááá áááááááááá"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"áááá áá€ááá áááááááááá"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"áá ášáááá¬á£á®áá"</string>
<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>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 781dbbf..8b86832 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ÓкÑÐŒÑÑÒ£Ñз ÑкÑОМÑÐŸÑ Ð¶Ð°ÑаÑÒа ÑÑйÑÐŒ ÑалЎÑ."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ӚзгеÑÑÑ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"СкÑОМÑПÑÑÑ Ó©Ð·Ð³ÐµÑÑÑ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"СкÑОМÑПÑÑÑ Ð±Ó©Ð»ÑÑÑ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ТаÒÑ ÑÑÑеÑке ÑÒ¯ÑÑÑÑ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"СкÑОМÑПÑÑÑ Ð¶Ð°Ð±Ñ"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ðұл ÒÒ±ÑÑлÒÑÐœÑ Ð°Ñа-аМаңÑз баÑÒаÑаЎÑ. ÐÑа-аМаңÑз ÑÑз пайЎалаМаÑÑМ ÒПлЎаМбалаÑ, геПЎеÑегÑÒ£Ñз жÓМе Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑ ÑаÒÑÑÑÒ£Ñз ÑОÑÒÑÑ Ð°ÒпаÑаÑÑÑ ÐºÓ©Ñе жÓМе баÑÒаÑа алаЎÑ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent аÑÒÑÐ»Ñ ÒÒ±Ð»Ð¿Ñ Ð°ÑÑлЎÑ."</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ò°ÑлÑÒÑаМ ÒПÑÒаÑ\nÒÒ±ÑÑлÒÑ ÒұлÑпÑалÒаМ, ÒұлÑпÑÑ Ð°ÑÑÒа ÑÑÐŒ көп ÓÑÐµÐºÐµÑ Ð¶Ð°ÑалЎÑ."</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐÑбÑÑ Ð¿Ð°ÑаЌеÑÑлеÑÑ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐвÑПЌаÑÑÑ ÑÑбÑОÑÑ ÒПÑÑ"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ÐÑбÑÑÑМ Ó©ÑÑÑÑ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ТÑаМÑлÑÑОÑлаÑ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÒПлжеÑÑÐŒÐŽÑ ÐµÐŒÐµÑ, ÑÑлЎÑÑлаÑÑ Ó©ÑÑÑÑлÑ."</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐÐ°Ð·Ð°Ð»Ð°ÐŒÐ°Ñ ÑÐµÐ¶ÐžÐŒÑ ÒПÑÑлÒаМЎÑÒÑаМ өзгеÑÑÑ ÐŒÒ¯ÐŒÐºÑМ еЌеÑ."</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐÐ°Ð·Ð°Ð»Ð°ÐŒÐ°Ñ ÑÐµÐ¶ÐžÐŒÑ ÒПÑÑлÒаМЎÑÒÑаМ өзгеÑÑÑ ÐŒÒ¯ÐŒÐºÑМ еЌеÑ."</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐÑбÑÑÑМ ÒПÑÑ Ò¯ÑÑМ ÑÒ¯ÑÑÑÒ£Ñз."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐÑÑÑл ÑежОЌÑМ ПÑМаÑÑ Ò¯ÑÑМ ÑÒ¯ÑÑÑÒ£Ñз. ÐÑÐœÐ°Ð¹Ñ ÐŒÒ¯ÐŒÐºÑМЎÑк ÒÑзЌеÑÑеÑÑМÑÒ£ ÐŽÑбÑÑÑ Ó©ÑÑÑ ÐŒÒ¯ÐŒÐºÑМ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐÑбÑÑÑМ Ó©ÑÑÑÑ Ò¯ÑÑМ ÑÒ¯ÑÑÑÒ£Ñз. ÐÑÐœÐ°Ð¹Ñ ÐŒÒ¯ÐŒÐºÑМЎÑк ÒÑзЌеÑÑеÑÑМÑÒ£ ÐŽÑбÑÑÑ Ó©ÑÑÑ ÐŒÒ¯ÐŒÐºÑМ."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÐŽÑÑÑлЎеÑÑ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"ÐÑбÑÑÑÑ Ð±Ð°ÑÒаÑÑ ÑлеЌеМÑÑеÑÑ: %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÒПңÑÑаÑÐ»Ð°Ñ ÐŒÐµÐœ Ñ
абаÑлаМЎÑÑÑÐ»Ð°Ñ ÐŽÑбÑÑÑ ÒПÑÑÐ»Ñ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"КÑÒÑÑ Ð¿Ð°ÑаЌеÑÑлеÑÑМ еМгÑзÑ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐÑбÑÑ ÐŽÐµÒ£Ð³ÐµÐ¹ÑМÑÒ£ жүгÑÑÑÐºÑ ÑеÑÑегÑÑÑеÑÑ Ð¶Ð°Ð¹ÑлЎÑ."</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐÑбÑÑ ÐŽÐµÒ£Ð³ÐµÐ¹ÑМÑÒ£ жүгÑÑÑÐºÑ ÑеÑÑегÑÑÑеÑÑ Ð¶ÐžÑлЎÑ."</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ÐŽÑбÑÑÑМ Ó©ÑÑÑÑ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ÐŽÑбÑÑÑМ ÒПÑÑ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ПйМаÑÑлаÑÑМ ÒÒ±ÑÑлÒÑ:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑЎОП ПйМаÑÑлаÑÑМ ÒÒ±ÑÑлÒÑ:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ÐүйелÑк пайЎалаМÑÑÑлÑÒ ÐžÐœÑеÑÑÐµÐ¹Ñ ÑÑМеÑÑ"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"СПңÒÑ ÒПлЎаМбалаÑÒа алÒа Ó©ÑÑ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"СПңÒÑ ÒПлЎаМбалаÑÒа аÑÑÒа Ó©ÑÑ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°Ð»Ð°Ñ ÑÑзÑÐŒÑМ аÑÑ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ТапÑÑÑÐŒÐ°Ð»Ð°Ñ Ð¶ÐŸÐ»Ð°ÒÑМ көÑÑеÑÑ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐаÑаЌеÑÑлеÑÐŽÑ Ð°ÑÑ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant-ÑÑ Ð°ÑÑ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐкÑÐ°ÐœÐŽÑ ÒұлÑпÑаÑ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐөлÑМгеМ ÑкÑаМ ÑежОЌÑМе кÑÑÑ (аÒÑЌЎаÒÑ ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°ÐœÑ ÐŸÒ£Òа ПÑМалаÑÑÑÑÑ)"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐөлÑМгеМ ÑкÑаМ ÑежОЌÑМе кÑÑÑ (аÒÑЌЎаÒÑ ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°ÐœÑ ÑПлÒа ПÑМалаÑÑÑÑÑ)"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐөлÑМгеМ ÑкÑаМ ÑежОЌÑМеМ ÑПлÑÒ ÑкÑаМ ÑежОЌÑМе аÑÑÑÑ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐкÑÐ°ÐœÐŽÑ Ð±Ó©Ð»Ñ ÐºÐµÐ·ÑМЎе: бÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÐ±Ð°ÐœÑ Ð±Ð°ÑÒаÑÑЌеМ алЌаÑÑÑÑÑ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐМгÑзÑ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐелеÑÑ ÑÑлге аÑÑÑÑ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑа блПкÑалÒаМ."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑа ЌеМ ЌОкÑПÑПМ блПкÑалÒаМ."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑПМ блПкÑалÒаМ."</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ÐазалаЌаÑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 60a1970..083586e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"áá¶áááá¢ááááááááááŒááá¶áááááááá¶áááááá¢ááááááááááááâááááááááááá¶ááá·áááá¶ááááá¢ááá"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"áá"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ááâááŒáááâá¢áááááá"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"á
áááááááááŒáááá¢áááááá"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ááâá
áááŸáááá"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"á
ááá¶áá
ááâááŒáááâá¢áááááá"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"á§áááááâáááâáááá·áâáááááâáá¶áâáááááááááâáááááá¶áá¶áá·áá¶á¢áááá áá¶áá¶áá·áá¶ááááá¢áááá¢á¶á
ááŸá áá·áááááááááááááááá¶áâááŒá
áá¶ áááááá·áážáááá¢áááááá០áážáá¶ááááááá¢ááá áá·áááááááááááŸáááá¶ááá§áááááááááá¢ááááá¶ááŸáá"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"áá¶áâáááááâááááááá¶áááá¶áââáá»áá
á·ááá"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"áá¶ááá¶ááá¶áâá
ááâááœá
\náá¶áá
á¶ááááá§ááááá áá¶ááááá¶áá¶ááááááá
áááŸáááááá"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"áá¶ááááááááá¡áá"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"áá¶ááá¢áááááááááŸáááááááááááááááááááá·"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"áá·áááá¡áá"</string>
<string name="media_device_cast" msgid="4786241789687569892">"áááááŒá"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"áá·áâá¢á¶á
âááááŸâáá¶áâááâ áááááâááá¡ááâááááâááááŒáâáá¶áâáá·á"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"áá·áá¢á¶á
ááááŸáá¶ááá ááááá¶ááá»ááá¶ááá»áâáááá¶áááááŒááá¶áááŸá"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"áá·áá¢á¶á
ááááŸáá¶ááá ááááá¶ááá»ááá¶ááá»áâáááá¶áááááŒááá¶áááŸá"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sá áááááŸáááážááŸáááá¡ááá"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sá áááááŸáááážáááááá²áááááá áááá¶áááááááááá¶áááááŸáááá¶ááá¢á¶á
áá¹áááááŒááá¶ááá·áááá¡ááá"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sá áááááŸáááážáá·áááá¡ááá áááá¶áááááááááá¶áááááŸáááá¶ááá¢á¶á
áá¹áááááŒááá¶ááá·áááá¡ááá"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ááá"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ááá¶áâááááá¶âááááá·áâááá¡áá"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"áá¶áâá á
âááŒááááá áá·áâáá¶áááŒáâáááá¹áâáá¹áâáááá (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"á
áŒááá¶ááááááá§ááááááááá"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"áá¶áááááážááááá¶áááááá·áááááá·áááá¡áá"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"áá¶ááááááœááááá¶áááááá·áááááá·áááá¡áá"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"áá·áááá¡áá %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ááŸáâááá¡áá %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"áááá»áá
á¶ááââ <xliff:g id="LABEL">%s</xliff:g> áá
âááŸ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ááá¡áááá¹áááááá
ááŸ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"áááááá·áážáááááœá UI áááááááá"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"áá»ááááá
áá»á ááŸáááážááŸááááááá·áážáááážá"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"áá»áááááááááá ááŸáááážááŸááááááá·áážáááážá"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ááŸáááááážáááááá·ááž"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"áááá á¶áááá¶ááá·á
áá
áá¶á"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ááŸááá¶áááááá"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ááŸáâááááœááá¶á"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"á
á¶ááâááâá¢áááááá"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"á
áŒááááá»ááá»ááá¶ááááááá¢áááááááááááááŸáááááá·áážáá
áá
á»áááááááá
áá¶ááááá¶ááá"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"á
áŒááááá»ááá»ááá¶áâáááááá¢áááááááááááááŸáááááá·áážáá
áá
á»áááááááá
áá¶áááááááá"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ááááŒááážáá»ááá¶áâáááááá¢áááááááá
áá¶á¢ááááááááá"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"áááá»áá¢áá¡á»ááááááááŸáá»ááá¶ááááááá¢ááááááá ááááœááááááá·áážáážááœááá
ááœáááá"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"áááá
áŒá"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ááááŒááá
áá¶áá¶ááááá¶áá"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"áá¶áâááááááá¶ááâáá¶ááááá¶"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"áá¶áááááááá¶ááâáá¶ááááá¶ áá·áâáážááááŒá áááŒá"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"áá¶áâááááááá¶ááâáážááááŒá áááŒá"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"áá»áâáááá¶á"</string>
<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>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e498ca4..df50db6 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ಞà³à²à³à²°à³à²šà³à²¶à²Ÿà²à³à²à²³à²šà³à²šà³ ಀà³à²à³à²Šà³à²à³à²³à³à²³à³à²µà³à²Šà²šà³à²šà³ ಚಿಮà³à²® IT ಚಿರà³à²µà²Ÿà²¹à²à²°à³ ಚಿರà³à²¬à²à²§à²¿à²žà²¿à²Šà³à²Šà²Ÿà²°à³"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à²à²¡à²¿à²à³ ಮಟಡಿ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ಞà³à²à³à²°à³à²šà³à²¶à²Ÿà²à³ à²
ಚà³à²šà³ à²à²¡à²¿à²à³ ಮಟಡಿ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ಞà³à²à³à²°à³à²šà³à²¶à²Ÿà²à³ à²
ಚà³à²šà³ ಹà²à²à²¿à²à³à²³à³à²³à²¿"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à²à²šà³à²šà²·à³à²à³ à²à³à²¯à²Ÿà²ªà³à²à²°à³ ಮಟಡಿ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ಞà³à²à³à²°à³à²šà³à²¶à²Ÿà²à³ à²
ಚà³à²šà³ ವà²à²Ÿà²à³à²³à²¿à²žà²¿"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ಠಞಟಧಚವಚà³à²šà³ ಚಿಮà³à²® ಪà³à²·à²à²°à³ ಚಿರà³à²µà²¹à²¿à²žà³à²€à³à²€à²¿à²Šà³à²Šà²Ÿà²°à³. ಚà³à²µà³ ಬಳಞà³à²µ à²à³à²¯à²ªà³à²à²³à³, ಚಿಮà³à²® ಞà³à²¥à²³ ಮಀà³à²€à³ ಚಿಮà³à²® ವà³à²à³à²·à²£à²Ÿ à²
ವಧಿಯà²à²€à²¹ ಮಟಹಿಀಿಯಚà³à²šà³ ಚಿಮà³à²® ಪà³à²·à²à²°à³ ಚà³à²¡à²¬à²¹à³à²Šà³ ಮಀà³à²€à³ ಚಿರà³à²µà²¹à²¿à²žà²¬à²¹à³à²Šà³."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ಚಿà²à²Š à²
ಚà³à²²à²Ÿà²à³ ಮಟಡಲಟà²à²¿à²Šà³"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à²à²³à³à²³à²€à²šà²Š ರà²à³à²·à²£à³\nಞಟಧಚ ಲಟà²à³ à²à²à²¿à²Šà³, à²
ಚà³à²²à²Ÿà²à³à²à³ ಹà³à²à³à²à³ ಪà³à²°à²¯à²€à³à²š..."</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ಞà³à²à²¡à³ ಞà³à²à³à²à²¿à²à²à³à²à²³à³"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ಞà³à²µà²¯à²à²à²Ÿà²²à²¿à²€ ಶà³à²°à³à²·à²¿à²à³ ಮಟಧà³à²¯à²®"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ಮà³à²¯à³à²à³"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ಬಿಀà³à²€à²°à²¿à²žà²¿"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ರಿà²à²à³ ಮà³à²¯à³à²à³ à²à²à²¿à²°à³à²µ à²à²Ÿà²°à²£ ಲà²à³à²¯à²µà²¿à²²à³à²²"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à²
ಡà²à²£à³ ಮಟಡಬà³à²¡à²¿ ಫà³à²à²°à³ à²à²šà³ à²à²à²¿à²°à³à²µà³à²Šà²°à²¿à²à²Š ಲà²à³à²¯à²µà²¿à²²à³à²²"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à²
ಡà²à²£à³ ಮಟಡಬà³à²¡à²¿ ಫà³à²à²°à³ à²à²šà³ à²à²à²¿à²°à³à²µà³à²Šà²°à²¿à²à²Š ಲà²à³à²¯à²µà²¿à²²à³à²²"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à²
ಚà³à²®à³à²¯à³à²à³ ಮಟಡà³à²µà³à²Šà²à³à²à²Ÿà²à²¿ à²à³à²¯à²Ÿà²ªà³ ಮಟಡಿ."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à²à²à²ªà²šà²à³à²à³ ಹà³à²à²Šà²¿à²žà²²à³ à²à³à²¯à²Ÿà²ªà³ ಮಟಡಿ. à²à³à²¯à²à³à²žà³à²žà²¿à²¬à²¿à²²à²¿à²à²¿ ಞà³à²µà³à²à²³à²šà³à²šà³ ಮà³à²¯à³à²à³ ಮಟಡಬಹà³à²Šà³."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮà³à²¯à³à²à³ ಮಟಡಲೠà²à³à²¯à²Ÿà²ªà³ ಮಟಡಿ. à²à³à²¯à²à³à²žà³à²žà²¿à²¬à²¿à²²à²¿à²à²¿ ಞà³à²µà³à²à²³à²šà³à²šà³ ಮà³à²¯à³à²à³ ಮಟಡಬಹà³à²Šà³."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವà³à²¬à³à²°à³à²à³"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ವಟಲà³à²¯à³à²®à³ ಚಿಯà²à²€à³à²°à²à²à²³à³"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"(<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>) ಚಲà³à²²à²¿ à²à²°à³à²à²³à³ ಮಀà³à²€à³ à²
ಧಿಞà³à²à²šà³à²à²³à³ ರಿà²à²à³ à²à²à³à²€à³à²€à²µà³"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à²à²à³à²ªà³à²à³ ಞà³à²à³à²à²¿à²à²à³à²à²³à²šà³à²šà³ ಪà³à²°à²µà³à²¶à²¿à²žà²¿"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ವಟಲà³à²¯à³à²®à³ ಞà³à²²à³à²¡à²°à³à²à²³à²šà³à²šà³ ವಿಞà³à²€à³à²€à²à³à²³à²¿à²žà²²à²Ÿà²à²¿à²Šà³"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ವಟಲà³à²¯à³à²®à³ ಞà³à²²à³à²¡à²°à³à²à²³à²šà³à²šà³ à²à³à²à³à²à²¿à²žà²²à²Ÿà²à²¿à²Šà³"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ಮà³à²¯à³à²à³ ಮಟಡಿ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à²
ಚà³à²®à³à²¯à³à²à³ ಮಟಡಿ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ಚಲà³à²²à²¿ ಪà³à²²à³ à²à²à³..."</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à²à²²à³à²²à²¿ à²à²¡à²¿à²¯à³ ಪà³à²²à³..."</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ಞಿಞà³à²à² UI à²à³à²¯à³à²šà²°à³"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à²à²€à³à²€à³à²à³à²à³ ಬಳಞಿಊ à²à³à²¯à²ªà³à²à²³ ಞಹಟಯಊಿà²à²Š ಮà³à²à²Šà²à³à²à³ ಹà³à²à²¿"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à²à²€à³à²€à³à²à³à²à³ ಬಳಞಿಊ à²à³à²¯à²ªà³à²à²³ ಞಹಟಯಊಿà²à²Š ಹಿà²à²Šà²à³à²à³ ಹà³à²à²¿"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à²à³à²¯à²ªà³à²à²³ ಪà²à³à²à²¿à²¯à²šà³à²šà³ ಀà³à²°à³à²¯à²¿à²°à²¿"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à²à²Ÿà²žà³à²à³à²¬à²Ÿà²°à³ à²
ಚà³à²šà³ ಀà³à²°à²¿à²žà²¿"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ಞà³à²à³à²à²¿à²à²à³à²à²³à²šà³à²šà³ ಀà³à²°à³à²¯à²¿à²°à²¿"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"assistant à²
ಚà³à²šà³ ಀà³à²°à³à²¯à²¿à²°à²¿"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ಞà³à²à³à²°à³à²šà³ ಲಟà²à³ ಮಟಡಿ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS à²à³ à²à²°à³à²µ ಪà³à²°à²žà³à²€à³à²€ à²à³à²¯à²ªà³ ಞಹಟಯಊಿà²à²Š ಞà³à²à³à²°à³à²šà³ ಬà³à²°à³à²ªà²¡à²¿à²žà²¿ ಮà³à²¡à³ ಚಮà³à²Šà²¿à²žà²¿"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS à²à³ à²à²°à³à²µ ಪà³à²°à²žà³à²€à³à²€ à²à³à²¯à²ªà³ ಞಹಟಯಊಿà²à²Š ಞà³à²à³à²°à³à²šà³ ಬà³à²°à³à²ªà²¡à²¿à²žà²¿ ಮà³à²¡à³ ಚಮà³à²Šà²¿à²žà²¿"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ಞà³à²à³à²°à³à²šà³ ಬà³à²°à³à²ªà²¡à²¿à²žà²¿ ಮà³à²¡à³à²šà²¿à²à²Š ಪà³à²°à³à²£ ಞà³à²à³à²°à³à²šà³à²à³ ಬಊಲಿಞಿ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ಞà³à²à³à²°à³à²šà³ ಬà³à²°à³à²ªà²¡à²¿à²žà³à²µ ಞಮಯಊಲà³à²²à²¿: à²à²à²Šà³ à²à³à²¯à²ªà³à²šà²¿à²à²Š ಮಀà³à²€à³à²à²Šà³ à²à³à²¯à²ªà³à²à³ ಬಊಲಿಞಿ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à²à²šà³à²ªà³à²à³"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ಮà³à²à²Šà²¿à²š à²à²Ÿà²·à³à²à³ ಬಊಲಿಞಿ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à²à³à²¯à²Ÿà²®à²°à²Ÿà²µà²šà³à²šà³ ಚಿರà³à²¬à²à²§à²¿à²žà²²à²Ÿà²à²¿à²Šà³"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à²à³à²¯à²Ÿà²®à²°à²Ÿ ಮಀà³à²€à³ ಮà³à²à³à²°à³à²«à³à²šà³ à²
ಚà³à²šà³ ಚಿರà³à²¬à²à²§à²¿à²žà²²à²Ÿà²à²¿à²Šà³"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ಮà³à²à³à²°à³à²«à³à²šà³ à²
ಚà³à²šà³ ಚಿರà³à²¬à²à²§à²¿à²žà²²à²Ÿà²à²¿à²Šà³"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"à²
ಡà²à²£à³ ಮಟಡಬà³à²¡à²¿"</string>
<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>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 75a6808..4c44228 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT êŽëЬìê° ì€í¬ëŠ°ì· ìŽ¬ìì íì©íì§ ììµëë€."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ìì "</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ì€í¬ëŠ°ì· ìì "</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ì€í¬ëŠ°ì· ê³µì "</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ë 캡ì²íêž°"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ì€í¬ëŠ°ì· ë«êž°"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ë¶ëªšëìŽ êŽëЬíë êž°êž°ì
ëë€. ë¶ëªšëìŽ ëŽê° ì¬ì©íë ì±, ëŽ ìì¹, êž°êž° ì¬ì© ìê°ê³Œ ê°ì ì 볎륌 ë³Žê³ êŽëЬí ì ììµëë€."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgentê° ì êž íŽì íš"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ëë ë°©ì§\nêž°êž° ì ê¹, ì êž íŽì ìë íìê° ë묎 ë§ì"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ìžìŠ ìë íìê° ë묎 ë§ì êž°êž°ê° ì 게ìµëë€."</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"êž°êž° ì ê¹\nìžìŠì ì€íšíš"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ì늬 ì€ì "</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"믞ëìŽ ìë§ ìë ìì±"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ììê±°"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ì ì¡"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"벚ìëŠ¬ê° ììê±°ëìŽ ììŒë¯ë¡ ì¬ì©í ì ìì"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ë°©íŽ êžì§ 몚ëê° ì¬ì© ì€ì ëìŽ ììŽ ì¬ì©í ì ìì"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ë°©íŽ êžì§ 몚ëê° ì¬ì© ì€ì ëìŽ ììŽ ì¬ì©í ì ìì"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ííì¬ ìì거륌 íŽì íìžì."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ííì¬ ì§ëìŒë¡ ì€ì íìžì. ì ê·Œì± ìë¹ì€ê° ììê±°ë ì ììµëë€."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ííì¬ ììê±°ë¡ ì€ì íìžì. ì ê·Œì± ìë¹ì€ê° ììê±°ë ì ììµëë€."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ì§ë"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s 볌륚 컚ížë¡€"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ì í ë° ìëŠŒìŽ ì€ë©Ž 벚ìëŠ¬ê° ìžëŠŒ(<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ì¶ë ¥ ì€ì ìŽêž°"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"볌륚 ì¬ëŒìŽë íŒì¹š"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"볌륚 ì¬ëŒìŽë ì í"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ììê±°"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ììê±° íŽì "</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ì¬ì ìì¹:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ì€ëì€ ì¬ì ìì¹:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ìì€í
UI íë"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ìµê·Œ ì± ê° ììŒë¡ ìí"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ìµê·Œ ì± ê° ë€ë¡ ìí"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ì± ëª©ë¡ ìŽêž°"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"íì€í¬ ë° íì"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ì€ì ìŽêž°"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ìŽìì€íŽíž ìŽêž°"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ì êž í멎"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"íì¬ ì±ì ì€ë¥žìªœìŒë¡ 볎ëŽë í멎 ë¶í ì
ë ¥"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"íì¬ ì±ì ìŒìªœìŒë¡ 볎ëŽë í멎 ë¶í ì
ë ¥"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"í멎 ë¶í ìì ì 첎 í멎ìŒë¡ ì í"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"í멎 ë¶í ì€: ë€ë¥ž ì±ìŒë¡ ë°êŸžêž°"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ì
ë ¥"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ë€ì ìžìŽë¡ ì í"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"칎ë©ëŒ ì°šëšëš"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"칎ë©ëŒ ë° ë§ìŽí¬ ì°šëšëš"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ë§ìŽí¬ ì°šëšëš"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ë°©íŽ êžì§ 몚ë"</string>
<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>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 74bc943..2044f92 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT аЎЌОМОÑÑÑаÑПÑÑÒ£Ñз ÑкÑОМÑÐŸÑ ÑаÑÑÑÑга ÑÑÑÑ ÑалгаМ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ТүзөÑÒ¯Ò¯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"СкÑОМÑПÑÑÑ ÑүзөÑÒ¯Ò¯"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"СкÑОМÑПÑÑÑ Ð±Ó©Ð»Ò¯ÑÒ¯Ò¯"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÐөбүÑөөк ÑаÑÑÑÑ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"СкÑОМÑПÑÑÑ ÑеÑке кагÑÑ"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÐÑл ÑүзЌөкÑÒ¯ аÑа-ÑМең баÑкаÑаÑ. ÐÑа-ÑМең ÑеМ ОÑÑеÑкеМ кПлЎПМЌПлПÑÐŽÑ, кайЎа жүÑгөМүңЎү жаМа ÑүзЌөкÑÒ¯ каМÑа ÑбакÑÑ ÐºÐŸÐ»ÐŽÐŸÐœÐ³ÐŸÐœÑÒ£ÐŽÑ ÐºÓ©Ñүп, баÑкаÑÑп ÑÑÑаÑ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ÐÑеМОЌ агеМÑО кÑлпÑÑÑМ аÑÑÑ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ТүзЌөкÑүМ ÑÑÑЎалÑÑÑМаМ кПÑгПП\nТүзЌөк кÑлпÑлаМЎÑ. ÐÑлпÑÐœÑ Ð°ÑÑÑга Ó©ÑÓ© көп аÑÐ°ÐºÐµÑ Ð¶Ð°ÑалЎÑ"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ТүзЌөк кÑлпÑлаМЎÑ. ÐÑÑеМÑОÑОкаÑОÑЎаМ Ó©Ñүүгө Ó©ÑÓ© көп аÑÐ°ÐºÐµÑ Ð¶Ð°ÑалЎÑ"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ТүзЌөк кÑлпÑлаМЎÑ\nÐÑÑеМÑОÑОкаÑОÑЎаМ Ó©ÑкөМ жПкÑÑз"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐПбÑÑÑÑМ паÑаЌеÑÑлеÑО"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐвÑПЌаÑÑÑк кПÑÑПЌП жазÑÑлаÑ"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ҮМÑүз"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ТÑÑÐºÑ ÑкÑаМга ÑÑгÑÑÑ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ҮМÑүз ÑежОЌЎе жеÑкОлОкÑОз"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\"ТÑМÑÑÐŒÐŽÑ Ð°Ð»Ð±Ð°\" ÑежОЌО күйүк бПлгПМЎÑкÑаМ, жеÑкОлОкÑОз"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"\"ТÑМÑÑÐŒÐŽÑ Ð°Ð»Ð±Ð°\" ÑежОЌО күйүк бПлгПМЎÑкÑаМ, жеÑкОлОкÑОз"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ҮМүМ ÑÑгаÑÑÑ Ò¯ÑүМ ÑапÑап кПÑÒ£Ñз."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐОÑОлЎөөгө кПÑÑ Ò¯ÑүМ ÑапÑап кПÑÒ£Ñз. ÐÑайÑМ ЌүЌкүМÑүлүкÑÓ©Ñ ÐºÑзЌаÑÑМÑМ үМүМ Ó©ÑÒ¯Ñүп кПйÑП бПлПÑ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ҮМүМ Ó©ÑÒ¯ÑÒ¯Ò¯ Ò¯ÑүМ ÑапÑап кПÑÒ£Ñз. ÐÑайÑМ ЌүЌкүМÑүлүкÑÓ©Ñ ÐºÑзЌаÑÑМÑМ үМүМ Ó©ÑÒ¯Ñүп кПйÑП бПлПÑ."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ЎОÑОлЎөө"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s үМЎү баÑкаÑÑÑ ÑлеЌеМÑÑеÑО"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ЧалÑÑÐ»Ð°Ñ ÐŒÐµÐœÐµÐœ ÑÑкеÑÑЌелеÑЎОМ үМү ÑÑгаÑÑÐ»Ð°Ñ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ЧÑгаÑÑÑ Ð¿Ð°ÑаЌеÑÑлеÑОМ кОÑгОзүү"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ҮМЎүМ каÑÑÑлÑгÑМÑМ ÑÑÐŽÑÑЌалаÑÑ Ð¶Ð°Ð¹Ñп көÑÑÓ©ÑүлЎү"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ҮМЎүМ каÑÑÑлÑгÑМÑМ ÑÑÐŽÑÑЌалаÑÑ Ð¶ÑйÑÑÑÑÑÑлЎÑ"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s үМүМ баÑÑÑ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s үМүМ ÑÑгаÑÑÑ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> аÑкÑлÑÑ ÐŸÐ¹ÐœÐŸÑÑлÑÑЎа"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑЎОП ÑөЌөМкүЎө ПйМПÑÑлаÑ:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Ð¡ÐŸÒ£ÐºÑ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸÐ»ÐŸÑЎП алЎÑга Ó©ÑÒ¯Ò¯"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Ð¡ÐŸÒ£ÐºÑ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸÐ»ÐŸÑЎП аÑÑка кайÑÑÑ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐПлЎПМЌПлПÑÐŽÑМ ÑОзЌеÑОМ аÑÑÑ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ТапÑÑÑÐŒÐ°Ð»Ð°Ñ Ð¿Ð°ÐœÐµÐ»ÐžÐœ көÑÑÓ©ÑÒ¯Ò¯"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐаÑаЌеÑÑлеÑЎО аÑÑÑ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐаÑЎаЌÑÑÐœÑ Ð°ÑÑÑ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐкÑÐ°ÐœÐŽÑ ÐºÑлпÑлПП"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"УÑÑÑЎа Пң жакÑÐ°Ð³Ñ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸ ЌеМеМ ÑкÑÐ°ÐœÐŽÑ Ð±Ó©Ð»Ò¯Ò¯ÐœÒ¯ ОÑÑеÑÒ¯Ò¯"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"УÑÑÑЎа ÑПл жакÑÐ°Ð³Ñ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸ ЌеМеМ ÑкÑÐ°ÐœÐŽÑ Ð±Ó©Ð»Ò¯Ò¯ÐœÒ¯ ОÑÑеÑÒ¯Ò¯"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐкÑÐ°ÐœÐŽÑ Ð±Ó©Ð»Ò¯Ò¯ ÑежОЌОМеМ ÑПлÑк ÑкÑаМга кПÑПÑÑлÑÑ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐкÑÐ°ÐœÐŽÑ Ð±Ó©Ð»Ò¯Ò¯ ÑежОЌОМЎе Ð±ÐžÑ ÐºÐŸÐ»ÐŽÐŸÐœÐŒÐŸÐœÑ ÑкОМÑОÑОМе алЌаÑÑÑÑÑÑ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐОÑгОзүү"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐОйОМкО ÑОлге кПÑПÑÑлÑÑ"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑа бөгөÑÑөлЎү"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑа ЌеМеМ ЌОкÑПÑПМ бөгөÑÑөлЎү"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑПМ бөгөÑÑөлЎү"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ТÑМÑÑÐŒÐŽÑ Ð°Ð»Ð±Ð°"</string>
<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>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6652200..f109041 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àºàº¹à»à»àºàºŽà»àºà»àºàºà»àºàºàºµàºàºàºàºà»àº²àºàºàº¥àº±àºàºàºàº²àºàºà»àº²àºàº®àº¹àºà»à»àº²àºà»à»àº§à»."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à»àºà»à»àº"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à»àºà»à»àºàº®àº¹àºà»à»àº²àºà»"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à»àºà»àºàºàº±àºàº®àº¹àºà»à»àº²àºà»"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àºà»àº²àºàº®àº¹àºà»àºàºµà»àº¡à»àºàºµàº¡"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àºàºŽàºàº®àº¹àºà»à»àº²àºà»"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àºàºžàºàº°àºàºàºàºàºµà»à»àº¡à»àºàºàº±àºàºàº²àºà»àºàºàºà»à»à»àº¡à»àºàºàºàºà»àº²àº. àºà»à»à»àº¡à»àºàºàºàºà»àº²àºàºªàº²àº¡àº²àºà»àºàºŽà»àº à»àº¥àº° àºàº±àºàºàº²àºàºà»à»àº¡àº¹àºà»àºà» à»àºàº±à»àº: à»àºàº±àºàºàºµà»àºà»àº²àºà»àºà», ສະàºàº²àºàºàºµà» à»àº¥àº° à»àº§àº¥àº²à»à»àº²àºà»àºàºàºàºà»àº²àº."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"àºàº±àºàºàº¥àº±àºàºàºàº°à»àº§à»à»àºàº TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àºàº²àºàºà»àºàºàºàº±àºàºàº²àºàºàº·àºàº¥àº±àº\nàºàºàºàºàºžàºàº°àºàºàºàºàº·àºàº¥àº±àºàº, àºàº°àºàº²àºàº²àº¡àºàº»àºàº¥àº±àºàºàº«àºŒàº²àºà»àºàº·à»àºà»àºàºµàºà»àº"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àºàº²àºàºàº±à»àºàºà»àº²àºªàºœàº"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ສà»àº²àºàºàº³àºàº±àºàºàº²àºàº¡àºµà»àºàºà»àºàºàºàº±àºàºàº°à»àºàº¡àº±àº"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àºàºŽàº"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ສົà»àºàºªàº±àºàºàº²àº"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"àºà»à»àº¡àºµà»àº«à»à»àºà»à»àºàº·à»àºàºàºàº²àºàº¡àºµàºàº²àºàºàºŽàºàºªàºœàºà»àºà»àºàº»à»àº²"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"àºà»à»àº¡àºµà»àº«à»àºà»àºàºàº§à»àº²àº«à»àº²àº¡àº¥àº»àºàºàº§àºà»àºàºµàºàº¢àº¹à»"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"àºà»à»àº¡àºµà»àº«à»àºà»àºàºàº§à»àº²àº«à»àº²àº¡àº¥àº»àºàºàº§àºà»àºàºµàºàº¢àº¹à»"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à»àºàº°à»àºàº·à»àºà»àºàº»àº²àºàºŽàºàºªàºœàº."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à»àºàº°à»àºàº·à»àºàºàº±à»àºà»àºàº±àºàºªàº±à»àº. àºà»àº¥àºŽàºàº²àºàºà»àº§àºà»àºàº»à»àº²à»àºàºŽàºàºàº²àºàºàº·àºàºàºŽàºàºªàºœàºà»àº§à»."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à»àºàº°à»àºàº·à»àºàºàºŽàºàºªàºœàº. àºà»àº¥àºŽàºàº²àºàºà»àº§àºà»àºàº»à»àº²à»àºàºŽàºàºàº²àºàºàº·àºàºàºŽàºàºªàºœàºà»àº§à»."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັà»àºà»àºàº·àºàº"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"àºàº²àºàºàº§àºàºàºžàº¡àºªàºœàº %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àºàº²àºà»àº à»àº¥àº° àºàº²àºà»àºà»àºà»àºàº·àºàºàºàº°àº¡àºµàºªàºœàºàºàº±àº (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à»àºªà»àºàº²àºàºàº±à»àºàºà»àº²à»àºàº»à»àº²àºàºžàº"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àºàº°àº«àºàº²àºàºªàº°à»àº¥à»àºàºµàº¥àº°àºàº±àºàºªàºœàºà»àº¥à»àº§"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ຫàºà»à»àºªàº°à»àº¥à»àºàºµàº¥àº°àºàº±àºàºªàºœàºàº¥àº»àºà»àº¥à»àº§"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"àºàºŽàºàºªàºœàº %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"à»àºàº»àº²àºàºŽàºàºªàºœàº %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"àºàº³àº¥àº±àºàº«àºŒàºŽà»àº <xliff:g id="LABEL">%s</xliff:g> à»àº"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ສຜàºàºàº°àº«àºŒàºŽà»àºàºà»à»à»àº"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ສະຫຌັàºàº¥àº°àº«àº§à»àº²àºà»àºàº±àºàº«àºŒà»àº²àºªàºžàºà»àºàºà»àºà»à»àº²"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ສະຫຌັàºàº¥àº°àº«àº§à»àº²àºà»àºàº±àºàº«àºŒà»àº²àºªàºžàºà»àºàºàºàº±àºàº«àºŒàº±àº"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à»àºàºµàºàº¥àº²àºàºàº·à»à»àºàº±àº"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ສະà»àºàºà»àºàºà»à»àº²àº§àºœàº"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à»àºàºµàºàºàº²àºàºàº±à»àºàºà»àº²"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"à»àºàºµàºàºàº¹à»àºà»àº§àº"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"à»à»àº²àºà»àº¥àº±àºàº"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"à»àºàº»à»àº²àºªàº¹à»à»àºà»àºà»à»àº²àºà»àºà»àº§àºà»àºàº±àºàºàº±àºàºàºžàºàº±àºà»àºàº«àº² RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à»àºàº»à»àº²àºªàº¹à»à»àºà»àºà»à»àº²àºà»àºà»àº§àºà»àºàº±àºàºàº±àºàºàºžàºàº±àºà»àºàº«àº² LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ສະຫຌັàºàºàº²àºà»àºà»àºà»à»àº²àºà»à»àºà»àºàº±àºà»àºàº±àº¡àºà»"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à»àºàº¥àº°àº«àº§à»àº²àºà»àºà»àºà»à»àº²àºà»: à»àº«à»àºà»àºœàºàºàº²àºà»àºàº±àºà»àº¶à»àºà»àºàº±àºàºàºµàºà»àºàº±àºà»àº¶à»àº"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àºàº²àºàºà»àºàºàºà»à»àº¡àº¹àº"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ສະຫຌັàºà»àºàº±àºàºàº²àºªàº²àºàº±àºà»àº"</string>
@@ -791,7 +792,7 @@
<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="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>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àºà»àºàºàºà»àº²àºàº®àº¹àºàºàº·àºàºàº¥àº±àºàºàº¢àº¹à»"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àºà»àºàºàºà»àº²àºàº®àº¹àº à»àº¥àº° à»àº¡à»àºàº£à»àºàºàºàº·àºàºàº¥àº±àºàºàº¢àº¹à»"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à»àº¡à»àºàº£à»àºàºàºàº·àºàºàº¥àº±àºàºàº¢àº¹à»"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ຫà»àº²àº¡àº¥àº»àºàºàº§àº"</string>
<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>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index aae13c9..5f1c7bb 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"JÅ«sų IT administratorius uÅŸblokavo galimybÄ daryti ekrano kopijas."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Redaguoti"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Redaguoti ekrano kopijÄ
"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Bendrinti ekrano kopijÄ
"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Fiksuoti daugiau"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Praleisti ekrano kopijÄ
"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ŠÄ¯ įrenginį tvarko vienas iš tavo tÄvų. Jis gali perÅŸiÅ«rÄti ir tvarkyti informacijÄ
, pvz., tavo naudojamas programas, vietovÄ ir įrenginio naudojimo laikÄ
."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Atrakinta taikant „TrustAgent“"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Apsauga nuo vagystÄs\nÄ®renginys uÅŸrakintas, per daug bandymų atrakinti"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Įrenginys uşrakintas, nes atlikta per daug bandymų autentifikuoti"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Įrenginys uşrakintas\nAutentifikuoti nepavyko"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Garso nustatymai"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Taikyti aut. medij. subtitr."</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Nutildyti"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Perdavimas"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nepasiekiama, nes skambutis nutildytas"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nepasiekiama, nes įjungtas netrukdymo reşimas"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nepasiekiama, nes įjungtas netrukdymo reşimas"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Palieskite, kad įjungtumÄte garsÄ
."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Palieskite, kad nustatytumÄte vibravimÄ
. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumÄte. Gali bÅ«ti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Garsumo valdikliai: %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"SkambuÄiai ir pranešimai skambÄs (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ä®veskite išvesties nustatymus"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Garsumo šliauÅŸikliai išskleisti"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Garsumo šliauÅŸikliai sutraukti"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"nutildyti %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"įjungti garsÄ
%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"LeidÅŸiama „<xliff:g id="LABEL">%s</xliff:g>“"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Garsas bus leidÅŸiamas"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sistemos naudotojo sÄ
sajos derinimo priemonÄ"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Pereiti į priekį per naujausias programas"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Pereiti atgal per naujausias programas"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Atidaryti programų sÄ
rašÄ
"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Rodyti uÅŸduoÄių juostÄ
"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Atidaryti nustatymus"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Atidaryti PadÄjÄjÄ
"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"UÅŸrakinti ekranÄ
"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Eiti į išskaidyto ekrano reÅŸimÄ
su dabartine programa dešinÄje"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Eiti į išskaidyto ekrano reÅŸimÄ
su dabartine programa kairÄje"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Perjungti iš išskaidyto ekrano reÅŸimo į viso ekrano reÅŸimÄ
"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Išskaidyto ekrano reÅŸimu: pakeisti iš vienos programos į kitÄ
"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Įvestis"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Perjungti į kitÄ
kalbÄ
"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparatas uÅŸblokuotas"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparatas ir mikrofonas uÅŸblokuoti"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonas uÅŸblokuotas"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Netrukdymo reÅŸimas"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Aptikta naudotojo veikla"</string>
<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>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index abe280d..0be94f1 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"JÅ«su IT administrators ir bloÄ·Äjis ekrÄnuzÅÄmumu izveidi"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"RediÄ£Ät"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"RediÄ£Ät ekrÄnuzÅÄmumu"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"KopÄ«got ekrÄnuzÅÄmumu"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Tvert vairÄk"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"NerÄdÄ«t ekrÄnuzÅÄmumu"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Šo ierÄ«ci pÄrvalda viens no jÅ«su vecÄkiem. VecÄki var skatÄ«t un pÄrvaldÄ«t tÄdu informÄciju kÄ jÅ«su izmantotÄs lietotnes, atrašanÄs vieta un izmantošanas ilgums."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"BloÄ·Äšanu liedzis TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"AizsardzÄ«ba pret zÄdzÄ«bu\nIerÄ«ce bloÄ·Äta; pÄrÄk daudz atbloÄ·Äšanas mÄÄ£inÄjumu"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"SkaÅas iestatÄ«jumi"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Autom. paraksti multividei"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"IzslÄgt skaÅu"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Apraide"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nevar mainÄ«t, jo izslÄgts skaÅas signÄls"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nav pieejams, jo ir ieslÄgts reÅŸÄ«ms NetraucÄt"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nav pieejams, jo ir ieslÄgts reÅŸÄ«ms NetraucÄt"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Pieskarieties, lai ieslÄgtu skaÅu."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Pieskarieties, lai iestatÄ«tu uz vibrozvanu. Var tikt izslÄgti pieejamÄ«bas pakalpojumu signÄli."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslÄgtu skaÅu. Var tikt izslÄgti pieejamÄ«bas pakalpojumu signÄli."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrÄt"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s skaČuma vadīklas"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Zvani un paziÅojumi aktivizÄs zvana signÄlu (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"AtvÄrt izvades iestatÄ«jumus"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"SkaÄŒuma slÄ«dÅi izvÄrsti"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"SkaÄŒuma slÄ«dÅi sakÄŒauti"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"izslÄgt skaÅu straumei %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ieslÄgt skaÅu straumei %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> — atskaÅošana šeit:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio tiks atskaÅots šeit:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"SistÄmas saskarnes regulators"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"SecÄ«gi pÄrlÅ«kot nesen izmantotÄs lietotnes (pÄriet uz nÄkamo)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"SecÄ«gi pÄrlÅ«kot nesen izmantotÄs lietotnes (pÄriet uz iepriekšÄjo)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"AtvÄrt lietotÅu sarakstu"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"RÄdÄ«t uzdevumu joslu"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"AtvÄrt iestatÄ«jumus"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"AtvÄrt Asistentu"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"BloÄ·Ät ekrÄnu"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"PÄriet ekrÄna sadalÄ«šanas reÅŸÄ«mÄ ar pašreizÄjo lietotni pa labi"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"PÄriet ekrÄna sadalÄ«šanas reÅŸÄ«mÄ ar pašreizÄjo lietotni pa kreisi"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"PÄrslÄgties no ekrÄna sadalÄ«šanas reÅŸÄ«ma uz pilnekrÄna reÅŸÄ«mu"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"EkrÄna sadalÄ«šanas reÅŸÄ«mÄ: pÄrvietot lietotni no viena ekrÄna uz otru"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Ievade"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"PÄrslÄgt uz nÄkamo valodu"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloÄ·Äta"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloÄ·Äta"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloÄ·Äts"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ReÅŸÄ«ms “NetraucÄt”"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"KonstatÄta lietotÄja klÄtbÅ«tne"</string>
<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>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index c3690efd..3a84c9c 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ÐаÑÑвÑваÑеÑП ÑлОкО ПЎ екÑÐ°ÐœÐŸÑ Ðµ блПкОÑаМП ПЎ IT-аЎЌОМОÑÑÑаÑПÑПÑ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÐзЌеМО"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÐзЌеМеÑе Ñа ÑлОкаÑа ПЎ екÑаМПÑ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"СпПЎелеÑе ÑлОка ПЎ екÑаМПÑ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"СМОЌО пПвеÑе"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐÑÑÑлеÑе Ñа ÑлОкаÑа ПЎ екÑаМПÑ"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"РПЎОÑÐµÐ»ÐŸÑ ÑпÑавÑва ÑП ÑÑеЎПв. РПЎОÑÐµÐ»ÐŸÑ ÐŒÐŸÐ¶Ðµ Ўа пÑеглеЎÑва О ÑпÑавÑва ÑП пПЎаÑПÑОÑе, какП ÑÑП Ñе аплОкаÑООÑе ÑÑП гО кПÑОÑÑОÑ, ÑвПÑаÑа лПкаÑОÑа О вÑеЌеÑП пПЌОМаÑП Ма ÑÑеЎПÑ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"ÐÐÐ"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Се ПЎÑжÑва ПÑклÑÑеМ ПЎ TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐаÑÑОÑа ПЎ кÑажбО\nÐаклÑÑеМП. ÐÑÐµÐŒÐœÐŸÐ³Ñ ÐŸÐ±ÐžÐŽÐž за ПÑклÑÑÑваÑе."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"УÑÐµÐŽÐŸÑ Ñе заклÑÑО, пÑÐµÐŒÐœÐŸÐ³Ñ ÐŸÐ±ÐžÐŽÐž за авÑеМÑОкаÑОÑа"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"УÑÐµÐŽÐŸÑ Ðµ заклÑÑеМ\nÐвÑеМÑОкаÑОÑаÑа Ме ÑÑпеа"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐПÑÑавкО за звÑкПÑ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐвÑПЌаÑÑкО ÑОÑлПвО"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ÐÑклÑÑО звÑк"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ÐЌОÑÑваÑе"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÐеЎПÑÑапМП бОЎеÑÑО ÑвПМеÑеÑП е ОÑклÑÑеМП"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐеЎПÑÑапМП бОЎеÑÑО е вклÑÑеМП „Ðе вПзМеЌОÑÑваѓ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐеЎПÑÑапМП бОЎеÑÑО е вклÑÑеМП „Ðе вПзМеЌОÑÑваѓ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐПпÑеÑе за Ўа вклÑÑОÑе звÑк."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐПпÑеÑе за Ўа пПÑÑавОÑе Ма вОбÑаÑОО. ÐПжебО Ñе Ñе ОÑклÑÑО звÑÐºÐŸÑ ÐœÐ° ÑÑлÑгОÑе за ЎПÑÑапМПÑÑ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐПпÑеÑе за Ўа ОÑклÑÑОÑе звÑк. ÐПжебО Ñе Ñе ОÑклÑÑО звÑÐºÐŸÑ ÐœÐ° ÑÑлÑгОÑе за ЎПÑÑапМПÑÑ."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вОбÑаÑОО"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"ÐПМÑÑПлО Ма ÑаÑОМаÑа Ма звÑÐºÐŸÑ Ð·Ð° %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐПвОÑОÑе О ОзвеÑÑÑваÑаÑа Ñе ÑÐ²ÐŸÐœÐ°Ñ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÐМеÑеÑе гО пПÑÑавкОÑе за Озлез"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐОзгаÑОÑе за ÑаÑОМа Ма звÑÐºÐŸÑ Ñе пÑПÑОÑеМО"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐОзгаÑОÑе за ÑаÑОМа Ма звÑÐºÐŸÑ Ñе ÑПбÑаМО"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ОÑклÑÑÑваÑе звÑк Ма %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"вклÑÑÑваÑе звÑк Ма %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>: пÑÑÑеМП Ма"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑЎОПÑП Ñе Ñе пÑÑÑО Ма"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ÐЎапÑÐµÑ ÐœÐ° УРМа ÑОÑÑеЌПÑ"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐÑелОÑÑÑваÑÑе гО МеПЎаЌМеÑМОÑе аплОкаÑОО МаМапÑеЎ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐÑелОÑÑÑваÑÑе гО МеПЎаЌМеÑМОÑе аплОкаÑОО МаМазаЎ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐÑвПÑеÑе гП ÑпОÑÐŸÐºÐŸÑ ÑП аплОкаÑОО"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐÑОкажО „ÐеМÑа ÑП заЎаÑО“"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐÑвПÑеÑе „ÐПÑÑавкО“"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑвПÑеÑе гП „ÐПЌПÑМОкПѓ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐаклÑÑеМ екÑаМ"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐкÑОвОÑаÑÑе пПЎелеМ екÑаМ ÑП ÑекПвМаÑа аплОкаÑОÑа ЎеÑМП"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐкÑОвОÑаÑÑе пПЎелеМ екÑаМ ÑП ÑекПвМаÑа аплОкаÑОÑа левП"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐÑеÑÑлеÑе ПЎ пПЎелеМ екÑаМ вП Ñел екÑаМ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐÑО пПЎелеМ екÑаМ: пÑеÑÑлеÑе гО аплОк. ПЎ еЎМаÑа Ма ÐŽÑÑгаÑа ÑÑÑаМа"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐМеÑÑваÑе"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐÑеÑÑлеÑе Ма ÑÐ»ÐµÐŽÐœÐžÐŸÑ ÑазОк"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑаÑа е блПкОÑаМа"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑаÑа О ЌОкÑПÑÐŸÐœÐŸÑ Ñе блПкОÑаМО"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑÐŸÐœÐŸÑ Ðµ блПкОÑаМ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе вПзМеЌОÑÑваÑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 3637953..e2ee3ec 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àŽžàµàŽàµàްàµàµ»àŽ·àµàŽàµàŽàµàŽàµŸ àŽàŽàµàŽàµàŽàµàŽšàµàŽšàŽ€àµ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽàŽàŽ¿ àŽ
àŽ¡àµàŽ®àŽ¿àµ» àŽ¬àµà޲àµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"àŽàŽ¡àŽ¿àŽ±àµàŽ±àµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"àŽžàµàŽàµàްàµàµ»àŽ·àµàŽàµàŽàµ àŽàŽ¡àŽ¿àŽ±àµàŽ±àµ àŽàµàޝàµàޝàµàŽ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"àŽžàµàŽàµàްàµàµ»àŽ·àµàŽàµàŽàµ àŽªàŽàµàŽàŽ¿àŽàµàŽ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àŽàµàŽàµàŽ€àµœ àŽàµàŽ¯àŽŸàŽªàµàŽàµŒ àŽàµàޝàµàޝàµàŽ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àŽžàµàŽàµàްàµàµ»àŽ·àµàŽàµàŽàµ àŽ¡àŽ¿àŽžàµàŽ®àŽ¿àŽžàµ àŽàµàޝàµàޝàµàŽ"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àŽ àŽàŽªàŽàŽ°àŽ£àŽ àŽ®àŽŸàŽšàµàŽàµ àŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àµ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ°àŽàµàŽ·àŽ¿àŽ€àŽŸàŽµàŽŸàŽ£àµ. àŽšàŽ¿àŽàµàŽàµŸ àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµàŽšàµàŽš àŽàŽªàµàŽªàµàŽàµŸ, àŽžàµàŽàµàްàµàµ» àŽžàŽ®àŽ¯àŽ, àŽ²àµàŽàµàŽàµàŽ·àµ» àŽàŽšàµàŽšàŽ¿àŽµ àŽªàµà޲àµà޳àµà޳ àŽµàŽ¿àŽµàŽ°àŽàµàŽàµŸ àŽšàŽ¿àŽàµàŽà޳àµàŽàµ àŽ°àŽàµàŽ·àŽ¿àŽ€àŽŸàŽµàŽ¿àŽšàµ àŽàŽŸàŽ£àŽŸàŽšàµàŽ àŽšàŽ¿àŽ¯àŽšàµàŽ€àµàŽ°àŽ¿àŽàµàŽàŽŸàŽšàµàŽ®àŽŸàŽàµàŽ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent àŽàŽªàŽ¯àµàŽàŽ¿àŽàµàŽàµ àŽ
àµºàŽ²àµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ€àµ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àŽ®àµàŽ·àŽ£ àŽªàŽ°àŽ¿àŽ°àŽàµàŽ·\nàŽàŽªàŽàŽ°àŽ£àŽ àŽ²àµàŽàµàŽàµ àŽàµàޝàµàŽ€àµ, àŽšàŽ¿àŽ°àŽµàŽ§àŽ¿ àŽ
àµºàŽ²àµàŽàµàŽàµ àŽ¶àµàŽ°àŽ®àŽàµàŽàµŸ"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"àŽàŽªàŽàŽ°àŽ£àŽ àŽ²àµàŽàµàŽàµ àŽàµàޝàµàŽ€àµ, àŽšàŽ¿àŽ°àŽµàŽ§àŽ¿ àŽ€àŽµàŽ£ àŽªàŽ°àŽ¿àŽ¶àµàŽ§àŽ¿àŽàµàŽàµàŽ±àŽªàµàŽªàŽ¿àŽàµàŽàŽŸàµ» àŽ¶àµàŽ°àŽ®àŽ¿àŽàµàŽàµ"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"àŽàŽªàŽàŽ°àŽ£àŽ àŽ²àµàŽàµàŽàµ àŽàµàޝàµàŽ€àµ\nàŽªàŽ°àŽ¿àŽ¶àµàŽ§àŽ¿àŽàµàŽàµàŽ±àŽªàµàŽªàŽ¿àŽàµàŽàµœ àŽªàŽ°àŽŸàŽàŽ¯àŽªàµàŽªàµàŽàµàŽàµ"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àŽ¶àŽ¬àµàŽŠ àŽàµàŽ°àŽ®àµàŽàŽ°àŽ£àŽ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"àŽ®àµàŽ¡àŽ¿àŽ¯àŽ¯àµàŽàµàŽàµ àŽžàµàŽµàŽ¯àŽ®àµà޵ àŽàµàŽ¯àŽŸàŽªàµàŽ·àµ»"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àŽ®àµàޝàµàŽàµàŽàµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"àŽàŽŸàŽžàµàޱàµàŽ±àµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"àŽ±àŽ¿àŽàŽàµ àŽ®àµàޝàµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ€àŽ¿àŽšàŽŸàµœ àŽ²àŽàµàŽ¯àŽ®àŽ²àµà޲"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"àŽ¶àŽ²àµàŽ¯àŽªàµàŽªàµàŽàµàŽ€àµàŽ€àŽ°àµàŽ€àµ àŽàŽ£àŽŸàŽ¯àŽ€àŽ¿àŽšàŽŸàµœ àŽ²àŽàµàŽ¯àŽ®àŽ²àµà޲"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"àŽ¶àŽ²àµàŽ¯àŽªàµàŽªàµàŽàµàŽ€àµàŽ€àŽ°àµàŽ€àµ àŽàŽ£àŽŸàŽ¯àŽ€àŽ¿àŽšàŽŸàµœ àŽ²àŽàµàŽ¯àŽ®àŽ²àµà޲"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. àŽ
àµºàŽ®àµàޝàµàŽàµàŽàµàŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽàŽŸàŽªàµàŽªàµàŽàµàޝàµàޝàµàŽ."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. àŽµàµàެàµàްàµàޱàµàŽ±àŽ¿àŽ²àµàŽàµàŽàµ àŽžàŽàµàŽàŽ®àŽŸàŽàµàŽàµàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽàŽŸàŽªàµàŽªàµàŽàµàޝàµàޝàµàŽ. àŽàŽªàŽ¯àµàŽàŽžàŽ¹àŽŸàŽ¯àŽ¿ àŽžàµàŽµàŽšàŽàµàŽàµŸ àŽ®àµàޝàµàŽàµàŽàµàŽàµàޝàµàŽ¯àŽªàµàŽªàµàŽàµàŽàµàŽàµàŽàŽŸàŽ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. àŽ®àµàޝàµàŽàµàŽàµàŽàµàޝàµàޝàµàŽšàµàŽšàŽ€àŽ¿àŽšàµ àŽàŽŸàŽªàµàŽªàµàŽàµàޝàµàޝàµàŽ. àŽàŽªàŽ¯àµàŽàŽžàŽ¹àŽŸàŽ¯àŽ¿ àŽžàµàŽµàŽšàŽàµàŽàµŸ àŽ®àµàޝàµàŽàµàŽàµàŽàµàޝàµàŽ¯àŽªàµàŽªàµàŽàµàŽàµàŽàµàŽàŽŸàŽ."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"àŽµàµàެàµàްàµàޱàµàŽ±àµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s àŽ¶àŽ¬àµàŽŠ àŽšàŽ¿àŽ¯àŽšàµàŽ€àµàŽ°àŽ£àŽàµàŽàµŸ"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àŽàµà޳àµàŽà޳àµàŽ àŽ
àŽ±àŽ¿àŽ¯àŽ¿àŽªàµàŽªàµàŽà޳àµàŽ àŽ²àŽàŽ¿àŽàµàŽàµàŽ®àµàŽªàµàµŸ àŽ±àŽ¿àŽàŽàµ àŽàµàޝàµàޝàµàŽ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"àŽàŽàµàŽàµàŽªàµàŽàµàŽàµ àŽàµàŽ°àŽ®àµàŽàŽ°àŽ£àŽ àŽšàµœàŽàµàŽ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àŽµàµàŽ³àŽ¿àŽ¯àŽ àŽžàµà޲àµàŽ¡àŽ±àµàŽàµŸ àŽµàŽ¿àŽàŽžàŽ¿àŽªàµàŽªàŽ¿àŽàµàŽàµ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"àŽµàµàŽ³àŽ¿àŽ¯àŽ àŽžàµà޲àµàŽ¡àŽ±àµàŽàµŸ àŽàµàްàµàŽàµàŽàŽ¿"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s àŽ®àµàޝàµàŽàµàŽàµ àŽàµàޝàµàޝàµàŽ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s àŽ
àµºàŽ®àµàޝàµàŽàµàŽàµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> àŽàŽšàµàŽšàŽ€àŽ¿àµœ àŽªàµàŽ²àµ àŽàµàޝàµàޝàµàŽšàµàŽšàµ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"àŽàŽ¡àŽ¿àŽ¯àµ àŽªàµàŽ²àµ àŽàµàޝàµàޝàµàŽ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"àŽžàŽ¿àŽžàµàޱàµàŽ±àŽ UI àŽàµàޝàµàŽ£àµŒ"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"àŽžàŽ®àµàŽªàŽàŽŸàŽ²àŽ€àµàŽ€àµ àŽàŽªàµàŽªàµàŽàŽ³àŽ¿àŽ²àµàŽàµ àŽªàµàŽàµàŽ (àŽ®àµàŽšàµàŽšàµàŽàµàŽàµ)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"àŽžàŽ®àµàŽªàŽàŽŸàŽ²àŽ€àµàŽ€àµ àŽàŽªàµàŽªàµàŽàŽ³àŽ¿àŽ²àµàŽàµ àŽªàµàŽàµàŽ (àŽªàŽ¿àŽšàµàŽšàµàŽàµàŽàµ)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"àŽàŽªàµàŽªàµ àŽ²àŽ¿àŽžàµàޱàµàŽ±àµ àŽ€àµàޱàŽàµàŽàµàŽ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"àŽàŽŸàŽžàµàŽàµàŽ¬àŽŸàµŒ àŽàŽŸàŽ£àŽ¿àŽàµàŽàµàŽ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"àŽàµàŽ°àŽ®àµàŽàŽ°àŽ£àŽ àŽ€àµàޱàŽàµàŽàµàŽ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant àŽ€àµàޱàŽàµàŽàµàŽ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"àŽ²àµàŽàµàŽàµ àŽžàµàŽàµàްàµàµ»"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"àŽšàŽ¿àŽ²àŽµàŽ¿àŽ²àµ àŽàŽªàµàŽªàµ àŽµàŽ²àŽ€àµàŽµàŽ¶àŽ€àµàŽ€àµ àŽµàŽ°àµàŽšàµàŽš àŽ°àµàŽ€àŽ¿àŽ¯àŽ¿àµœ àŽžàµàŽàµàްàµàµ» àŽµàŽ¿àŽàŽàŽš àŽ®àµàŽ¡àŽ¿àµœ àŽàŽàŽàµàŽàµàŽ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"àŽšàŽ¿àŽ²àŽµàŽ¿àŽ²àµ àŽàŽªàµàŽªàµ àŽàŽàŽ€àµàŽµàŽ¶àŽ€àµàŽ€àµ àŽµàŽ°àµàŽšàµàŽš àŽ°àµàŽ€àŽ¿àŽ¯àŽ¿àµœ àŽžàµàŽàµàްàµàµ» àŽµàŽ¿àŽàŽàŽš àŽ®àµàŽ¡àŽ¿àµœ àŽàŽàŽàµàŽàµàŽ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"àŽžàµàŽàµàްàµàµ» àŽµàŽ¿àŽàŽàŽš àŽ®àµàŽ¡àŽ¿àµœ àŽšàŽ¿àŽšàµàŽšàµ àŽªàµàµŒàŽ£àµàŽ£ àŽžàµàŽàµàްàµàŽšàŽ¿àŽ²àµàŽàµàŽàµ àŽ®àŽŸàŽ±àµàŽ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"àŽžàµàŽàµàްàµàµ» àŽµàŽ¿àŽàŽàŽš àŽ®àµàŽ¡àŽ¿àµœ: àŽàŽ°àµ àŽàŽªàµàŽªàŽ¿àµœ àŽšàŽ¿àŽšàµàŽšàµ àŽ®àŽ±àµàޱàµàŽšàµàŽšàŽ¿àŽ²àµàŽàµàŽàµ àŽ®àŽŸàŽ±àµàŽ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àŽàµ»àŽªàµàŽàµàŽàµ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"àŽ
àŽàµàŽ€àµàŽ€ àŽàŽŸàŽ·àŽ¯àŽ¿àŽ²àµàŽàµàŽàµ àŽ®àŽŸàŽ±àµàŽ"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àŽàµàŽ¯àŽŸàŽ®àŽ± àŽ¬àµà޲àµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àŽàµàŽ¯àŽŸàŽ®àŽ±àŽ¯àµàŽ àŽ®àµàŽàµàްàµàŽ«àµàŽ£àµàŽ àŽ¬àµà޲àµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"àŽ®àµàŽàµàްàµàŽ«àµàµº àŽ¬àµà޲àµàŽàµàŽàµ àŽàµàޝàµàŽ€àŽ¿àŽ°àŽ¿àŽàµàŽàµàŽšàµàŽšàµ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àŽ¶àŽ²àµàŽ¯àŽªàµàŽªàµàŽàµàŽ€àµàŽ€àŽ°àµàŽ€àµ"</string>
<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>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 26c5027..84ff51b 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Ð¢Ð°ÐœÑ IT аЎЌОМ ÐŽÑлгÑÑОйМ агÑОМ аваÑ
Ñг блПклПÑПМ байМа"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÐаÑаÑ
"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÐÑлгÑÑОйМ агÑМÑг заÑаÑ
"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÐÑлгÑÑОйМ агÑМÑг Ñ
ÑваалÑаÑ
"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÐÑ
Ойг багÑааÑаМ зÑÑаг аваÑ
"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐÑлгÑÑОйМ агÑМÑг Ñ
ааÑ
"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÐÐœÑ ÑÓ©Ñ
Ó©Ó©ÑөЌжОйг ÑÐ°ÐœÑ ÑÑÑг ÑÑ
ÑЎОÑЎЎаг. Ð¢Ð°ÐœÑ ÑÑÑг ÑÑ
ÑÐ°ÐœÑ Ñ
ÑÑÑглÑÐŽÑг апп, байÑÑОл, ÐŽÑлгÑÑОйМ Ñаг зÑÑÑг ÐŒÑÐŽÑÑллОйг Ñ
аÑж, ÑЎОÑЎаÑ
бПлПЌжÑПй."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent-Ñ ÑүгжÑÑгүй байлгаÑаМ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ð¥ÑлгайМ Ñ
аЌгаалалÑ\nТөÑ
Ó©Ó©ÑөЌж ÑүгжОгЎÑÑМ, ÑүгжÑÑг ÑайлаÑ
Ñ
ÑÑ ÐŸÐ»ÐŸÐœ ПÑПлЎлПгП"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐÑÑÐœÑ ÑПÑ
ОÑгПП"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐеЎОаЎ авÑПЌаÑÐ°Ð°Ñ ÑÐ°Ð¹Ð»Ð±Ð°Ñ ÐœÑÐŒÑÑ
"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ХааÑ
"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ÐаЌжÑÑлаÑ
"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ХПМÑ
ÐœÑ ÐŽÑÑг Ñ
ааÑаМ ÑÑл бПлПЌжгүй"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐÒ¯Ò¯ ÑааЎ бПл аÑаалÑÑай ÑÑл бПлПЌжгүй"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐÒ¯Ò¯ ÑааЎ бПл аÑаалÑÑай ÑÑл бПлПЌжгүй"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐÑÑг ÐœÑ ÐœÑÑÑ
ОйМ ÑÑлЎ ÑПвÑОМП ÑÑ."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ЧОÑОÑгÑÑМЎ ÑПÑ
ОÑÑÑлаÑ
ÑМ ÑÑлЎ ÑПвÑОМП ÑÑ. Ð¥Ò¯ÑÑÑÑЌжОйМ үйлÑОлгÑÑМОй ÐŽÑÑг Ñ
ааÑаМ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐÑÑг ÐœÑ Ñ
ааÑ
ÑМ ÑÑлЎ ÑПвÑОМП ÑÑ. Ð¥Ò¯ÑÑÑÑЌжОйМ үйлÑОлгÑÑМОй ÐŽÑÑг Ñ
ааÑаМ."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÑОÑÑÑÑ
"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ÑүвÑМОй Ñ
ÑМалÑ"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐÑÑЎлага бПлПМ ÐŒÑÐŽÑгЎлОйМ Ñ
ПМÑ
ÐŽÑÑгаÑМа (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÐÑПлÑÑМ ÑПÑ
ОÑгППг ПÑÑÑлаÑ
"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐÑÑÐœÑ ÑүвÑМОй гÑлÑÑÑлагÑÐŽÑг ÐŽÑлгÑÑÑМ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐÑÑÐœÑ ÑүвÑМОй гÑлÑÑÑлагÑÐŽÑг Ñ
ÑÑааÑаМ"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s-М ÐŽÑÑг Ñ
ааÑ
"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s-М ÐŽÑÑг МÑÑÑ
"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ÐŽÑÑÑ ÑПглÑÑлж байМа"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑЎОПг ЎаÑааÑ
аЎ ÑПглÑÑлМа"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"СОÑÑеЌОйМ UI ТПÑ
ОÑÑÑлагÑ"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"СаÑÑ
ÐœÑ Ð°Ð¿Ð¿ÑÑÐŽÐ°Ð°Ñ ÑÑÐ°Ð³Ñ Ð³Ò¯Ð¹Ð»Ð³ÑÑ
"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"СаÑÑ
ÐœÑ Ð°Ð¿Ð¿ÑÑÐŽÐ°Ð°Ñ Ð°ÑÐ°Ð³Ñ Ð³Ò¯Ð¹Ð»Ð³ÑÑ
"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐппÑÑÐŽÑМ жагÑаалÑÑг МÑÑÑ
"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐжлÑМ Ñ
ÑÑгОйг Ñ
аÑÑÑлаÑ
"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ТПÑ
ОÑгППг МÑÑÑ
"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ТÑÑлаÑ
Ñг МÑÑÑ
"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ТүгжÑÑÑÑй ÐŽÑлгÑÑ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐЎППгОйМ Ð°Ð¿Ð¿Ð°Ð°Ñ Ð±Ð°ÑÑÑМ Ð³Ð°Ñ ÑалЎ ÐŽÑлгÑÑ Ñ
ÑвааÑ
аЎ ПÑПÑ
"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐЎППгОйМ Ð°Ð¿Ð¿Ð°Ð°Ñ Ð·Ò¯Ò¯Ðœ Ð³Ð°Ñ ÑалЎ ÐŽÑлгÑÑ Ñ
ÑвааÑ
аЎ ПÑПÑ
"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐÑлгÑÑ Ñ
ÑвааÑ
Ð°Ð°Ñ Ð±Ò¯ÑÑМ ÐŽÑлгÑÑ ÑÒ¯Ò¯ ÑÑлгÑÑ
"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐÑлгÑÑ Ñ
ÑвааÑ
үеÑÑ: аппÑг МÑгÑÑÑ ÐœÓ©Ð³Ó©Ó©Ð³Ó©Ó©Ñ ÑПлОÑ
"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐÑПлÑ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐаÑаагОйМ Ñ
Ñл ÑÒ¯Ò¯ ÑÑлгÑÑ
"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑÑг блПклПÑПМ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐÐ°ÐŒÐµÑ Ð±ÐŸÐ»ÐŸÐœ ЌОкÑПÑПМÑг блПклПÑПМ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑПМÑг блПклПÑПМ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ÐÒ¯Ò¯ ÑааЎ бПл"</string>
<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>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 11f42af..7372368 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"à€€à¥à€®à€à¥à€¯à€Ÿ à€à€¯à€à¥ à¥²à€¡à€®à€¿à€šà€šà¥ à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€à¥à€£à¥ à€¬à¥à€²à¥à€ à€à¥à€²à¥ à€à€¹à¥"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à€žà€à€ªà€Ÿà€Šà€¿à€€ à€à€°à€Ÿ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€žà€à€ªà€Ÿà€Šà€¿à€€ à€à€°à€Ÿ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€¶à¥à€
à€° à€à€°à€Ÿ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à€à€£à€à¥ à€à¥à€·à¥à€à¥ à€à¥
à€ªà¥à€à€° à€à€°à€Ÿ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"à€žà¥à€à¥à€°à¥à€šà€¶à¥à€ à€¡à€¿à€žà€®à€¿à€ž à€à€°à€Ÿ"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"à€²à¥à€ à€žà¥à€à¥à€°à¥à€šà€µà€° à€à¥à€£à€€à¥à€¯à€Ÿà€¹à¥ à€µà€¿à€à¥à€à€²à€Ÿ à€
à€šà¥à€®à€€à¥ à€Šà¥à€¯à€Ÿà€¯à€à¥ à€à€¹à¥ à€à€Ÿ?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"à€žà¥à€à€¿à€à€à¥à€ à€à€à€¡à€Ÿ"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"à€µà€°à¥à€ à¥²à€ªà¥à€ž à€ªà¥à€šà¥à€¹à€Ÿ à€žà¥à€°à¥ à€à€°à€Ÿà€¯à€à¥?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"à€ªà¥à€šà¥à€¹à€Ÿ à€žà¥à€°à¥ à€à€°à€Ÿ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"à€µà€Ÿà€ªà€°à€à€°à¥à€€à€Ÿ à€žà¥à€µà€¿à€ à€à€°à€Ÿ"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à€¹à¥ à€¡à€¿à€µà¥à€¹à€Ÿà€à€ž à€€à¥à€®à€à¥à€¯à€Ÿ à€ªà€Ÿà€²à€à€Ÿà€šà¥ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à¥à€²à¥ à€à€¹à¥. à€€à¥à€®à¥à€¹à¥ à€µà€Ÿà€ªà€°à€€ à€
à€žà€²à¥à€²à¥ à¥²à€ªà¥à€ž, à€€à¥à€®à€à¥ à€žà¥à€¥à€Ÿà€š à€à€£à€¿ à€€à¥à€®à€à€Ÿ à€žà¥à€à¥à€°à¥à€š à€µà¥à€³ à€¯à€Ÿà€à€žà€Ÿà€°à€à¥ à€®à€Ÿà€¹à€¿à€€à¥ à€€à¥à€®à€à¥ à€ªà€Ÿà€²à€ à€ªà€Ÿà€¹à¥ à€à€£à€¿ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€¿à€€ à€à€°à¥ à€¶à€à€€à€Ÿà€€."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à€šà¥ à€
à€šà€²à¥à€ à€ à¥à€µà€²à¥"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à€à¥à€°à¥à€ªà€Ÿà€žà¥à€š à€žà€à€°à€à¥à€·à€£\nà€¡à€¿à€µà¥à€¹à€Ÿà€à€ž à€²à¥à€ à€à¥à€²à¥, à€
à€šà€²à¥à€ à€à€°à€Ÿà€¯à€à¥ à€à¥à€ª à€ªà¥à€°à€¯à€€à¥à€š"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à€à€µà€Ÿà€ à€žà¥à€à€¿à€à€à¥à€"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à€®à¥à€¡à€¿à€¯à€Ÿà€²à€Ÿ à€à€ªà¥à€à€ª à€žà€¬à€à€Ÿà€¯à€à€² à€Šà¥à€¯à€Ÿ"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à€®à¥à€¯à¥à€ à€à€°à€Ÿ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à€à€Ÿà€žà¥à€ à€à€°à€Ÿ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à€°à€¿à€à€ à€®à¥à€¯à¥à€ à€à¥à€²à¥à€¯à€Ÿà€®à¥à€³à¥ à€à€ªà€²à€¬à¥à€§ à€šà€Ÿà€¹à¥"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à€µà¥à€¯à€€à¥à€¯à€¯ à€à€£à¥ à€šà€à€Ÿ à€¹à¥ à€žà¥à€°à¥ à€
à€žà€²à¥à€¯à€Ÿà€®à¥à€³à¥ à€à€ªà€²à€¬à¥à€§ à€šà€Ÿà€¹à¥"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à€µà¥à€¯à€€à¥à€¯à€¯ à€à€£à¥ à€šà€à€Ÿ à€¹à¥ à€žà¥à€°à¥ à€
à€žà€²à¥à€¯à€Ÿà€®à¥à€³à¥ à€à€ªà€²à€¬à¥à€§ à€šà€Ÿà€¹à¥"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à€
à€šà€®à¥à€¯à¥à€ à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à¥
à€ª à€à€°à€Ÿ."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à€µà¥à€¹à€Ÿà€¯à€¬à¥à€°à¥à€ à€žà¥à€ à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à¥
à€ª à€à€°à€Ÿ. à€ªà¥à€°à€µà¥à€¶à€¯à¥à€à¥à€¯à€€à€Ÿ à€žà¥à€µà€Ÿ à€®à¥à€¯à¥à€ à€à¥à€²à¥à€¯à€Ÿ à€à€Ÿà€ à€¶à€à€€à€Ÿà€€."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à€®à¥à€¯à¥à€ à€à€°à€£à¥à€¯à€Ÿà€žà€Ÿà€ ॠà€à¥
à€ª à€à€°à€Ÿ. à€ªà¥à€°à€µà¥à€¶à€à¥à€·à€®à€€à€Ÿ à€žà¥à€µà€Ÿ à€®à¥à€¯à¥à€ à€à¥à€²à¥à€¯à€Ÿ à€à€Ÿà€ à€¶à€à€€à€Ÿà€€."</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à€µà¥à€¹à€Ÿà€¯à€¬à¥à€°à¥à€ à€à€°à€Ÿ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s à€µà¥à€¹à¥à€²à¥à€¯à¥à€® à€šà€¿à€¯à€à€€à¥à€°à€£"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à€à¥à€² à€à€£à€¿ à€žà¥à€à€šà€Ÿ à€µà€Ÿà€à€€à¥à€² (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à€à€à€à€ªà¥à€ à€žà¥à€à€¿à€à€à¥à€ à€à€à€à€° à€à€°à€Ÿ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à€µà¥à€¹à¥à€²à¥à€¯à¥à€® à€žà¥à€²à€Ÿà€¯à€¡à€° à€µà€¿à€žà¥à€€à€Ÿà€°à€¿à€€ à€à¥à€²à¥ à€à€¹à¥à€€"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à€µà¥à€¹à¥à€²à¥à€¯à¥à€® à€žà¥à€²à€Ÿà€¯à€¡à€° à€à¥à€²à¥
à€ªà¥à€ž à€à¥à€²à¥ à€à€¹à¥à€€"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s à€®à¥à€¯à¥à€ à€à€°à€Ÿ"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à€
à€šà€®à¥à€¯à¥à€ à€à€°à€Ÿ"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> à€µà€° à€ªà¥à€²à¥ à€à€°à€€ à€à€¹à¥"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à€¯à€Ÿà€µà€° à€à€¡à€¿à€ à€ªà¥à€²à¥ à€¹à¥à€à€²"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"à€žà€¿à€žà¥à€à€® UI à€à¥à€¯à¥à€šà€°"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à€
à€²à¥à€à€¡à¥à€² à¥²à€ªà¥à€žà€µà€°à¥à€š à€ªà¥à€¢à¥ à€à€Ÿ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à€
à€²à¥à€à€¡à¥à€² à¥²à€ªà¥à€žà€µà€°à¥à€š à€®à€Ÿà€à¥ à€à€Ÿ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à¥²à€ªà¥à€žà€à¥ à€žà¥à€à¥ à€à€à€¡à€Ÿ"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à€à€Ÿà€žà¥à€à€¬à€Ÿà€° à€Šà€Ÿà€à€µà€Ÿ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à€žà¥à€à€¿à€à€à¥à€ à€à€à€¡à€Ÿ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant à€à€à€¡à€Ÿ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"à€²à¥à€ à€žà¥à€à¥à€°à¥à€š"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"à€à€à€µà¥à€¯à€Ÿ à€¬à€Ÿà€à¥à€²à€Ÿ à€žà€§à¥à€¯à€Ÿà€à¥ à€
à¥
à€ª à€
à€žà€²à¥à€²à¥à€¯à€Ÿ à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€šà€µà€° à€à€Ÿ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à€¡à€Ÿà€µà¥à€¯à€Ÿ à€¬à€Ÿà€à¥à€²à€Ÿ à€žà€§à¥à€¯à€Ÿà€à¥ à€
à¥
à€ª à€
à€žà€²à¥à€²à¥à€¯à€Ÿ à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€šà€µà€° à€à€Ÿ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€šà€µà€°à¥à€š à€«à¥à€² à€žà¥à€à¥à€°à¥à€šà€µà€° à€žà¥à€µà€¿à€ à€à€°à€Ÿ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à¥à€šà€Šà€°à€®à¥à€¯à€Ÿà€š: à€à€ à€
à¥
à€ª à€Šà¥à€žà€±à¥à€¯à€Ÿ à€
à¥
à€ªà€šà¥ à€¬à€Šà€²à€Ÿ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à€à€šà€ªà¥à€"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à€ªà¥à€¢à¥à€² à€à€Ÿà€·à¥à€µà€° à€žà¥à€µà€¿à€ à€à€°à€Ÿ"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à€à¥
à€®à¥à€°à€Ÿ à€¬à¥à€²à¥à€ à€à¥à€²à€Ÿ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à€à¥
à€®à¥à€°à€Ÿ à€à€£à€¿ à€®à€Ÿà€¯à€à¥à€°à¥à€«à¥à€š à€¬à¥à€²à¥à€ à€à¥à€²à¥ à€à€¹à¥à€€"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à€®à€Ÿà€¯à€à¥à€°à¥à€«à¥à€š à€¬à¥à€²à¥à€ à€à¥à€²à€Ÿ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"à€µà¥à€¯à€€à¥à€¯à€¯ à€à€£à¥ à€šà€à€Ÿ"</string>
<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>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e7e3057..3839df3 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Pengambilan tangkapan skrin disekat oleh pentadbir IT anda"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edit tangkapan skrin"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Kongsi tangkapan skrin"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Tangkap imej lagi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ketepikan tangkapan skrin"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Peranti ini diurus oleh ibu bapa anda. Ibu bapa anda dapat melihat dan mengurus maklumat seperti apl yang anda gunakan, lokasi dan masa skrin anda."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Dibiarkan tidak berkunci oleh TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Perlindungan kecurian\nDikunci, banyak percubaan membuka kunci"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Tetapan bunyi"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sari kata media automatik"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Redam"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Hantar"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia kerana deringan diredam"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Tidak tersedia kerana Jangan Ganggu dihidupkan"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Tidak tersedia kerana Jangan Ganggu dihidupkan"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketik untuk menyahredam."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s kawalan kelantangan"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Panggilan dan pemberitahuan akan berdering (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Masukkan tetapan output"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Peluncur kelantangan dikembangkan"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Peluncur kelantangan dikuncupkan"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"redamkan %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"nyahredamkan %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Memainkan <xliff:g id="LABEL">%s</xliff:g> pada"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio dimainkan pada"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Penala UI Sistem"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Kitar ke hadapan menerusi apl terbaharu"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Kitar ke belakang menerusi apl terbaharu"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Buka senarai apl"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Tunjukkan bar tugas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Buka tetapan"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buka Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci skrin"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Masuk skrin pisah dengan apl semasa pada sisi kanan"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Masuk skrin pisah dengan apl semasa pada sisi kiri"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Beralih daripada skrin pisah kepada skrin penuh"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Semasa skrin pisah: gantikan apl daripada satu apl kepada apl lain"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Beralih kepada bahasa seterusnya"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera disekat"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon disekat"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon disekat"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Jangan ganggu"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna dikesan"</string>
<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>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 109d674..dd3e3a7 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"áááºáá¬ážááŒááºáá¬ááºáá¯á¶ááá¯ááºááŒááºážááᯠááá·áº IT á
á®áá¶ááá·áºááœá²áá°á ááááºáá¬ážáááº"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"áááºážááŒááºáááº"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"áááºáá¬ážááŒááºáá¬ááºáá¯á¶ááᯠáááºážááŒááºáááº"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"áááºáá¬ážááŒááºáá¬ááºáá¯á¶ááᯠáá»áŸáá±ááá¯ááºáááº"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"áá±á¬ááºááẠááá¯ááºáá°ážáááº"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"áááºáá¬ážááŒááºáá¬ááºáá¯á¶ááᯠáááºáááº"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"á€á
ááºáá
á¹á
ááºážááᯠááá·áºáááá á
á®áá¶ááá·áºááœá²áááºá ááá·áºáááá áááºáá¯á¶ážáá±á¬á¡ááºááºáá»á¬ážá áááºááááºáá±áá¬ááŸáá·áº á¡áá¯á¶ážááŒá¯áá»ááẠáá²á·ááá¯á·áá±á¬ á¡áá»ááºá¡áááºáá»á¬ážááᯠááŒááºááá¯ááºááŒá®áž á
á®áá¶ááá·áºááœá²ááá¯ááºáááºá"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ááŒáá·áº áááºááœáá·áºáá¬ážáááº"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"áá°ááá¯ážáá¬ááœááºáá±áž\ná
ááºáá±á¬á·ááºáá»á á¡ááŒáááºáá»á¬ážá
áœá¬ááœáá·áºáááºááŒáá¯ážá
á¬ážáá¬áž"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>á <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"á¡áá¶áááºáááºáá»á¬áž"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"á¡ááá¯á¡áá»á±á¬áẠá
á¬áááºážááá¯ážáááº"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"á¡áá¶ááááºáááº"</string>
<string name="media_device_cast" msgid="4786241789687569892">"áá¬á
áºáá¯ááºáááº"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"áá¯ááºážááŒááºáá¶ááááºáá¬ážáááŒáá·áº ááááá¯ááºáá«"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"‘áááŸá±á¬áá·áºááŸááºá’ ááœáá·áºáá¬ážáá±á¬ááŒá±á¬áá·áº ááááá¯ááºáá«"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"‘áááŸá±á¬áá·áºááŸááºá’ ááœáá·áºáá¬ážáá±á¬ááŒá±á¬áá·áº ááááá¯ááºáá«"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sá á¡áá¶ááŒááºááœáá·áºááẠááá¯á·áá«á"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sá áá¯ááºáá«ááŸá¯ááᯠáááºááŸááºááẠááá¯á·áá«á á¡áá»á¬ážáá¯á¶ážááá¯ááºááŸá¯ áááºáá±á¬ááºááŸá¯áá»á¬ážááᯠá¡áá¶ááááºáá¬ážááá¯ááºáá«áááºá"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sá á¡áá¶ááááºááẠááá¯á·áá«á á¡áá»á¬ážáá¯á¶ážááá¯ááºááŸá¯ áááºáá±á¬ááºááŸá¯áá»á¬ážááᯠá¡áá¶ááááºáá¬ážááá¯ááºáá«áááºá"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"áá¯ááºáá«ááŸá¯"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s á¡áá¶á¡ááá¯ážá¡áá»áŸá±á¬á· ááá¯ááºáá»á¬áž"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"áá±á«áºááá¯ááŸá¯áá»á¬ážááŸáá·áº á¡ááŒá±á¬ááºážááŒá¬ážáá»ááºáá»á¬ážá¡ááœáẠá¡áá¶ááŒááºááŸá¯ááºáž (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>) ááŒá
áºáááº"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"á¡ááœáẠáááºáááºáá»á¬áž ááá·áºáááº"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"á¡áá¶á¡ááá¯ážá¡áá»áẠááœáŸá±á·áá¯á¶ážáá»á¬áž ááá¯ááŒáá¬ážáááº"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"á¡áá¶á¡ááá¯ážá¡áá»áẠááœáŸá±á·áá¯á¶ážáá»á¬áž áá»áŸá±á¬á·ááŒáá¬ážáááº"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s á¡áá¶ááááºáááº"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s á¡áá¶ááŒááºááœáá·áºáááº"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ááᯠááœáá·áºáá±áááº"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"á¡á±á¬ááºááœááºá¡áá¶ááœáá·áºáááº"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"á
áá
ẠUI áááºážá
ááº"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"áááŒá¬áá±ážáá®á á¡ááºááºáá»á¬ážááᯠá¡ááá¯ááºážáá¯á¶ááŸá±á·ááá¯á·ááŸáá·áºáááº"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"áááŒá¬áá±ážáá®á á¡ááºááºáá»á¬ážááᯠá¡ááá¯ááºážáá¯á¶áá±á¬ááºááŒááºááŸáá·áºáááº"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"á¡ááºááºááŒáááŸá¯ ááœáá·áºáááº"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Taskbar ááŒáá«"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"áááºáááºáá»á¬áž ááœáá·áºáááº"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ááœáá·áºáááº"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"áá±á¬á·ááºáá»ááºááŸá¬ááŒááº"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"áááºááŸáá¡ááºááºááᯠáá»ááºááŸá¬ááŒáẠááœá²áááŒáááŸá¯á áá¬áááºááœááºááá·áºáááº"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"áááºááŸáá¡ááºááºááᯠáá»ááºááŸá¬ááŒáẠááœá²áááŒáááŸá¯á áááºáááºááœááºááá·áºáááº"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"áá»ááºááŸá¬ááŒáẠááœá²áááŒáááŸá¯á០áá»ááºááŸá¬ááŒááºá¡ááŒáá·áºááá¯á· ááŒá±á¬ááºážáááº"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"áá»ááºááŸá¬ááŒáẠááœá²áááŒáá
ááº- á¡ááºááºáá
áºáá¯ááᯠáá±á¬ááºáá
áºáá¯ááŸáá·áº á¡á
á¬ážááá¯ážáááº"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"á
á¬ááá¯ááºááŒááºáž"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"áá±á¬ááºáá¬áá¬á
áá¬ážááá¯á· ááŒá±á¬ááºážáááº"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"áááºááá¬ááᯠááááºáá¬ážáááº"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"áááºááá¬ááŸáá·áº ááá¯ááºáááá¯áá¯ááºážááᯠááááºáá¬ážáááº"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ááá¯ááºáááá¯áá¯ááºážááᯠááááºáá¬ážáááº"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"áááŸá±á¬áá·áºááŸááºá"</string>
<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>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 57b40b9..23c3f45 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Funksjonen for å ta skjermdumper er blokkert av IT-administratoren din"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger skjermdumpen"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Del skjermdumpen"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Utvidet skjermdump"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Avvis skjermdumpen"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Denne enheten administreres av forelderen din. Forelderen din kan se og administrere informasjon, for eksempel appene du bruker, posisjonen din og skjermtiden din."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes opplåst med TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Tyveribeskyttelse\nEnheten er låst – mange opplåsingsforsøk"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Lydinnstillinger"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatisk medieteksting"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ignorer"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Utilgjengelig fordi ringelyden er kuttet"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Utilgjengelig fordi «Ikke forstyrr» er på"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Utilgjengelig fordi «Ikke forstyrr» er på"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trykk for å slå på lyden."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s volumkontroller"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Anrop og varsler ringer (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Angi utdatainnstillinger"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Glidebrytere for volum er skjult"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Glidebrytere for volum er skjult"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"kutt lyden til %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå på lyden til %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Spiller av <xliff:g id="LABEL">%s</xliff:g> på"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Lyden spilles av på"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Gå forover gjennom nylige apper"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Gå bakover gjennom nylige apper"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Åpne applisten"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Vis oppgavelinje"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Åpne innstillingene"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Åpne assistenten"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Låseskjerm"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Åpne delt skjerm med den aktive appen til høyre"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Åpne delt skjerm med den aktive appen til venstre"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Bytt fra delt skjerm til fullskjerm"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"I delt skjerm: Bytt ut en app"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Skrivespråk"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Bytt til neste språk"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokkert"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameraet og mikrofonen er blokkert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokkert"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ikke forstyrr"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Det er registrert at brukeren er til stede"</string>
<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>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b682e44..23543c2 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"à€€à€ªà€Ÿà€à€à€à¥ IT à€à€¡à¥à€®à€¿à€šà€²à¥ à€žà¥à€à¥à€°à€¿à€šà€žà€ à€²à€¿à€šà¥ à€žà¥à€µà€¿à€§à€Ÿ à€¬à¥à€²à€ à€à€°à¥à€šà¥à€à€à€à¥ à€"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à€žà€®à¥à€ªà€Ÿà€Šà€š à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à€žà¥à€à¥à€°à€¿à€šà€žà€ à€žà€®à¥à€ªà€Ÿà€Šà€š à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à€žà¥à€à¥à€°à€¿à€šà€žà€ à€žà¥à€¯à€° à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à€
à€šà¥à€¯ à€à¥à€°à€Ÿà€¹à€°à¥ à€à€¿à€à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"à€žà¥à€à¥à€°à€¿à€šà€žà€ à€¹à€à€Ÿà€à€šà¥à€¹à¥à€žà¥"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à€¯à¥ à€¡à€¿à€à€Ÿà€à€ž à€€à€ªà€Ÿà€à€à€à€Ÿ à€
à€à€¿à€à€Ÿà€µà€ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€š à€à€°à¥à€šà¥à€¹à¥à€šà¥à€à¥€ à€€à€ªà€Ÿà€à€à€à€Ÿ à€
à€à€¿à€à€Ÿà€µà€ à€€à€ªà€Ÿà€à€à€²à¥ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥ à€à€ª, à€€à€ªà€Ÿà€à€à€à¥ à€žà¥à€¥à€Ÿà€š à€° à€€à€ªà€Ÿà€à€à€²à¥ à€¯à€šà¥à€€à¥à€° à€à€²à€Ÿà€à€° à€¬à€¿à€€à€Ÿà€à€šà¥ à€žà€®à€¯ à€à€žà¥à€€à€Ÿ à€à€Ÿà€šà€à€Ÿà€°à¥ à€¹à¥à€°à¥à€š à€€à€¥à€Ÿ à€µà¥à€¯à€µà€žà¥à€¥à€Ÿà€ªà€š à€à€°à¥à€š à€žà€à¥à€šà¥à€¹à¥à€šà¥à€à¥€"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à€²à¥ à€à¥à€²à€Ÿ à€°à€Ÿà€à¥à€à¥"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à€à¥à€°à¥à€¬à€Ÿà€ à€žà¥à€°à€à¥à€·à€Ÿ\nà€¡à€¿à€à€Ÿà€à€ž à€²à€ à€à€°à€¿à€à€à¥ à€, à€
à€€à¥à€¯à€§à€¿à€ à€§à¥à€°à¥ à€ªà€à€ à€
à€šà€²à€ à€à€°à¥à€šà¥ à€ªà¥à€°à€¯à€Ÿà€ž à€à€°à€¿à€à€à¥ à€"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à€§à¥à€µà€šà€¿à€žà€®à¥à€¬à€šà¥à€§à¥ à€žà¥à€à€¿à€à€¹à€°à¥"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à€®à€¿à€¡à€¿à€¯à€Ÿà€à¥ à€žà¥à€µà€€: à€à¥à€¯à€Ÿà€ªà¥à€žà€š à€¬à€šà€Ÿà€à€šà¥à€¹à¥à€žà¥"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à€®à¥à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à€à€Ÿà€žà¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à€¡à€¿à€à€Ÿà€à€ž à€®à¥à€¯à¥à€ à€à€°à€¿à€à€à€Ÿà€²à¥ à€¯à¥ à€žà¥à€µà€¿à€§à€Ÿ à€à€ªà€²à€¬à¥à€§ à€à¥à€š"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Do Not Disturb à€
à€š à€à€à€à€Ÿà€²à¥ à€à¥à€²à¥à€¯à¥à€® à€¬à€¢à€Ÿà€à€š à€®à€¿à€²à¥à€Šà¥à€š"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Do Not Disturb à€
à€š à€à€à€à€Ÿà€²à¥ à€à¥à€²à¥à€¯à¥à€® à€¬à€¢à€Ÿà€à€š à€®à€¿à€²à¥à€Šà¥à€š"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sी à€
à€šà€®à¥à€¯à¥à€ à€à€°à¥à€šà€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€à¥à€¯à€Ÿà€ª à€à€°à¥à€šà¥à€¹à¥à€žà¥à¥€"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sी à€à€®à¥à€ªà€šà€®à€Ÿ à€žà¥à€ à€à€°à¥à€šà€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€à¥à€¯à€Ÿà€ª à€à€°à¥à€šà¥à€¹à¥à€žà¥à¥€ à€ªà€¹à¥à€à€ à€žà€®à¥à€¬à€šà¥à€§à¥ à€žà¥à€µà€Ÿà€¹à€°à¥ à€®à¥à€¯à¥à€ à€¹à¥à€š à€žà€à¥à€à€šà¥à¥€"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sी à€®à¥à€¯à¥à€ à€à€°à¥à€šà€Ÿà€à€Ÿ à€²à€Ÿà€à€¿ à€à¥à€¯à€Ÿà€ª à€à€°à¥à€šà¥à€¹à¥à€žà¥à¥€ à€ªà€¹à¥à€à€ à€žà€®à¥à€¬à€šà¥à€§à¥ à€žà¥à€µà€Ÿà€¹à€°à¥ à€®à¥à€¯à¥à€ à€¹à¥à€š à€žà€à¥à€à€šà¥à¥€"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à€à€®à¥à€ªà€š à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s à€à¥à€²à¥à€¯à¥à€®à€à€Ÿ à€šà€¿à€¯à€šà¥à€€à¥à€°à€£à€¹à€°à¥"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à€à€² à€€à€¥à€Ÿ à€žà¥à€à€šà€Ÿà€¹à€°à¥ à€à€à€à€Šà€Ÿ à€à€šà¥à€à¥ à€¬à€à¥à€šà¥ à€ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à€à€à€à€ªà¥à€à€žà€®à¥à€¬à€šà¥à€§à¥ à€žà¥à€à€¿à€à€®à€Ÿ à€à€Ÿà€šà¥à€¹à¥à€žà¥"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à€à¥à€²à¥à€¯à¥à€® à€žà¥à€²à€Ÿà€à€¡à€°à€¹à€°à¥ à€à€à¥à€žà¥à€ªà€Ÿà€šà¥à€¡ à€à€°à€¿à€à€à€Ÿ à€à€šà¥"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à€à¥à€²à¥à€¯à¥à€® à€žà¥à€²à€Ÿà€à€¡à€°à€¹à€°à¥ à€à¥à€²à¥à€¯à€Ÿà€ªà¥à€ž à€à€°à€¿à€à€à€Ÿ à€à€šà¥"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s à€®à¥à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à€
à€šà€®à¥à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> à€ªà¥à€²à¥ à€à€°à€¿à€à€Šà¥ à€"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à€
à€¡à€¿à€¯à¥ à€ªà¥à€²à¥ à€à€à€°à€¹à€šà¥ à€"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"à€žà€¿à€žà¥à€à€® UI à€à¥à€¯à¥à€šà€°"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à€¹à€Ÿà€²à€žà€Ÿà€²à¥ à€à€²à€Ÿà€à€à€à€Ÿ à€à€ªà€¹à€°à¥ à€
à€à€Ÿà€¡à€¿à€¬à€Ÿà€ à€¹à¥à€°à¥à€Šà¥ à€à€Ÿà€šà¥à€¹à¥à€žà¥"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à€¹à€Ÿà€²à€žà€Ÿà€²à¥ à€à€²à€Ÿà€à€à€à€Ÿ à€à€ªà€¹à€°à¥ à€ªà€à€Ÿà€¡à€¿à€¬à€Ÿà€ à€¹à¥à€°à¥à€Šà¥ à€à€Ÿà€šà¥à€¹à¥à€žà¥"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à€à€ªà€¹à€°à¥à€à¥ à€žà¥à€à¥ à€à¥à€²à¥à€šà¥à€¹à¥à€žà¥"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à€à€Ÿà€žà¥à€à€¬à€Ÿà€° à€Šà¥à€à€Ÿà€à€¯à¥à€žà¥"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à€žà¥à€à€¿à€ à€à¥à€²à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"à€à€žà€¿à€žà¥à€à¥à€šà¥à€ à€à¥à€²à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"à€žà¥à€à¥à€°à€¿à€š à€²à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"à€¹à€Ÿà€²à€à¥ à€à€ª à€Šà€Ÿà€¯à€Ÿà€à€€à€°à¥à€« à€°à€¹à€šà¥ à€à€°à¥ à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€®à¥à€¡ à€žà¥à€°à¥ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à€¹à€Ÿà€²à€à¥ à€à€ª à€¬à€Ÿà€¯à€Ÿà€à€€à€°à¥à€« à€°à€¹à€šà¥ à€à€°à¥ à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€®à¥à€¡ à€žà¥à€°à¥ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€šà€à¥ à€žà€Ÿà€à¥ à€«à¥à€² à€žà¥à€à¥à€°à€¿à€š à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à€žà¥à€ªà¥à€²à€¿à€ à€žà¥à€à¥à€°à€¿à€š à€ªà¥à€°à€¯à¥à€ à€à€°à€¿à€à€à€Ÿ à€¬à¥à€²à€Ÿ: à€à€à€à€Ÿ à€žà¥à€à¥à€°à€¿à€šà€®à€Ÿ à€à€à€à¥ à€à€ª à€
à€°à¥à€à¥à€®à€Ÿ à€²à¥à€à€Ÿà€šà¥à€¹à¥à€žà¥"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à€à€šà€ªà¥à€"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à€
à€°à¥à€à¥ à€à€Ÿà€·à€Ÿ à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€šà¥à€¹à¥à€žà¥"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€¬à¥à€²à€ à€à€°à€¿à€à€à¥ à€"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à€à¥à€¯à€Ÿà€®à¥à€°à€Ÿ à€° à€®à€Ÿà€à€à¥à€°à¥à€«à¥à€š à€¬à¥à€²à€ à€à€°à€¿à€à€à¥ à€"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à€®à€Ÿà€à€à¥à€°à¥à€«à¥à€š à€¬à¥à€²à€ à€à€°à€¿à€à€à¥ à€"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Do Not Disturb"</string>
<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>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index dd56a2e..976d2ab 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Screenshots maken is geblokkeerd door je IT-beheerder"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Bewerken"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bewerken"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Screenshot delen"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Meer opnemen"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot sluiten"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dit apparaat wordt beheerd door je ouder. Je ouder kan informatie bekijken en beheren, zoals de apps die je gebruikt, je locatie en je schermtijd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontgrendeld gehouden door TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Diefstalbeveiliging\nApparaat vergrendeld, te veel ontgrendelpogingen"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Het apparaat is vergrendeld na te veel verificatiepogingen"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Apparaat vergrendeld\nVerificatie mislukt"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Geluidsinstellingen"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatisch ondertitelen"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Geluid staat uit"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Casten"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Niet beschikbaar, belgeluid staat uit"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Niet beschikbaar omdat Niet storen aanstaat"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Niet beschikbaar omdat Niet storen aanstaat"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om dempen op te heffen."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om in te stellen op trillen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s-volumeknoppen"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Geluid bij gesprekken en meldingen (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Uitvoerinstellingen invoeren"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volumeschuifregelaars uitgevouwen"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volumeschuifregelaars samengevouwen"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"geluid van %s uitzetten"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"geluid van %s aanzetten"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> wordt afgespeeld op"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio wordt afgespeeld op"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Systeem-UI-tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Vooruitbladeren door recente apps"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Terugbladeren door recente apps"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Lijst met apps openen"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Taakbalk tonen"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Instellingen openen"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistent openen"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Scherm vergrendelen"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Gesplitst scherm openen met huidige app rechts"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Gesplitst scherm openen met huidige app links"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Van gesplitst scherm naar volledig scherm schakelen"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Tijdens gesplitst scherm: een app vervangen door een andere"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Invoer"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Overschakelen naar volgende taal"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera geblokkeerd"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera en microfoon geblokkeerd"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfoon geblokkeerd"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Niet storen"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikersaanwezigheid is waargenomen"</string>
<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>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 40683a7..ee8c094 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ଞàà¬àରିଚଞà¬à¬àଡଌିଠଚàବଟ à¬à¬ªà¬£à¬àଠIT à¬à¬¡à¬®à¬¿à¬šà¬àଠଊàà±à¬Ÿà¬°à¬Ÿ ବàଲଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à¬à¬¡à¬¿à¬ à¬à¬°à¬šà଀à"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ଞàà¬àରିଚଞà¬à à¬à¬¡à¬¿à¬ à¬à¬°à¬šà଀à"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ଞàà¬àରିଚଞଠଞààଟର à¬à¬°à¬šà଀à"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à¬
ଧିଠà¬àପà¬à¬° à¬à¬°à¬šà଀à"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ଞàà¬àରିଚଞà¬à à¬à¬Ÿà¬°à¬ à¬à¬°à¬šà଀à"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"ଲà¬à¬žàà¬àରିଚରà ଯà à¬àଣଞି à±à¬¿à¬àà¬à¬à à¬
ଚàମ଀ି ଊàବà?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"ଞàà¬à¬¿à¬à¬ž à¬àଲଚà଀à"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"à±à¬Ÿà¬°àଠà¬à¬ªàଞà¬à ପàଣି à¬à¬Ÿà¬²à à¬à¬°à¬¿à¬¬à?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"ପàଣି à¬à¬Ÿà¬²à à¬à¬°à¬šà଀à"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ààà¬à¬°à ବଊଳଟଚà଀à"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à¬à¬¹à¬¿ ଡିà¬à¬Ÿà¬à¬žà à¬à¬ªà¬£à¬àଠବଟପଟମଟà¬àଠଊàà±à¬Ÿà¬°à¬Ÿ ପରିà¬à¬Ÿà¬³à¬¿à¬€à¥€ à¬à¬ªà¬£à¬àଠବଟପଟମଟ à¬à¬ªà¬£ ବààବହଟର à¬à¬°àଥିବଟ à¬à¬ªàଞ, à¬à¬ªà¬£à¬àଠଲàà¬àଞଚà ଠଞàà¬àରିଚà ଞମà ପରି ଞàà¬à¬šà¬Ÿ ଊàà¬à¬¿à¬ªà¬Ÿà¬°à¬¿à¬¬à à¬à¬¬à¬ ପରିà¬à¬Ÿà¬³à¬šà¬Ÿ à¬à¬°à¬¿à¬ªà¬Ÿà¬°à¬¿à¬¬àी"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ଊàà±à¬Ÿà¬°à¬Ÿ à¬
ଚàଲà¬à ରହିà¬à¬¿"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ଥàଫàଠଞàରà¬àଷଟ\nଡିà¬à¬Ÿà¬à¬ž ଲଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿, à¬
ଚàà¬à¬àଡଌିଠà¬
ଚଲଠପàରà¬àଷàà¬à¬Ÿ"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ଞଟà¬à¬£àଡ ଞàà¬à¬¿à¬à¬žà"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ଞàବà¬à¬Ÿà¬³à¬¿à¬€ à¬ààଟପàଞଚà ମିଡିà¬"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ମàààà¬"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à¬à¬Ÿà¬·àଠà¬à¬°à¬šà଀à"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ରିà¬à¬à ମàààଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬¥à¬¿à¬¬à¬Ÿ ଯàà¬àଠà¬à¬ªà¬²à¬¬àଧ ଚଟହିà¬"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'ବିରà¬à଀ à¬à¬°à¬šà଀à ଚଟହିà¬\' à¬à¬Ÿà¬²à ଥିବଟ ଯàà¬àଠà¬à¬ªà¬²à¬¬àଧ ଚଟହିà¬"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"\'ବିରà¬à଀ à¬à¬°à¬šà଀à ଚଟହିà¬\' à¬à¬Ÿà¬²à ଥିବଟ ଯàà¬àଠà¬à¬ªà¬²à¬¬àଧ ଚଟହିà¬"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sी à¬
ଚମàààà¬à à¬à¬°à¬¿à¬¬à¬Ÿ ପଟà¬à¬ à¬à¬Ÿà¬ªà à¬à¬°à¬šà଀àी"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sी à¬à¬Ÿà¬à¬¬àରàà¬à ଞàà¬à à¬à¬°à¬¿à¬¬à¬Ÿà¬à à¬à¬Ÿà¬ªà à¬à¬°à¬šà଀àी à¬à¬àଞàଞିବିଲିà¬à ଞରàà¬à¬¿à¬žà ମàààà¬à à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬ªà¬Ÿà¬°àी"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sी ମàààà¬à à¬à¬°à¬¿à¬¬à¬Ÿà¬à à¬à¬Ÿà¬ªà à¬à¬°à¬šà଀àी à¬à¬àଞàଞିବିଲିà¬à ଞରàà¬à¬¿à¬žà ମàààà¬à à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬ªà¬Ÿà¬°àी"</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à¬à¬Ÿà¬à¬¬àରàà¬à"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s à¬à¬²àààମà ଚିàଚà଀àରଣ"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à¬à¬²à ଠବିà¬àà¬à¬ªà଀ି ପଟà¬à¬ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)ରà ରିà¬àଠହàବ"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à¬à¬à¬à¬ªàଠଞàà¬à¬¿à¬à¬ž ଲàà¬à¬šà଀à"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à¬à¬²àààମ ଞàଲଟà¬à¬¡à¬°à¬àଡଌିà¬à ବିଞà଀ଟର à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à¬à¬²àààମ ଞàଲଟà¬à¬¡à¬°à¬àଡଌିà¬à ଞà¬àà¬àà¬à¬¿à¬€ à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sà¬à ମàààଠà¬à¬°à¬šà଀à"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sà¬à à¬
ଚମàààଠà¬à¬°à¬šà଀à"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>ରà ପàଲà à¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à¬
ଡିଠପàଲà ହàବ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ଞିଷàà¬à¬®à UI à¬àààଚରà"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ବରà଀à଀ମଟଚର à¬à¬ªàଞ ମଧààରà à¬à¬à¬à ଯଟà¬à¬šà଀à"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ବରà଀à଀ମଟଚର à¬à¬ªàଞ ମଧààରà ପà¬à¬à ଯଟà¬à¬šà଀à"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à¬à¬ªàଞ ଀ଟଲିà¬à¬Ÿ à¬àଲଚà଀à"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à¬à¬Ÿà¬žàà¬à¬¬à¬Ÿà¬° ଊàà¬à¬Ÿà¬šà଀à"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ଞàà¬à¬¿à¬à¬ž à¬àଲଚà଀à"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant à¬àଲଚà଀à"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ଲଠଞàà¬àରିଚ"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"RHSରà ବରà଀à଀ମଟଚର à¬à¬ª ଞହ ଞàପàଲିଠଞàà¬àରିଚà¬à ପàରବàଶ à¬à¬°à¬Ÿà¬šà଀à"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"LHSରà ବରà଀à଀ମଟଚର à¬à¬ª ଞହ ଞàପàଲିଠଞàà¬àରିଚà¬à ପàରବàଶ à¬à¬°à¬Ÿà¬šà଀à"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ଞàପàଲିଠଞàà¬àରିଚରà ପàରàଣàଣ ଞàà¬àରିଚà¬à ଞàà¬à¬ à¬à¬°à¬šà଀à"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ଞàପàଲିଠଞàà¬àରିଚ ଞମàରà: à¬àଣଞି à¬à¬ªà¬à à¬àà¬à¬¿à¬à¬°à à¬
ଚàà à¬à¬ à¬à¬ªà¬°à ବଊଳଟଚà଀à"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à¬à¬šà¬ªàଠà¬à¬°à¬šà଀à"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ପରବରà଀à଀à à¬à¬Ÿà¬·à¬Ÿà¬à ଞàà¬à¬ à¬à¬°à¬šà଀à"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à¬àମàରଟà¬à ବàଲଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à¬àମàରଟ à¬à¬¬à¬ ମଟà¬à¬àରàଫàଚà¬à ବàଲଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ମଟà¬à¬àରàଫàଚà¬à ବàଲଠà¬à¬°à¬Ÿà¬¯à¬Ÿà¬à¬à¬¿"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ବିରà¬à଀ à¬à¬°à¬šà଀à ଚଟହିà¬"</string>
<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>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index b2296b2..49156bc 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àš€à©àš¹àšŸàš¡à© àšàš.àšà©. àšªà©àš°àšžàšŒàšŸàšžàš àšµà©±àš²à©àš àšžàšà©àš°à©àššàšžàšŒàšŸàš àš²à©àš£ àšŠà© àšžà©àšµàš¿àš§àšŸ àššà©à©° àš¬àš²àšŸàš àšà©àš€àšŸ àšàš¿àš àš¹à©"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"àšžà©°àšªàšŸàšŠàšš àšàš°à©"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"àšžàšà©àš°à©àššàšžàšŒàšŸàš àšŠàšŸ àšžà©°àšªàšŸàšŠàšš àšàš°à©"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"àšžàšà©àš°à©àššàšžàšŒàšŸàš àšžàšŸàšàšàšŸ àšàš°à©"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àš¹à©àš° àšà©àšªàšàš° àšàš°à©"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àšžàšà©àš°à©àššàšžàšŒàšŸàš àšàšŸàš°àš àšàš°à©"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"àšà© àš²àšŸàš-àšžàšà©àš°à©àšš \'àš€à© àšàš¿àšžà© àšµà© àšµàš¿àšà©àš àššà©à©° àšàšàš¿àš àšŠà©àš£à© àš¹à©?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"àšžà©àšàš¿à©°àšàšŸàš àšà©àš²à©àš¹à©"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"àšà©°àš® àšžà©°àš¬à©°àš§à© àšàšªàšŸàš àš€à©àš àš°à©àš àš¹àšàšŸàšàš?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"àš°à©àš àš¹àšàšŸàš"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"àšµàš°àš€à©àšàšàšŸàš° àšžàšµàš¿à©±àš àšàš°à©"</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àšàšž àš¡à©àšµàšŸàšàšž àšŠàšŸ àšªà©àš°àš¬à©°àš§àšš àš€à©àš¹àšŸàš¡à© àš®àšŸàš-àšªàš¿àš àšµà©±àš²à©àš àšà©àš€àšŸ àšàšŸàšàšŠàšŸ àš¹à©à¥€ àš€à©àš¹àšŸàš¡à© àš®àšŸàš-àšªàš¿àš àš€à©àš¹àšŸàš¡à©àšàš àšàšªàšŸàš àšŠà© àšµàš°àš€à©àš, àš€à©àš¹àšŸàš¡à© àšàš¿àšàšŸàš£à© àš
àš€à© àš€à©àš¹àšŸàš¡à© àšžàšà©àš°à©àšš àšžàš®à©àš àšµàš°àšà© àšàšŸàš£àšàšŸàš°à© àššà©à©° àšŠà©àš àš
àš€à© àšàšžàšŠàšŸ àšªà©àš°àš¬à©°àš§àšš àšàš° àšžàšàšŠà© àš¹àššà¥€"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"àšàš°à©±àšžàš-àšàšà©°àš àšµà©±àš²à©àš àš
àš£àš²àšŸàš àš°à©±àšàš¿àš àšàš¿àš"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àšà©àš°à© àš€à©àš àšžà©àš°à©±àšàš¿àš\nàš¡à©àšµàšŸàšàšž àš²àšŸàš àš¹à© àšàš¿àš, àš
àš£àš²àšŸàš àšàš°àšš àšŠà©àšàš àšàš àšà©àšžàšŒàš¿àšžàšŒàšŸàš àšà©àš€à©àšàš àšàšàšàš"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àš§à©àššà© àšžà©àšàš¿à©°àšàšŸàš"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"àšžàšµà©àšàš²àš¿àš€ àšžà©àš°àšà© àš®à©àš¡à©àš"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àš®àš¿àšàš"</string>
<string name="media_device_cast" msgid="4786241789687569892">"àšàšŸàšžàš àšàš°à©"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"àšàšªàš²àš¬àš§ àššàš¹à©àš àš¹à© àšàš¿àšàšàšàš¿ àšà©°àšà© àš®àš¿àšàš àšà©àš€à© àš¹à©àš àš¹à©"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"àšàšªàš²àš¬àš§ àššàš¹à©àš àš¹à© àšàš¿àšàšàšàš¿ àšªàš°à©àšžàšŒàšŸàšš àššàšŸ àšàš°à© àšµàš¿àšžàšŒà©àšžàšŒàš€àšŸ àšàšŸàš²à© àš¹à©"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"àšàšªàš²àš¬àš§ àššàš¹à©àš àš¹à© àšàš¿àšàšàšàš¿ àšªàš°à©àšžàšŒàšŸàšš àššàšŸ àšàš°à© àšµàš¿àšžàšŒà©àšžàšŒàš€àšŸ àšàšŸàš²à© àš¹à©"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sी àš
àš£àš®àš¿àšàš àšàš°àšš àš²àš àšà©àšª àšàš°à©à¥€"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sी àš¥àš°àš¥àš°àšŸàš¹àš àšžà©à©±àš àšàš°àšš àš²àš àšà©àšª àšàš°à©à¥€ àšªàš¹à©à©°àšàš¯à©àšàš€àšŸ àšžà©àšµàšŸàšµàšŸàš àš®àš¿àšàš àš¹à© àšžàšàšŠà©àšàš àš¹àššà¥€"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sी àš®àš¿àšàš àšàš°àšš àš²àš àšà©àšª àšàš°à©à¥€ àšªàš¹à©à©°àšàš¯à©àšàš€àšŸ àšžà©àšµàšŸàšµàšŸàš àš®àš¿àšàš àš¹à© àšžàšàšŠà©àšàš àš¹àššà¥€"</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"àš¥àš°àš¥àš°àšŸàš¹àš"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s àšµà©àš²àš¿àšàš® àšà©°àšàš°à©àš²"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àšàšŸàš²àšŸàš àšàšàš£ àš
àš€à© àšžà©àšàššàšŸàšµàšŸàš àš®àš¿àš²àš£ \'àš€à© àšà©°àšà© àšµàšà©àšà© (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"àšàšàšàšªà©à©±àš àšžà©àšàš¿à©°àšàšŸàš àšŠàšŸàšàš² àšàš°à©"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àš
àšµàšŸàšàšŒ àšžàš²àšŸàšàš¡àš°àšŸàš àšµàš¿àšžàš€àšŸàš° àšà©àš€àšŸ àšàš¿àš"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"àš
àšµàšŸàšàšŒ àšžàš²àšŸàšàš¡àš°àšŸàš àššà©à©° àšžàš®à©àšàš¿àš àšàš¿àš"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s àššà©à©° àš®àš¿àšàš àšàš°à©"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s àššà©à©° àš
àš£àš®àš¿àšàš àšàš°à©"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> àšàš²àšŸàšàš àšàšŸ àš°àš¿àš¹àšŸ àš¹à©"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"àšàš¡à©àš àšàšž \'àš€à© àšà©±àš²à©àšà©"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI àšàš¿àšàššàš°"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"àš¹àšŸàš² àš¹à© àšµàš¿à©±àš àšà©àš²à©àš¹à©àšàš àšàšàšàš àšàšªàšŸàš \'àš€à© àš
ੱàšà© àšàšŸàš"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"àš¹àšŸàš² àš¹à© àšµàš¿à©±àš àšà©àš²à©àš¹à©àšàš àšàšàšàš àšàšªàšŸàš \'àš€à© àšµàšŸàšªàšž àšàšŸàš"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"àšàšªàšŸàš àšŠà© àšžà©àšà© àšà©àš²à©àš¹à©"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"àšàšŸàšžàšàš¬àšŸàš° àšŠàš¿àšàšŸàš"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"àšžà©àšàš¿à©°àšàšŸàš àšà©àš²à©àš¹à©"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant àšà©àš²à©àš¹à©"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"àš²àšŸàš àšžàšà©àš°à©àšš"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS àš²àš àš®à©àšà©àšŠàšŸ àšàšª àššàšŸàš² àšžàšªàš²àš¿àš àšžàšà©àš°à©àšš àšµàš¿à©±àš àšŠàšŸàšàš² àš¹à©àšµà©"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS àš²àš àš®à©àšà©àšŠàšŸ àšàšª àššàšŸàš² àšžàšªàš²àš¿àš àšžàšà©àš°à©àšš àšµàš¿à©±àš àšŠàšŸàšàš² àš¹à©àšµà©"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"àšžàšªàš²àš¿àš àšžàšà©àš°à©àšš àš€à©àš àšªà©àš°à© àšžàšà©àš°à©àšš \'àš€à© àšžàšµàš¿à©±àš àšàš°à©"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"àšžàšªàš²àš¿àš àšžàšà©àš°à©àšš àšŠà©àš°àšŸàšš: àšà©±àš àšàšª àššàšŸàš² àšŠà©àšà© àšàšª àššà©à©° àš¬àšŠàš²à©"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àšàššàšªà©à©±àš"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"àš
àšàš²à© àšàšŸàšžàšŒàšŸ \'àš€à© àšžàšµàš¿à©±àš àšàš°à©"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àšà©àš®àš°àšŸ àš¬àš²àšŸàš àšà©àš€àšŸ àšàš¿àš"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àšà©àš®àš°àšŸ àš
àš€à© àš®àšŸàšàšà©àš°à©àš«àšŒà©àšš àš¬àš²àšŸàš àšà©àš€à© àšàš"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"àš®àšŸàšàšà©àš°à©àš«àšŒà©àšš àš¬àš²àšŸàš àšà©àš€àšŸ àšàš¿àš"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àšªàš°à©àšžàšŒàšŸàšš àššàšŸ àšàš°à©"</string>
<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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a08e473..9ee0b78 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Robienie zrzutów ekranu zostaÅo zablokowane przez administratora IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Edytuj"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Edytuj zrzut ekranu"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"UdostÄpnij"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"UdostÄpnij zrzut ekranu"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zarejestruj wiÄcej danych"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
@@ -538,7 +539,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tym urzÄ
dzeniem zarzÄ
dza Twój rodzic. Rodzic moÅŒe zobaczyÄ róÅŒne informacje, np. o aplikacjach, których uÅŒywasz, lokalizacji i czasie korzystania z urzÄ
dzenia, a takÅŒe zarzÄ
dzaÄ tymi danymi."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Blokada anulowana przez agenta zaufania"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ochrona przed kradzieÅŒÄ
\nZablokowano – za duÅŒo prób logowania."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"UrzÄ
dzenie zostaÅo zablokowane, zbyt wiele prób uwierzytelnienia"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"UrzÄ
dzenie zostaÅo zablokowane\nNie udaÅo siÄ uwierzytelniÄ"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ustawienia dźwiÄku"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Autom. napisy do multimediów"</string>
@@ -752,7 +754,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"PrzeÅÄ
czanie siÄ do przodu miÄdzy ostatnimi aplikacjami"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"PrzeÅÄ
czanie siÄ wstecz miÄdzy ostatnimi aplikacjami"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otwieranie listy aplikacji"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Pokazywanie paska aplikacji"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otwieranie ustawieÅ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otwieranie asystenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Blokada ekranu"</string>
@@ -761,6 +762,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Uruchamianie trybu podzielonego ekranu z bieÅŒÄ
cÄ
aplikacjÄ
po prawej"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Uruchamianie trybu podzielonego ekranu z bieÅŒÄ
cÄ
aplikacjÄ
po lewej"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"PrzeÅÄ
cz podzielony ekran na peÅny ekran"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"PrzeÅÄ
cz siÄ na aplikacjÄ po prawej lub poniÅŒej na podzielonym ekranie"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"PrzeÅÄ
cz siÄ na aplikacjÄ po lewej lub powyÅŒej na podzielonym ekranie"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Podczas podzielonego ekranu: zastÄpowanie aplikacji"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Wprowadzanie"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"PrzeÅÄ
czanie na nastÄpny jÄzyk"</string>
@@ -1259,8 +1262,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon sÄ
zablokowane"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Nie przeszkadzaÄ"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Wykryto obecnoÅÄ uÅŒytkownika"</string>
<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>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 83d523a..a519883 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"As capturas de tela foram bloqueadas pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerenciado pelo seu familiar responsável, que pode ver e gerenciar informações como os apps que você usa, sua localização e seu tempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Proteção contra roubo\nDispositivo bloqueado por tentativas de desbloqueio em excesso"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Configurações de som"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Transcrição automática"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque foi silenciado"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível porque o Não perturbe está ativado"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível porque o Não perturbe está ativado"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controles de volume %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Chamadas e notificações farão o smartphone tocar (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserir configurações de saída"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volume abertos"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volume fechados"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"O áudio vai tocar em"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Avançar pela lista de apps recentes"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Voltar pela lista de apps recentes"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de apps"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar a Barra de tarefas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configurações"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir o Google Assistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Usar a tela dividida com o app atual à direita"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Usar a tela dividida com o app atual à esquerda"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar da tela dividida para a tela cheia"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para o próximo idioma"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Não perturbe"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<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>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 44637a3..f0f451b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"A capacidade de fazer capturas de ecrã foi bloqueada pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de ecrã"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Partilhar"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Partilhar captura de ecrã"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar captura de ecrã"</string>
@@ -538,7 +539,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerido pelos teus pais, que podem ver e gerir informações como as apps que utilizas, a tua localização e o tempo de utilização."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mantido desbloqueado pelo TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Proteção contra roubo\nDisp. bloq., muitas tentativas de desb."</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"O dispositivo foi bloqueado; demasiadas tentativas de autenticação"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Dispositivo bloqueado\nA autenticação falhou"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Definições de som"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Multim. legendas automáticas"</string>
@@ -583,10 +585,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível porque o toque está desat."</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível porque Não incomodar está ativado"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível porque Não incomodar está ativado"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para reativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
@@ -603,16 +603,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controlos de volume de %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"As chamadas e as notificações tocam (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introduzir definições de saída"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controlos de deslize do volume expandidos"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controlos de deslize do volume reduzidos"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"reativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"A ouvir <xliff:g id="LABEL">%s</xliff:g> em"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"O áudio será ouv. em"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador da interface do sistema"</string>
@@ -759,7 +754,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Percorrer apps recentes para a frente"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Percorrer apps recentes para trás"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de apps"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar barra de tarefas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir definições"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Assistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ecrã de bloqueio"</string>
@@ -768,6 +762,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Aceder ao ecrã dividido com a app atual para RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Aceder ao ecrã dividido com a app atual para LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar de ecrã dividido para ecrã inteiro"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mude para a app à direita ou abaixo enquanto usa o ecrã dividido"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para a app à esquerda ou acima enquanto usa o ecrã dividido"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Durante o ecrã dividido: substituir uma app por outra"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para idioma seguinte"</string>
@@ -1266,8 +1262,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmara e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Não incomodar"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Quando deteta a presença do utilizador"</string>
<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>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 83d523a..a519883 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"As capturas de tela foram bloqueadas pelo administrador de TI"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Este dispositivo é gerenciado pelo seu familiar responsável, que pode ver e gerenciar informações como os apps que você usa, sua localização e seu tempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Proteção contra roubo\nDispositivo bloqueado por tentativas de desbloqueio em excesso"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Configurações de som"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Transcrição automática"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque foi silenciado"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponível porque o Não perturbe está ativado"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponível porque o Não perturbe está ativado"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Controles de volume %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Chamadas e notificações farão o smartphone tocar (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserir configurações de saída"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volume abertos"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volume fechados"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"O áudio vai tocar em"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Avançar pela lista de apps recentes"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Voltar pela lista de apps recentes"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Abrir lista de apps"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Mostrar a Barra de tarefas"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configurações"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir o Google Assistente"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Usar a tela dividida com o app atual à direita"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Usar a tela dividida com o app atual à esquerda"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar da tela dividida para a tela cheia"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Mudar para o próximo idioma"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Não perturbe"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<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>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 24bec4a..4fea189 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Administratorul IT a blocat crearea capturilor de ecran"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"EditeazÄ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"EditeazÄ captura de ecran"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Trimite captura de ecran"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Surprinde mai mult"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închide captura de ecran"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dispozitivul este gestionat de unul dintre pÄrinÈi. PÄrintele poate sÄ vadÄ Èi sÄ gestioneze informaÈii cum ar fi aplicaÈiile pe care le foloseÈti, locaÈia ta Èi durata de folosire a dispozitivului."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Deblocat de TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ProtecÈie anti-furt\nDispozitiv blocat, prea multe încercÄri de deblocare"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"SetÄri de sunet"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"AdaugÄ subtitrÄri automate la fiÈierele media"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"BlocheazÄ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ProiecteazÄ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponibil; soneria este dezactivatÄ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Indisponibil; funcÈia Nu deranja e activatÄ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Indisponibil; funcÈia Nu deranja e activatÄ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Atinge pentru a activa sunetul."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Atinge pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atinge pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibraÈii"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Comenzi de volum pentru %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Apelurile Èi notificÄrile vor suna (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introdu setÄrile de ieÈire"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Glisoare de volum extinse"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Glisoare de volum restrânse"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"dezactiveazÄ sunetul pentru %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activeazÄ sunetul pentru %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Se redÄ <xliff:g id="LABEL">%s</xliff:g> pe"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ConÈinutul audio se va reda pe"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Parcurge aplicaÈiile recente înainte"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Parcurge aplicaÈiile recente înapoi"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Deschide lista de aplicaÈii"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"AfiÈeazÄ bara de activitÄÈi"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Deschide setÄrile"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Deschide Asistentul"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ecranul de blocare"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"AcceseazÄ ecranul împÄrÈit cu aplicaÈia actualÄ în dreapta"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"AcceseazÄ ecranul împÄrÈit cu aplicaÈia actualÄ în stânga"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ComutÄ de la ecranul împÄrÈit la ecranul complet"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"În modul ecran împÄrÈit: înlocuieÈte o aplicaÈie cu alta"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Introducere"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ComutÄ la urmÄtoarea limbÄ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera foto a fost blocatÄ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera foto Èi microfonul sunt blocate"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfonul a fost blocat"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Nu deranja"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"S-a detectat prezenÈa utilizatorului"</string>
<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>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 584a7da..d70d8ff 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"СОÑÑеЌМÑй аЎЌОМОÑÑÑаÑÐŸÑ Ð·Ð°Ð¿ÑеÑОл ЎелаÑÑ ÑкÑОМÑПÑÑ."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÐзЌеМОÑÑ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÐзЌеМОÑÑ ÑкÑОМÑПÑ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÐПЎелОÑÑÑÑ ÑкÑОМÑПÑПЌ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"УвелОÑОÑÑ Ð¿Ð»ÐŸÑÐ°ÐŽÑ ÑкÑОМÑПÑа"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐакÑÑÑÑ ÑкÑОМÑПÑ"</string>
@@ -437,10 +439,8 @@
<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>
- <!-- no translation found for dialog_title_to_allow_any_widget (1004820948962675644) -->
- <skip />
- <!-- no translation found for button_text_to_open_settings (1987729256950941628) -->
- <skip />
+ <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"РазÑеÑОÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑ Ð»ÑбÑе вОЎжеÑÑ ÐœÐ° заблПкОÑПваММÑй ÑкÑаМ?"</string>
+ <string name="button_text_to_open_settings" msgid="1987729256950941628">"ÐÑкÑÑÑÑ ÐœÐ°ÑÑÑПйкО"</string>
<string name="work_mode_off_title" msgid="5794818421357835873">"ÐклÑÑОÑÑ ÑабПÑОе пÑОлПжеМОÑ?"</string>
<string name="work_mode_turn_on" msgid="907813741770247267">"ÐклÑÑОÑÑ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"СЌеМОÑÑ Ð¿ÐŸÐ»ÑзПваÑелÑ."</string>
@@ -540,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÐÑОЌ ÑÑÑÑПйÑÑвПЌ ÑпÑавлÑÐµÑ ÐŸÐŽÐžÐœ Оз ÑвПОÑ
ÑПЎОÑелей. ÐМ ÐŒÐŸÐ¶ÐµÑ Ð²ÐžÐŽÐµÑÑ, МапÑОЌеÑ, какОЌО пÑОлПжеМОÑЌО ÑÑ Ð¿ÐŸÐ»ÑзÑеÑÑÑÑ Ðž гЎе МаÑ
ПЎОÑÑÑÑ, а Ñакже заЎаваÑÑ ÐŸÐ¿ÑеЎелеММÑе МаÑÑÑПйкО (МапÑОЌеÑ, ПгÑаМОÑОваÑÑ Ð²ÑÐµÐŒÑ ÐžÑпПлÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÑÑÑПйÑÑва)."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"СеÑÑ VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"РазблПкОÑПваМП агеМÑПЌ ЎПвеÑОÑ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐаÑОÑа ÐŸÑ ÐºÑажО\nУÑÑÑ-вП заблПкОÑПваМП. СлОÑкПЌ ЌМПгП пПпÑÑПк."</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>."</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐаÑÑÑПйкО звÑка"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐвÑПЌаÑОÑеÑкО ЎПбавлÑÑÑ ÑÑбÑОÑÑÑ"</string>
@@ -585,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ðез звÑка"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ТÑаМÑлÑÑОÑ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÐеЎПÑÑÑпМП, кПгЎа ПÑклÑÑеМ звÑк вÑзПвПв"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐеЎПÑÑÑпМП пÑО вклÑÑеММПЌ ÑежОЌе \"Ðе беÑпПкПОÑÑ\"."</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐеЎПÑÑÑпМП пÑО вклÑÑеММПЌ ÑежОЌе \"Ðе беÑпПкПОÑÑ\"."</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐажЌОÑе, ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑОÑÑ Ð·Ð²Ñк."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐажЌОÑе, ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑОÑÑ Ð²ÐžÐ±ÑаÑОÑ. СпеÑОалÑМÑе вПзЌПжМПÑÑО ЌПгÑÑ Ð¿ÑекÑаÑОÑÑ ÑабПÑÑ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐажЌОÑе, ÑÑÐŸÐ±Ñ Ð²ÑклÑÑОÑÑ Ð·Ð²Ñк. СпеÑОалÑМÑе вПзЌПжМПÑÑО ЌПгÑÑ Ð¿ÑекÑаÑОÑÑ ÑабПÑÑ."</string>
@@ -605,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вклÑÑОÑÑ Ð²ÐžÐ±ÑаÑОÑ"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s: ÑегÑлОÑПвка гÑПЌкПÑÑО"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐÐ»Ñ Ð·Ð²ÐŸÐœÐºÐŸÐ² О ÑвеЎПЌлеМОй вклÑÑеМ звÑк (ÑÑÐŸÐ²ÐµÐœÑ Ð³ÑПЌкПÑÑО: <xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÐеÑейÑО к МаÑÑÑПйкаЌ вÑвПЎа аÑЎОП"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐПлзÑМкО ÐŽÐ»Ñ ÑегÑлОÑПвкО гÑПЌкПÑÑО ÑазвеÑМÑÑÑ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐПлзÑМкО ÐŽÐ»Ñ ÑегÑлОÑПвкО гÑПЌкПÑÑО ÑвеÑМÑÑÑ"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ПÑклÑÑОÑÑ Ð·Ð²Ñк: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"вклÑÑОÑÑ Ð·Ð²Ñк: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> – запÑÑеМП зЎеÑÑ:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑПОгÑÑваМОе аÑЎОП:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -761,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐÑПкÑÑÑОÑÑ Ð²Ð¿ÐµÑеЎ ÑпОÑПк МеЎавМОÑ
пÑОлПжеМОй"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐÑПкÑÑÑОÑÑ ÐœÐ°Ð·Ð°ÐŽ ÑпОÑПк МеЎавМОÑ
пÑОлПжеМОй"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐÑкÑÑÑÑ ÑпОÑПк пÑОлПжеМОй"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐПказаÑÑ Ð¿Ð°ÐœÐµÐ»Ñ Ð·Ð°ÐŽÐ°Ñ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐÑкÑÑÑÑ ÐœÐ°ÑÑÑПйкО"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑкÑÑÑÑ ÐÑÑОÑÑеМÑа"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐаблПкОÑПваÑÑ ÑкÑаМ"</string>
@@ -770,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐклÑÑОÑÑ ÑазЎелеМОе ÑкÑаМа Ñ ÑекÑÑОЌ пÑОлПжеМОеЌ ÑпÑава"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐклÑÑОÑÑ ÑазЎелеМОе ÑкÑаМа Ñ ÑекÑÑОЌ пÑОлПжеМОеЌ Ñлева"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐзЌеМОÑÑ ÑежОЌ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ ÑкÑаМа Ма пПлМПÑкÑаММÑй ÑежОЌ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ð ÑежОЌе ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ ÑкÑаМа заЌеМОÑÑ ÐŸÐŽÐœÐŸ пÑОлПжеМОе ÐŽÑÑгОЌ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐвПЎ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐÑбÑаÑÑ ÑлеЎÑÑÑОй ÑзÑк"</string>
@@ -1268,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑа заблПкОÑПваМа"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑа О ЌОкÑПÑПМ заблПкОÑПваМÑ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑПМ заблПкОÑПваМ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе беÑпПкПОÑÑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 30f7db3..720f76d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"à¶à·à¶» ර෠à¶à·à¶±à·à¶ž à¶à¶¶à¶à· IT à¶Žà¶»à·à¶Žà·à¶œà¶ à·à·à·à·à¶±à· à¶
à·à·à·à¶» à¶à¶» à¶à¶"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à·à¶à·à·à¶à¶»à¶«à¶º à¶à¶»à¶±à·à¶±"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à¶à·à¶» à¶»à·à· à·à¶à·à·à¶à¶»à¶«à¶º à¶à¶»à¶±à·à¶±"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à¶à·à¶» à¶»à·à· à¶¶à·à¶¯à· à¶à¶±à·à¶±"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à¶à· à¶à·à¶»à·à¶«à¶º à¶à¶»à¶±à·à¶±"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"à¶à·à¶» à¶»à·à· à¶à·à¶ ගනà·à¶±"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à¶žà·à¶ž à¶à¶Žà·à¶à¶à¶º à¶à¶¶à¶à· à¶žà·à¶Žà·à¶ºà¶±à· à·à·à·à·à¶±à· à¶à·
à¶žà¶±à·à¶à¶»à¶«à¶º à¶à·à¶»à·. à¶à¶¶ à¶·à·à·à·à¶ à¶à¶»à¶± යà·à¶¯à·à¶žà·, à¶à¶¶à¶à· à·à·à¶®à·à¶±à¶º à·à· à¶à¶¶à¶à· à¶à·à¶» à¶à·à¶œà¶º à·à·à¶±à· à¶à·à¶»à¶à·à¶»à· à¶à¶¶à¶à· à¶žà·à¶Žà·à¶ºà¶±à·à¶§ à¶¶à·à¶œà·à¶žà¶§ à·à· à¶à·
à¶žà¶±à·à¶à¶»à¶«à¶º à¶à·à¶»à·à¶žà¶§ à·à·à¶à·à¶º."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à¶žà¶à·à¶±à· à¶
à¶à·à¶œà· දඞ෠à¶à¶¶à· à¶à¶±à·à¶±"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à·à·à¶»à¶à¶žà· à¶à¶»à¶à·à·à¶«à¶º\nà¶à¶Žà·à¶à¶à¶º à¶
à¶à·à·
෠දඞ෠à¶à¶, à¶
à¶à·à·
à· à·à·à¶»à·à¶žà· à¶à¶à·à·à·à·à¶ºà¶±à· à·à·à¶©à·à¶ºà·"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à·à¶¶à·à¶¯ à·à·à¶à·à·à¶žà·"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à¶žà·à¶°à·à¶º à·à·à·à¶ºà¶à¶à·à¶»à·à¶ºà· à·à·à¶»à·à·à¶à¶œ"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à¶±à·à·à¶¬ à¶à¶»à¶±à·à¶±"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à·à·à¶à·à·à¶º"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à¶±à·à¶¯à¶º à¶±à·à·à¶¬ à¶à¶» à¶à¶à· à¶±à·à·à· à¶±à·à¶œà·à¶¶à·"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à¶¶à·à¶°à· à¶±à·à¶à¶»à¶±à·à¶± à¶à·à¶»à·à¶ºà·à¶à·à¶žà¶à· à¶à¶à· à¶¶à·à·à·à¶±à· ගද à¶±à·à·à·à¶"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à¶¶à·à¶°à· à¶±à·à¶à¶»à¶±à·à¶± à¶à·à¶»à·à¶ºà·à¶à·à¶žà¶à· à¶à¶à· à¶¶à·à·à·à¶±à· ගද à¶±à·à·à·à¶"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à¶±à·à·à¶¬ à¶à·à¶»à·à¶ž à¶à·à¶à· à¶à·à¶»à·à¶žà¶§ à¶à¶§à·à¶§à· à¶à¶»à¶±à·à¶±."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à¶à¶žà·à¶Žà¶±à¶º à¶à·à¶»à·à¶žà¶§ à¶à¶§à·à¶§à· à¶à¶»à¶±à·à¶±. à¶Žà·à¶»à·à·à·à·à¶ºà¶à· à·à·à·à· à¶±à·à·à¶¬ à¶à·
à·à·à¶à·à¶º."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à¶±à·à·à¶¬ à¶à·à¶»à·à¶žà¶§ à¶à¶§à·à¶§à· à¶à¶»à¶±à·à¶±. à¶Žà·à¶»à·à·à·à·à¶ºà¶à· à·à·à·à· à¶±à·à·à¶¬ à¶à·
à·à·à¶à·à¶º."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à¶à¶žà·à¶Žà¶±à¶º"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"à·à¶¬ à¶Žà¶»à·à¶žà· à¶Žà·à¶œà¶± %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à¶à¶žà¶à·à¶žà· à·à· දà·à¶±à·à¶žà·à¶¯à·à¶žà· (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>) à¶±à·à¶¯ à¶à¶»à¶±à· à¶à¶"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à¶Žà·à¶»à¶à·à¶¯à·à¶± à·à·à¶à·à·à¶žà· à¶à¶à·à¶œà· à¶à¶»à¶±à·à¶±"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à·à¶¬ à·à·à¶œà¶ºà·à¶©à¶» දà·à¶à·à·à¶» à¶à¶"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à·à¶¬ à·à·à¶œà¶ºà·à¶©à¶» à·à¶à·à·
à· à¶à¶"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s à¶±à·à·à¶¬ à¶à¶»à¶±à·à¶±"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à¶±à·à·à¶¬ à¶±à·à¶à¶»à¶±à·à¶±"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> à·à·à¶¯à¶±à¶º à¶à¶»à¶±à·à¶±à·"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à·à·à¶»à·à·à¶º à·à·à¶¯à¶±à¶º à·à¶±à· à¶à¶à·à¶à·"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ඎදà·à¶°à¶à· UI à·à·à·à¶»à¶à¶º"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à¶žà·à¶ යà·à¶¯à·à¶žà· à·à¶»à·à· à¶à¶¯à·à¶»à·à¶ºà¶§ à¶à·à¶œà¶à·à¶»à¶ž à¶à¶»à¶±à·à¶±"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à¶žà·à¶ යà·à¶¯à·à¶žà· à·à¶»à·à· à¶à¶Žà·à·à·à¶§ à¶à·à¶œà¶à·à¶»à¶ž à¶à¶»à¶±à·à¶±"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"යà·à¶¯à·à¶žà· à¶œà·à¶ºà·à·à·à¶à·à· à·à·à·à·à¶ à¶à¶»à¶±à·à¶±"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à¶à·à¶»à·à¶º à¶à·à¶»à·à· à¶Žà·à¶±à·à·à¶±à·à¶±"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à·à·à¶à·à·à¶žà· à·à·à·à·à¶ à¶à¶»à¶±à·à¶±"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"à·à·à·à¶ºà¶ à·à·à·à·à¶ à¶à¶»à¶±à·à¶±"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"à¶à·à¶»à¶º à¶
à¶à·à·
෠දඞනà·à¶±"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS à·à·à¶ à·à¶à·à¶žà¶±à· යà·à¶¯à·à¶ž à·à¶žà¶ à¶¶à·à¶¯à·à¶žà· à¶à·à¶»à¶ºà¶§ à¶à¶à·à·
à· à·à¶±à·à¶±"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS à·à·à¶ à·à¶à·à¶žà¶±à· යà·à¶¯à·à¶ž à·à¶žà¶ à¶¶à·à¶¯à·à¶žà· à¶à·à¶»à¶ºà¶§ à¶à¶à·à·
à· à·à¶±à·à¶±"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à¶¶à·à¶¯à·à¶žà· à¶à·à¶»à¶ºà· à·à·à¶§ à¶Žà·à¶»à·à¶« à¶à·à¶»à¶ºà¶§ à¶žà·à¶»à· à·à¶±à·à¶±"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à¶¶à·à¶¯à·à¶žà· à¶à·à¶»à¶º à¶
à¶à¶»à¶à·à¶»: යà·à¶¯à·à¶žà¶à· à¶à¶à¶à·à¶±à· à¶à·à¶à· à¶à¶à¶à· à¶Žà·à¶»à¶à·à·à·à¶®à·à¶Žà¶±à¶º à¶à¶»à¶±à·à¶±"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à¶à¶¯à·à¶±à¶º"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à¶žà·à·
à¶ à¶·à·à·à·à·à¶§ à¶žà·à¶»à· à·à¶±à·à¶±"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à¶à·à¶žà¶»à·à· à¶
à·à·à·à¶»à¶ºà·"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à¶à·à¶žà¶»à·à· à·à· ඞයà·à¶à·à¶»à·à·à·à¶±à¶º à¶
à·à·à·à¶»à¶ºà·"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ඞයà·à¶à·à¶»à·à·à·à¶±à¶º à¶
à·à·à·à¶»à¶ºà·"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"à¶¶à·à¶°à· à¶±à·à¶à¶»à¶±à·à¶±"</string>
<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>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 21a0122..7722736 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Vytváranie snímok obrazovky zablokoval váš správca IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Upraviť"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"UpraviÅ¥ snímku obrazovky"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ZdieÄŸaÅ¥ snímku obrazovky"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zachytiť viac"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ZavrieÅ¥ snímku obrazovky"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Toto zariadenie spravuje tvoj rodiÄ. Vidí a môÅŸe spravovaÅ¥ informácie, napríklad aplikácie, ktoré pouÅŸívaš, tvoju polohu a Äas pouÅŸívania."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odomknutie udrÅŸiava TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ochrana pred krádeÅŸou\nUzamknuté, priveÄŸa pokusov o odomknutie"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Nastavenia zvuku"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatické titulkovanie médií"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"VypnúÅ¥ zvuk"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Prenos"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, pretoÅŸe je vypnuté zvonenie"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nedostupné, pretoÅŸe je zapnutý reÅŸim bez vyrušení"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nedostupné, pretoÅŸe je zapnutý reÅŸim bez vyrušení"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnite zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujte reÅŸim vibrovania. SluÅŸby dostupnosti je moÅŸné stlmiÅ¥."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. SluÅŸby dostupnosti je moÅŸné stlmiÅ¥."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Ovládacie prvky hlasitosti %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Hovory a upozornenia spustia zvonenie (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ZadaÅ¥ nastavenia výstupu"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"PosúvaÄe hlasitosti sú rozbalené"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"PosúvaÄe hlasitosti sú zbalené"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"vypnete zvuk %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"zapnete zvuk %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> sa prehráva v:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk sa prehrá v:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Tuner pouÅŸívateÄŸského rozhrania systému"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Cyklické prechádzanie dopredu po nedávnych aplikáciách"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Cyklické prechádzanie dozadu po nedávnych aplikáciách"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvorenie zoznamu aplikácií"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Zobrazenie panela aplikácií"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvorenie nastavení"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvorenie Asistenta"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ZamknúÅ¥ obrazovku"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Rozdelenie obrazovky s aktuálnou aplikáciou vpravo"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Rozdelenie obrazovky s aktuálnou aplikáciou vÄŸavo"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Prepnutie rozdelenej obrazovky na celú"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"PoÄas rozdelenej obrazovky: nahradenie aplikácie inou"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vstup"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Prepnutie na Äalší jazyk"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokovaná"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofón je blokovaný"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ReÅŸim bez vyrušení"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Bola rozpoznaná prítomnosÅ¥ pouÅŸívateÄŸa"</string>
<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>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 06774ed..cbf5512 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Skrbnik za IT je onemogoÄil zajemanje posnetkov zaslona."</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Urejanje posnetka zaslona"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Deljenje posnetka zaslona"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zajemi veÄ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Opusti posnetek zaslona"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"To napravo upravlja tvoj starš. Lahko si ogleda in upravlja podatke, na primer katere aplikacije uporabljaš, tvojo lokacijo in koliko Äasa uporabljaš napravo."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ohranja odklenjeno"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ZašÄita pred krajo\nNaprava je zaklenjena, preveÄ poskusov odklepanja"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Naprava se je zaklenila, preveÄ poskusov preverjanja pristnosti"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Naprava se je zaklenila\nPreverjanje pristnosti ni uspelo"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Nastavitve zvoka"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Sam. podnapisi predstavnosti"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Utišano"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Predvajanje"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ni na voljo, ker je zvonjenje izklopljeno"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ni na voljo, ker je vklopljen naÄin »Ne moti«"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ni na voljo, ker je vklopljen naÄin »Ne moti«"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dotaknite se, Äe ÅŸelite vklopiti zvok."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dotaknite se, Äe ÅŸelite nastaviti vibriranje. V storitvah za dostopnost bo morda izklopljen zvok."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, Äe ÅŸelite izklopiti zvok. V storitvah za dostopnost bo morda izklopljen zvok."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Kontrolniki glasnosti za %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Klici in obvestila bodo pozvonili (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Vnos izhodnih nastavitev"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Razširitev drsnikov za glasnost"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Strnitev drsnikov za glasnost"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"izklop zvoka %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"vklop zvoka %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Predvajanje »<xliff:g id="LABEL">%s</xliff:g>« v"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvok bo predvajan v"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Uglaševalnik uporabniškega vmesnika sistema"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Pomikanje naprej po nedavnih aplikacijah"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Pomikanje nazaj po nedavnih aplikacijah"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Odpiranje seznama aplikacij"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Prikaz opravilne vrstice"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Odpiranje nastavitev"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Odpiranje PomoÄnika"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Zaklepanje zaslona"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Vklop razdeljenega zaslona s trenutno aplikacijo na desni"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Vklop razdeljenega zaslona s trenutno aplikacijo na levi"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Preklop iz razdeljenega zaslona v celozaslonski naÄin"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Pri razdeljenem zaslonu: medsebojna zamenjava aplikacij"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vnosna naprava"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Preklop na naslednji jezik"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparat je blokiran."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparat in mikrofon sta blokirana."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran."</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ne moti"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Zaznana je prisotnost uporabnika"</string>
<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>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b541c47e..ac5955b 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Shkrepja e pamjeve të ekranit është bllokuar nga administratori i teknologjisë së informacionit"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Modifiko"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Modifiko pamjen e ekranit"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Ndaj pamjen e ekranit"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Regjistro më shumë"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hiq pamjen e ekranit"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Kjo pajisje menaxhohet nga prindi yt. Prindi yt mund të shikojë dhe menaxhojë informacionet, si p.sh. aplikacionet që përdor, vendndodhjen tënde dhe kohën para ekranit."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mbajtur shkyçur nga TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Mbrojtje nga vjedhja\nPajisja u kyç. Shumë përpjekje shkyçjeje"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Cilësimet e zërit"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Media me titra automatike"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Pa zë"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Transmeto"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Nuk ofrohet; ziles i është hequr zëri"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Nuk ofrohet sepse \"Mos shqetëso\" është aktiv"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Nuk ofrohet sepse \"Mos shqetëso\" është aktiv"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trokit për të aktivizuar."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Kontrollet e volumit %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Do të bjerë zilja për telefonatat dhe njoftimet (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Hyr te cilësimet e daljes"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Rrëshqitësit e volumit u zgjeruan"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Rrëshqitësit e volumit u palosën"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"çaktivizo audion: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"aktivizo audion: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Po luhet <xliff:g id="LABEL">%s</xliff:g> në"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Do të luhet audio në"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Lëviz përpara përmes aplikacioneve të fundit"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Lëviz prapa përmes aplikacioneve të fundit"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Hap listën e aplikacioneve"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Shfaq shiritin e detyrave"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Hap cilësimet"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Hap \"Asistentin\""</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ekrani i kyçjes"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Hyr në ekranin e ndarë me aplikacionin aktual në anën e djathtë"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Hyr në ekranin e ndarë me aplikacionin aktual në anën e majtë"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Kalo nga ekrani i ndarë në ekranin e plotë"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Gjatë ekranit të ndarë: zëvendëso një aplikacion me një tjetër"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Hyrja"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Kalo te gjuha tjetër"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera u bllokua"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dhe mikrofoni u bllokuan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni u bllokua"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Mos shqetëso"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Është zbuluar prania e përdoruesit"</string>
<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>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3ae30b5..085f1b0 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ÐТ аЎЌОМОÑÑÑаÑÐŸÑ Ð±Ð»ÐŸÐºÐžÑа пÑавÑеÑе ÑМОЌака екÑаМа"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ÐзЌеМО"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ÐзЌеМОÑе ÑМОЌак екÑаМа"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÐелОÑе ÑМОЌак екÑаМа"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"СМОЌОÑе ÑПÑ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐЎбаÑОÑе ÑМОЌак екÑаМа"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÐвОЌ ÑÑеÑаÑеЌ ÑпÑавÑа ÑПЎОÑеÑ. РПЎОÑÐµÑ ÐŒÐŸÐ¶Ðµ Ўа вОЎО ОМÑПÑЌаÑОÑе, каП ÑÑП ÑÑ Ð°Ð¿Ð»ÐžÐºÐ°ÑОÑе кПÑе кПÑОÑÑОÑ, ÑвПÑÑ Ð»ÐŸÐºÐ°ÑОÑÑ Ðž вÑеЌе ОÑпÑеЎ екÑаМа, О Ўа ÑпÑавÑа ÑОЌа."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ÐПÑзЎаМО Ð°Ð³ÐµÐœÑ ÑпÑеÑава закÑÑÑаваÑе"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐаÑÑОÑа ПЎ кÑаÑе\nÐакÑ. ÑÑеÑаÑ, пÑевОÑе пПкÑÑаÑа ПÑкÑÑÑаваÑа"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"УÑеÑÐ°Ñ Ñе закÑÑÑаМ, пÑевОÑе пПкÑÑаÑа пПÑвÑЎе ОЎеМÑОÑеÑа"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"УÑеÑÐ°Ñ Ñе закÑÑÑаМ\nÐПÑвÑЎа ОЎеМÑОÑеÑа МОÑе ÑÑпела"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐПЎеÑаваÑа звÑка"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐÑÑПЌаÑÑкО ÑОÑл за ЌеЎОÑе"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"ÐÑкÑÑÑО звÑк"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ÐÑебаÑОваÑе"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÐеЎПÑÑÑпМП ÑÐµÑ Ñе звÑк ОÑкÑÑÑеМ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐеЎПÑÑÑпМП ÑÐµÑ Ñе ÑкÑÑÑеМ ÑежОЌ Ðе ÑзМеЌОÑаваÑ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐеЎПÑÑÑпМП ÑÐµÑ Ñе ÑкÑÑÑеМ ÑежОЌ Ðе ÑзМеЌОÑаваÑ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ÐПЎОÑМОÑе Ўа бОÑÑе ÑкÑÑÑОлО звÑк."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ÐПЎОÑМОÑе Ўа бОÑÑе пПЎеÑОлО Ма вОбÑаÑОÑÑ. ÐвÑк ÑÑлÑга пÑОÑÑÑпаÑМПÑÑО Ñе ЌПжЎа бОÑО ОÑкÑÑÑеМ."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ÐПЎОÑМОÑе Ўа бОÑÑе ОÑкÑÑÑОлО звÑк. ÐвÑк ÑÑлÑга пÑОÑÑÑпаÑМПÑÑО Ñе ЌПжЎа бОÑО ОÑкÑÑÑеМ."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вОбÑаÑОÑа"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"ÐПМÑÑПле за ÑаÑÐžÐœÑ Ð·Ð²Ñка за %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐелПЎОÑа звПМа за пПзОве О ПбавеÑÑеÑа Ñе ÑкÑÑÑеМа (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"УМеÑОÑе пПЎеÑаваÑа ОзлазМПг ÑОгМала"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐлОзаÑО за ÑаÑÐžÐœÑ Ð·Ð²Ñка ÑÑ Ð¿ÑПÑОÑеМО"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐлОзаÑО за ÑаÑÐžÐœÑ Ð·Ð²Ñка ÑÑ ÑкÑпÑеМО"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ОÑкÑÑÑОÑе звÑк за: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ÑкÑÑÑОÑе звÑк за: %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> Ñе пÑÑÑа Ма"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐвÑк Ñе пÑÑÑа Ма"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ТÑÑÐœÐµÑ Ð·Ð° кПÑОÑМОÑкО ОМÑеÑÑеÑÑ ÑОÑÑеЌа"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐÑÐµÐ³Ð»ÐµÐŽÐ°Ñ ÐœÐµÐŽÐ°Ð²ÐœÐŸ кПÑОÑÑеМе аплОкаÑОÑе ÑМапÑеЎ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐÑÐµÐ³Ð»ÐµÐŽÐ°Ñ ÐœÐµÐŽÐ°Ð²ÐœÐŸ кПÑОÑÑеМе аплОкаÑОÑе ÑМазаЎ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐÑвПÑО лОÑÑÑ Ð°Ð¿Ð»ÐžÐºÐ°ÑОÑа"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐÑОкажО ÑÑÐ°ÐºÑ Ð·Ð°ÐŽÐ°Ñака"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐÑвПÑО пПЎеÑаваÑа"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑвПÑО пПЌПÑМОка"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐакÑÑÑаваÑе екÑаМа"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"ÐПкÑеМО пПЎеÑеМО екÑаМ за акÑÑÐµÐ»ÐœÑ Ð°Ð¿Ð»ÐžÐºÐ°ÑОÑÑ ÐœÐ° ЎеÑÐœÐŸÑ ÑÑÑаМО"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"ÐПкÑеМО пПЎеÑеМО екÑаМ за акÑÑÐµÐ»ÐœÑ Ð°Ð¿Ð»ÐžÐºÐ°ÑОÑÑ ÐœÐ° Ð»ÐµÐ²ÐŸÑ ÑÑÑаМО"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐÑеÑО Ñа пПЎеÑеМПг екÑаМа Ма ÑеП екÑаМ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"У ÑÐµÐ¶ÐžÐŒÑ Ð¿ÐŸÐŽÐµÑеМПг екÑаМа: заЌеМа ÑеЎМе аплОкаÑОÑе ÐŽÑÑгПЌ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"УМПÑ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐÑеÑО Ма ÑлеЎеÑО ÑезОк"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑа Ñе блПкОÑаМа"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑа О ЌОкÑПÑПМ ÑÑ Ð±Ð»ÐŸÐºÐžÑаМО"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐОкÑПÑПМ Ñе блПкОÑаМ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе ÑзМеЌОÑаваÑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e8f0d2c..854e547 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Möjligheten att ta skärmbilder blockeras av IT-administratören"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Redigera"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Redigera skärmbild"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Dela skärmbild"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Fånga mer"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Stäng skärmbild"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Den här enheten hanteras av din förälder. Föräldern kan se och hantera information som vilka appar du använder, din plats och din skärmtid."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Hålls olåst med TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Stöldskydd\nEnheten har låsts på grund av för många försök"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ljudinställningar"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Texta media automatiskt"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Dölj"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Casta"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Otillgängligt eftersom ringljudet är av"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Inte tillgängligt eftersom Stör ej är aktiverat"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Inte tillgängligt eftersom Stör ej är aktiverat"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryck här om du vill slå på ljudet."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Volymkontroller för %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Ringsignal används för samtal och aviseringar (volym: <xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ange inställningar för utdata"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volymreglagen har utökats"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volymreglagen har komprimerats"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"stäng av ljudet för %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå på ljudet för %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Spelar upp <xliff:g id="LABEL">%s</xliff:g> på"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ljud spelas upp på"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Inställningar för systemgränssnitt"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Bläddra framåt bland de senaste apparna"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Bläddra bakåt bland de senaste apparna"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Öppna applistan"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Se aktivitetsfält"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Öppna inställningarna"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Öppna assistenten"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skärmen"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Öppna delad skärm med aktuell app till höger"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Öppna delad skärm med aktuell app till vänster"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Byt mellan delad skärm och helskärm"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Med delad skärm: ersätt en app med en annan"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Inmatning"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Byt till nästa språk"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameran är blockerad"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameran och mikrofonen är blockerade"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen är blockerad"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Stör ej"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Användarnärvaro har upptäckts"</string>
<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>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 19685b1..9dc17ab 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Kupiga picha za skrini kumezuiwa na Msimamizi wako wa TEHAMA"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Badilisha"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Badilisha picha ya skrini"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Shiriki picha ya skrini"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Nasa zaidi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ondoa picha ya skrini"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Kifaa hiki kinadhibitiwa na mzazi wako. Mzazi wako anaweza kuona na kudhibiti maelezo kama vile programu unazotumia, mahali ulipo na muda unaotumia kwenye kifaa."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Imefunguliwa na kipengele cha kutathmini hali ya kuaminika"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Kifaa cha ulinzi\ndhidi ya wizi kimefungwa, kuna majaribio mengi mno ya kukifungua"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Mipangilio ya sauti"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Wekea maudhui manukuu kiotomatiki"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Zima sauti"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Tuma"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Halipatikani kwa sababu sauti imezimwa"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Imeshindwa kwa sababu Usinisumbue imewashwa"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Imeshindwa kwa sababu Usinisumbue imewashwa"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Gusa ili urejeshe."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Gusa ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Vidhibiti %s vya sauti"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Itatoa mlio arifa ikitumwa na simu ikipigwa (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Weka mipangilio ya sauti inayotoka"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Vitelezi vya sauti vimepanuliwa"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Vitelezi vya kiwango cha sauti vimekunjwa"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"zima sauti ya %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"rejesha sauti ya %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Inacheza <xliff:g id="LABEL">%s</xliff:g> kwenye"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Sauti itacheza kwenye"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Kirekebishi cha kiolesura cha mfumo"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Nenda mbele kwenye programu ulizofungua awali"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Rudi nyuma kwenye programu ulizofungua awali"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Fungua orodha ya programu"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Onyesha upauzana"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Fungua mipangilio"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Fungua programu ya Mratibu wa Google"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Funga skrini"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Tumia programu kwenye skrini iliyogawanywa upande wa kulia"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Tumia programu kwenye skrini iliyogawanywa upande wa kushoto"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Badilisha kutoka skrini iliyogawanywa utumie skrini nzima"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ukigawanya skrini: badilisha kutoka programu moja hadi nyingine"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vifaa vya kuingiza data"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Badilisha utumie lugha inayofuata"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Usinisumbue"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Imetambua uwepo wa mtumiaji"</string>
<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>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 742e88f..5d6b131 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"ஞà¯à®à®¿à®°à¯à®©à¯à®·à®Ÿà®à¯à®à®³à¯ à®à®à¯à®ªà¯à®ªà®€à¯ à®à®à¯à®à®³à¯ IT சிரà¯à®µà®Ÿà®à®¿ ஀à®à¯à®à¯à®¯à¯à®€à¯à®³à¯à®³à®Ÿà®°à¯"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"஀ிரà¯à®€à¯à®€à¯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ஞà¯à®à®¿à®°à¯à®©à¯à®·à®Ÿà®à¯à®à¯à®€à¯ ஀ிரà¯à®€à¯à®€à¯à®®à¯"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ஞà¯à®à®¿à®°à¯à®©à¯à®·à®Ÿà®à¯à®à¯à®ªà¯ பà®à®¿à®°à¯"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"à®à¯à®à¯à®€à®²à®Ÿà® பà®à®®à¯à®à¯"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ஞà¯à®à®¿à®°à¯à®©à¯à®·à®Ÿà®à¯à®à¯ சிரடà®à®°à®¿à®à¯à®à¯à®®à¯"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"à®à®šà¯à®€à®à¯ à®à®Ÿà®€à®©à®®à¯ à®à®à¯à®à®³à¯ பà¯à®±à¯à®±à¯à®°à®Ÿà®²à¯ சிரà¯à®µà®à®¿à®à¯à®à®ªà¯à®ªà®à¯à®à®¿à®±à®€à¯. சà¯à®à¯à®à®³à¯ பயனà¯à®ªà®à¯à®€à¯à®€à¯à®®à¯ à®à®ªà¯à®žà¯, à®à®°à¯à®ªà¯à®ªà®¿à®à®®à¯, பயனà¯à®ªà®à¯à®€à¯à®€à®¿à®¯ சà¯à®°à®®à¯ à®à®à®¿à®¯à®µà®±à¯à®±à¯à®ªà¯ படரà¯à®à¯à®à®µà¯à®®à¯ சிரà¯à®µà®à®¿à®à¯à®à®µà¯à®®à¯ à®à®à¯à®à®³à¯ பà¯à®±à¯à®±à¯à®°à®Ÿà®²à¯ à®®à¯à®à®¿à®¯à¯à®®à¯."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à®à®€à¯à®€à¯ ஀ிறசà¯à®€à¯ வà¯à®€à¯à®€à¯à®³à¯à®³à®€à¯"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"஀ிரà¯à®à¯à®à¯à®€à¯ ஀à®à¯à®à¯à®\nà®à®Ÿà®€à®©à®®à¯ பà¯à®à¯à®à®ªà¯à®ªà®à¯à®à®€à¯, à®
஀ிà®à®®à®Ÿà®© à®
னà¯à®²à®Ÿà®à¯ à®®à¯à®¯à®±à¯à®à®¿à®à®³à¯"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"à®
ளவà¯à®à¯à®à®€à®¿à®à®®à®Ÿà®© à®
à®à¯à®à¯à®à®°à®¿à®ªà¯à®ªà¯ à®®à¯à®¯à®±à¯à®à®¿à®à®³à®Ÿà®²à¯ à®à®Ÿà®€à®©à®®à¯ பà¯à®à¯à®à®ªà¯à®ªà®à¯à®à®€à¯"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"à®à®Ÿà®€à®©à®®à¯ பà¯à®à¯à®à®ªà¯à®ªà®à¯à®à®€à¯\nà®
à®à¯à®à¯à®à®°à®¿à®à¯à® à®®à¯à®à®¿à®¯à®µà®¿à®²à¯à®²à¯"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à®à®²à®¿ à®
à®®à¯à®ªà¯à®ªà¯à®à®³à¯"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"வà®à®© à®à®°à¯à®à®³à¯à®€à¯ ஀டனட஠à®à®Žà¯à®€à¯à®®à¯"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à®
à®®à¯à®€à®¿"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à®
லà¯à®ªà®°à®ªà¯à®ªà¯"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"\'ரிà®à¯\' மியà¯à®à¯à®à®¿à®²à¯ à®à®³à¯à®³à®€à®Ÿà®²à¯ à®à®¿à®à¯à®à¯à®à®µà®¿à®²à¯à®²à¯"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"\'஀à¯à®šà¯à®€à®°à®µà¯ à®à¯à®¯à¯à®¯ வà¯à®£à¯à®à®Ÿà®®à¯\' à®à®©à®¿à®²à¯ à®à®°à¯à®ªà¯à®ªà®€à®Ÿà®²à¯ à®à®²à¯à®²à¯"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"\'஀à¯à®šà¯à®€à®°à®µà¯ à®à¯à®¯à¯à®¯ வà¯à®£à¯à®à®Ÿà®®à¯\' à®à®©à®¿à®²à¯ à®à®°à¯à®ªà¯à®ªà®€à®Ÿà®²à¯ à®à®²à¯à®²à¯"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à®à®²à®¿ à®à®¯à®à¯à®, ஀à®à¯à®à®µà¯à®®à¯."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à®
஀ிரà¯à®µà®¿à®±à¯à®à¯ à®
à®®à¯à®à¯à®, ஀à®à¯à®à®µà¯à®®à¯. à®
ணà¯à®à®²à¯à®€à®©à¯à®®à¯ à®à¯à®µà¯à®à®³à¯ à®à®²à®¿à®¯à®à®à¯à®à®ªà¯à®ªà®à®à¯à®à¯à®à¯à®®à¯."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à®à®²à®¿à®¯à®à®à¯à®, ஀à®à¯à®à®µà¯à®®à¯. à®
ணà¯à®à®²à¯à®€à®©à¯à®®à¯ à®à¯à®µà¯à®à®³à¯ à®à®²à®¿à®¯à®à®à¯à®à®ªà¯à®ªà®à®à¯à®à¯à®à¯à®®à¯."</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à®
஀ிரà¯à®µà¯à®±à¯à®®à¯"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s à®à®²à®¿à®¯à®³à®µà¯à®à¯ à®à®à¯à®à¯à®ªà¯à®ªà®Ÿà®à¯à®à®³à¯"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à®
எà¯à®ªà¯à®ªà¯à®à®³à¯à®®à¯ à®
றிவிபà¯à®ªà¯à®à®³à¯à®®à¯ வரà¯à®®à¯à®ªà¯à®€à¯ à®à®²à®¿à®à¯à®à®à¯ à®à¯à®¯à¯à®¯à¯à®®à¯ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"வà¯à®³à®¿à®¯à¯à®à¯à®à¯ à®
à®®à¯à®ªà¯à®ªà¯à®à®³à¯à®à¯à®à¯à®à¯ à®à¯à®²à¯à®²à¯à®®à¯"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"à®à®²à®¿à®¯à®³à®µà¯ ஞà¯à®²à¯à®à®°à¯à®à®³à¯ விரிவடà®à¯à®à®ªà¯à®ªà®à¯à®à®©"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"à®à®²à®¿à®¯à®³à®µà¯ ஞà¯à®²à¯à®à®°à¯à®à®³à¯ à®à¯à®°à¯à®à¯à®à®ªà¯à®ªà®à¯à®à®©"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s à® à®à®²à®¿à®¯à®à®à¯à®à¯à®®à¯"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s à® à®à®²à®¿ à®à®¯à®à¯à®à¯à®®à¯"</string>
<string name="media_output_label_title" msgid="872824698593182505">"à®à®€à®¿à®²à¯ <xliff:g id="LABEL">%s</xliff:g> பிள௠à®à®à®¿à®±à®€à¯"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à®à®²à¯ à®à®à®¿à®¯à¯ பிள௠à®à®à¯à®®à¯"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à®à®®à¯à®ªà®€à¯à®€à®¿à®¯ à®à®ªà¯à®žà¯à®à¯à®à¯ à®®à¯à®©à¯à®©à¯à®à¯à®à®¿à®à¯ à®à¯à®²à¯à®²à¯à®€à®²à¯"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à®à®®à¯à®ªà®€à¯à®€à®¿à®¯ à®à®ªà¯à®žà¯à®à¯à®à¯à®ªà¯ பினà¯à®©à¯à®à¯à®à®¿à®à¯ à®à¯à®²à¯à®²à¯à®€à®²à¯"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à®à®ªà¯à®žà¯ பà®à¯à®à®¿à®¯à®²à¯à®€à¯ ஀ிற஀à¯à®€à®²à¯"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à®à¯à®¯à®²à¯ பà®à¯à®à®¿à®¯à¯à®à¯ à®à®Ÿà®à¯à®à¯à®€à®²à¯"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à®
à®®à¯à®ªà¯à®ªà¯à®à®³à¯à®€à¯ ஀ிற஀à¯à®€à®²à¯"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistantà®à¯à®€à¯ ஀ிற஀à¯à®€à®²à¯"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"பà¯à®à¯à®à¯à®€à¯ ஀ிரà¯"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"வல஀à¯à®ªà¯à®±à®€à¯à®€à®¿à®²à¯ ஀றà¯à®ªà¯à®€à¯à®¯ à®à®ªà¯à®žà¯ ஀à¯à®©à¯à®±à¯à®®à®Ÿà®±à¯ ஀ிரà¯à®ªà¯ பிரிபà¯à®ªà¯ à®
à®®à¯à®€à¯à®€à®²à¯"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à®à®à®€à¯à®ªà¯à®±à®€à¯à®€à®¿à®²à¯ ஀றà¯à®ªà¯à®€à¯à®¯ à®à®ªà¯à®žà¯ ஀à¯à®©à¯à®±à¯à®®à®Ÿà®±à¯ ஀ிரà¯à®ªà¯ பிரிபà¯à®ªà¯ à®
à®®à¯à®€à¯à®€à®²à¯"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"஀ிரà¯à®ªà¯ பிரிபà¯à®ªà¯ பயனà¯à®®à¯à®±à¯à®¯à®¿à®²à®¿à®°à¯à®šà¯à®€à¯ à®®à¯à®Žà¯à®€à¯à®€à®¿à®°à¯à®à¯à®à¯ மடறà¯à®±à¯à®€à®²à¯"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"஀ிரà¯à®ªà¯ பிரிபà¯à®ªà®¿à®©à¯à®ªà¯à®€à¯: à®à®°à¯ à®à®ªà¯à®žà¯à®à¯à®à¯à®ªà¯ ப஀ிலட஠மறà¯à®±à¯à®©à¯à®±à¯ மடறà¯à®±à¯à®€à®²à¯"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à®à®³à¯à®³à¯à®à¯"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à®
à®à¯à®€à¯à®€ à®®à¯à®Žà®¿à®à¯à®à¯ மடறà¯à®±à¯à®€à®²à¯"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à®à¯à®®à®°à®Ÿ ஀à®à¯à®à¯à®à®ªà¯à®ªà®à¯à®à¯à®³à¯à®³à®€à¯"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à®à¯à®®à®°à®Ÿà®µà¯à®®à¯ à®®à¯à®à¯à®°à¯à®à®ªà¯à®©à¯à®®à¯ ஀à®à¯à®à¯à®à®ªà¯à®ªà®à¯à®à¯à®³à¯à®³à®©"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à®®à¯à®à¯à®°à¯à®à®ªà¯à®©à¯ ஀à®à¯à®à¯à®à®ªà¯à®ªà®à¯à®à¯à®³à¯à®³à®€à¯"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"஀à¯à®šà¯à®€à®°à®µà¯ à®à¯à®¯à¯à®¯ வà¯à®£à¯à®à®Ÿà®®à¯"</string>
<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>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 0ec2a0e..5c5d828 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"à°žà±à°à±à°°à±à°šà±à°·à°Ÿà°à±à°²à± à°€à±à°¯à°¡à°Ÿà°šà±à°šà°¿ మౠIT à°
à°¡à±à°®à°¿à°šà± à°¬à±à°²à°Ÿà°à± à°à±à°¶à°Ÿà°°à±"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à°à°¡à°¿à°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à°žà±à°à±à°°à±à°šà±à°·à°Ÿà°à±à°šà± à°à°¡à°¿à°à± à°à±à°¯à°à°¡à°¿"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à°žà±à°à±à°°à±à°šà±à°·à°Ÿà°à±à°šà± à°·à±à°°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"మరిచà±à°šà°¿ à°à±à°¯à°Ÿà°ªà±à°à°°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"à°žà±à°à±à°°à±à°šà±à°·à°Ÿà°à±à°šà± విఞà±à°®à°°à°¿à°à°à±"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఠపరిà°à°°à°Ÿà°šà±à°šà°¿ మౠఀలà±à°²à°¿/à°€à°à°¡à±à°°à°¿ à°®à±à°šà±à°à± à°à±à°žà±à°€à±à°šà±à°šà°Ÿà°°à±. మౠఀలà±à°²à°¿/à°€à°à°¡à±à°°à°¿, à°®à±à°°à± à°à°ªà°¯à±à°à°¿à°à°à± యటపà±à°²à±, మౠలà±à°à±à°·à°šà±, à°
లటà°à± మౠపరిà°à°° విచియà±à° à°µà±à°¯à°µà°§à°¿ à°µà°à°à°¿ ఞమటà°à°Ÿà°°à°Ÿà°šà±à°šà°¿ à°à±à°¡à°à°²à°°à±, à°®à±à°šà±à°à± à°à±à°¯à°à°²à°°à±."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent à°Šà±à°µà°Ÿà°°à°Ÿ à°
à°šà±à°²à°Ÿà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"à°Šà±à°à°à°€à°šà° à°à±à°¯à°¡à° à°šà±à°à°¡à°¿ à°°à°à±à°·à°£\nపరిà°à°°à° లటà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿, à°à°Ÿà°²à°Ÿ à°à°à±à°à±à°µ à°
à°šà±à°²à°Ÿà°à± à°ªà±à°°à°¯à°€à±à°šà°Ÿà°²à± à°à°°à°¿à°à°Ÿà°¯à°¿"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"à°§à±à°µà°šà°¿ à°žà±à°à±à°à°¿à°à°à±à°²à±"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à°®à±à°¡à°¿à°¯à°Ÿà°à± à°à°à±à°®à±à°à°¿à°à± à°à±à°¯à°Ÿà°ªà±à°·à°šà±à°²à±"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"à°®à±à°¯à±à°à±"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à°ªà±à°°à°žà°Ÿà°°à° à°à±à°¯à°à°¡à°¿"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"వటలà±à°¯à±à°®à± à°®à±à°¯à±à°à± à°
యిచà°à°Šà±à°š à°
à°à°Šà±à°¬à°Ÿà°à±à°²à± à°²à±à°Šà±"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à°
à°à°€à°°à°Ÿà°¯à°à°à°²à°¿à°à°¿à°à°à°µà°Šà±à°Šà± à°à°šà±à°²à± à°à°šà±à°šà°à°Šà±à°š à°
à°à°Šà±à°¬à°Ÿà°à±à°²à±à°²à±à°Šà±"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à°
à°à°€à°°à°Ÿà°¯à°à°à°²à°¿à°à°¿à°à°à°µà°Šà±à°Šà± à°à°šà±à°²à± à°à°šà±à°šà°à°Šà±à°š à°
à°à°Šà±à°¬à°Ÿà°à±à°²à±à°²à±à°Šà±"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. à°
à°šà±à°®à±à°¯à±à°à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ à°šà±à°à±à°à°à°¡à°¿."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. à°µà±à°¬à±à°°à±à°·à°šà±à°à± à°žà±à°à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ à°šà±à°à±à°à°à°¡à°¿. యటà°à±à°žà±à°žà± ఞటమరà±à°¥à±à°¯ à°žà±à°µà°²à± à°®à±à°¯à±à°à± à°à±à°¯à°¬à°¡à°µà°à±à°à±."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. à°®à±à°¯à±à°à± à°à±à°¯à°¡à°Ÿà°šà°¿à°à°¿ à°šà±à°à±à°à°à°¡à°¿. యటà°à±à°žà±à°žà± ఞటమరà±à°¥à±à°¯ à°žà±à°µà°²à± à°®à±à°¯à±à°à± à°à±à°¯à°¬à°¡à°µà°à±à°à±."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"à°µà±à°¬à±à°°à±à°à±"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s వటలà±à°¯à±à°®à± à°šà°¿à°¯à°à°€à±à°°à°£à°²à±"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"à°à°Ÿà°²à±à°žà± మరియౠచà±à°à°¿à°«à°¿à°à±à°·à°šà±à°²à± à°°à°¿à°à°à± à°
à°µà±à°€à°Ÿà°¯à°¿ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à°
à°µà±à°à±à°ªà±à°à± à°žà±à°à±à°à°¿à°à°à±à°²à°šà± à°à°à°à°°à± à°à±à°¯à°à°¡à°¿"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"వటలà±à°¯à±à°®à± à°žà±à°²à°¯à°¿à°¡à°°à±à°²à± విఞà±à°€à°°à°¿à°à°à°¬à°¡à±à°¡à°Ÿà°¯à°¿"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"వటలà±à°¯à±à°®à± à°žà±à°²à°¯à°¿à°¡à°°à±à°²à± à°à±à°Šà°¿à°à°à°¬à°¡à±à°¡à°Ÿà°¯à°¿"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sà°šà± à°®à±à°¯à±à°à± à°à±à°¯à°à°¡à°¿"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sà°šà± à°
à°šà±à°®à±à°¯à±à°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>లౠపà±à°²à± à°
à°µà±à°€à±à°à°Šà°¿"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à°à°¡à°¿à°¯à± à°ªà±à°²à± à°
à°µà±à°€à±à°à°Šà°¿"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"à°žà°¿à°žà±à°à°®à± UI à°à±à°¯à±à°šà°°à±"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"à°à°à±à°µà°² à°à°ªà°¯à±à°à°¿à°à°à°¿à°š యటపà±à°² ఀఊà±à°ªà°°à°¿ à°ªà±à°à±à°à°¿ à°µà±à°³à±à°²à°à°¡à°¿"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"à°à°à±à°µà°² à°à°ªà°¯à±à°à°¿à°à°à°¿à°š యటపà±à°² à°®à±à°šà±à°ªà°à°¿ à°ªà±à°à±à°à°¿ à°µà±à°³à±à°²à°à°¡à°¿"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"యటపà±à°² లిఞà±à°à±à°šà± à°€à±à°°à°µà°à°¡à°¿"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à°à°Ÿà°žà±à°à±à°¬à°Ÿà°°à±à°šà± à°à±à°ªà°à°¡à°¿"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à°žà±à°à±à°à°¿à°à°à±à°²à°šà± à°€à±à°°à°µà°à°¡à°¿"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"à°
à°žà°¿à°žà±à°à±à°à°à±à°šà± à°€à±à°°à°µà°à°¡à°¿"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"లటà°à± à°žà±à°à±à°°à±à°šà±"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"RHSà°à± à°ªà±à°°à°žà±à°€à±à°€ యటపà±à°€à± à°žà±à°ªà±à°²à°¿à°à± à°žà±à°à±à°°à±à°šà±à°šà± à°à°à°à°°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"LHSà°à± à°ªà±à°°à°žà±à°€à±à°€ యటపà±à°€à± à°žà±à°ªà±à°²à°¿à°à± à°žà±à°à±à°°à±à°šà±à°šà± à°à°à°à°°à± à°à±à°¯à°à°¡à°¿"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à°žà±à°ªà±à°²à°¿à°à± à°žà±à°à±à°°à±à°šà±à°šà± à°«à±à°²à± à°žà±à°à±à°°à±à°šà±à°à± మటరà±à°à°à°¡à°¿"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"à°žà±à°ªà±à°²à°¿à°à± à°žà±à°à±à°°à±à°šà± ఞమయà°à°²à±: à°à° à°Šà°Ÿà°šà±à°šà±à°à°¡à°¿ మరౠఊటచిà°à°¿ యటపౠరà±à°ªà±à°²à±à°žà± à°à±à°¯à°à°¡à°¿"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"à°à°šà±à°ªà±à°à±"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ఀరà±à°µà°Ÿà°€ à°à°Ÿà°·à°à± à°žà±à°µà°¿à°à± à°
à°µà±à°µà°à°¡à°¿"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"à°à±à°®à±à°°à°Ÿ à°¬à±à°²à°Ÿà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"à°à±à°®à±à°°à°Ÿ, à°®à±à°à±à°°à±à°«à±à°šà± à°¬à±à°²à°Ÿà°à± à°à±à°¯à°¬à°¡à±à°¡à°Ÿà°¯à°¿"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à°®à±à°à±à°°à±à°«à±à°šà± à°¬à±à°²à°Ÿà°à± à°à±à°¯à°¬à°¡à°¿à°à°Šà°¿"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"à°
à°à°€à°°à°Ÿà°¯à° à°à°²à°¿à°à°¿à°à°à°µà°Šà±à°Šà±"</string>
<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>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 835c5bb..90074372 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"àžàž²àž£àžàž±àžàž àž²àžàž«àžà¹àž²àžàžàžàž¹àžàžàž¥à¹àžàžà¹àžàž¢àžàž¹à¹àžàž¹à¹àž¥àž£àž°àžàžà¹àžàžàžµàžàžàžàžàžžàž"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"à¹àžà¹à¹àž"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"à¹àžà¹à¹àžàž àž²àžàž«àžà¹àž²àžàž"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"à¹àžàž£à¹àž àž²àžàž«àžà¹àž²àžàž"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"àžàž±àžàž àž²àžà¹àžà¹àž¡àž²àžàžàž¶à¹àž"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"àžàžŽàžàž àž²àžàž«àžà¹àž²àžàž"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"àžàžžàžàžàž£àžà¹àžàžµà¹àžàž±àžàžàž²àž£à¹àžàž¢àžàž¹à¹àžàžàžàž£àžàž àžàž¹à¹àžàžàžàž£àžàžàžàž°àžàž¹à¹àž¥àž°àžàž±àžàžàž²àž£àžà¹àžàž¡àž¹àž¥àžà¹àž²àžà¹ à¹àžà¹ à¹àžà¹àž à¹àžàžàžàžµà¹àžàžžàžà¹àžà¹ àžàž³à¹àž«àžà¹àžàžàžàžàžàžžàž à¹àž¥àž°à¹àž§àž¥àž²àžàž¢àž¹à¹àž«àžà¹àž²àžàž"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"àžàž¥àžàž¥à¹àžàžà¹àž§à¹à¹àžàž¢ TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"àžàž²àž£àžà¹àžàžàžàž±àžàžàž²àž£à¹àžàž£àžàž£àž£àž¡\nàžàžžàžàžàž£àžà¹àžàž¹àžàž¥à¹àžàž àž¥àžàžàžàž¥àžàž¥à¹àžàžàž«àž¥àž²àž¢àžàž£àž±à¹àžà¹àžàžŽàžà¹àž"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"àž¥à¹àžàžàžàžžàžàžàž£àžà¹à¹àž¥à¹àž§ à¹àžàž·à¹àžàžàžàž²àžàžàž£àž§àžàžªàžàžàžªàžŽàžàžàžŽà¹àž«àž¥àž²àž¢àžàž£àž±à¹àžà¹àžàžŽàžà¹àž"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"àž¥à¹àžàžàžàžžàžàžàž£àžà¹à¹àž¥à¹àž§\nàžàž²àž£àžàž£àž§àžàžªàžàžàžªàžŽàžàžàžŽà¹à¹àž¡à¹àžªàž³à¹àž£à¹àž"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g> <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"àžàž²àž£àžàž±à¹àžàžà¹àž²à¹àžªàžµàž¢àž"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"à¹àžªàžàžàžàž³àžàž£àž£àž¢àž²àž¢àžªàž·à¹àžà¹àžàž¢àžàž±àžà¹àžàž¡àž±àžàžŽ"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"àžàžŽàžà¹àžªàžµàž¢àž"</string>
<string name="media_device_cast" msgid="4786241789687569892">"à¹àžàžªàžà¹"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"à¹àžàž¥àžµà¹àž¢àžà¹àž¡à¹à¹àžà¹à¹àžàž·à¹àžàžàžàž²àžàžàžŽàžà¹àžªàžµàž¢àžà¹àž£àžµàž¢àžà¹àžà¹àž²"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"à¹àž¡à¹àžàž£à¹àžàž¡à¹àžà¹àžàž²àžà¹àžàž·à¹àžàžàžàž²àžà¹àž«àž¡àžàž«à¹àž²àž¡àž£àžàžàž§àžà¹àžàžŽàžàžàž¢àž¹à¹"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"à¹àž¡à¹àžàž£à¹àžàž¡à¹àžà¹àžàž²àžà¹àžàž·à¹àžàžàžàž²àžà¹àž«àž¡àžàž«à¹àž²àž¡àž£àžàžàž§àžà¹àžàžŽàžàžàž¢àž¹à¹"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s à¹àžàž°à¹àžàž·à¹àžà¹àžàžŽàžà¹àžªàžµàž¢àž"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s à¹àžàž°à¹àžàž·à¹àžàžàž±à¹àžàžà¹àž²à¹àž«à¹àžªàž±à¹àž àžàž²àžàž¡àžµàžàž²àž£àžàžŽàžà¹àžªàžµàž¢àžàžàž£àžŽàžàž²àž£àžàž²àž£à¹àžà¹àž²àžàž¶àž"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s à¹àžàž°à¹àžàž·à¹àžàžàžŽàžà¹àžªàžµàž¢àž àžàž²àžàž¡àžµàžàž²àž£àžàžŽàžà¹àžªàžµàž¢àžàžàž£àžŽàžàž²àž£àžàž²àž£à¹àžà¹àž²àžàž¶àž"</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"àžªàž±à¹àž"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"àžàž±àž§àžàž§àžàžàžžàž¡àž£àž°àžàž±àžà¹àžªàžµàž¢àž %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"àžªàž²àž¢à¹àž£àžµàž¢àžà¹àžà¹àž²à¹àž¥àž°àžàž²àž£à¹àžà¹àžà¹àžàž·àžàžàžàž°àžªà¹àžà¹àžªàžµàž¢àž (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"à¹àžà¹àž²àžªàž¹à¹àžàž²àž£àžàž±à¹àžàžà¹àž²à¹àžàž²àžà¹àžàžžàž"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"àžàž¢àž²àž¢à¹àžàžà¹àž¥àž·à¹àžàžàž£àž°àžàž±àžà¹àžªàžµàž¢àžà¹àž¥à¹àž§"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"àž¢àžžàžà¹àžàžà¹àž¥àž·à¹àžàžàž£àž°àžàž±àžà¹àžªàžµàž¢àžà¹àž¥à¹àž§"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"àžàžŽàžà¹àžªàžµàž¢àž%s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"à¹àžàžŽàžà¹àžªàžµàž¢àž%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"àžàž³àž¥àž±àžà¹àž¥à¹àž <xliff:g id="LABEL">%s</xliff:g> à¹àž"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"à¹àžªàžµàž¢àžàžàž°à¹àž¥à¹àžàžà¹àžà¹àž"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"àžàž±àž§àž£àž±àžàžªàž±àžàžàž²àž UI àž£àž°àžàž"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"àžªàž¥àž±àžàž£àž°àž«àž§à¹àž²àžà¹àžàžàž¥à¹àž²àžªàžžàžà¹àžàžà¹àžàžà¹àž²àžàž«àžà¹àž²"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"àžªàž¥àž±àžàž£àž°àž«àž§à¹àž²àžà¹àžàžàž¥à¹àž²àžªàžžàžà¹àžàžàžàž¥àž±àžàž«àž¥àž±àž"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"à¹àžàžŽàžàž£àž²àž¢àžàž·à¹àžà¹àžàž"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"à¹àžªàžàžà¹àžàžàžàž²àž"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"à¹àžàžŽàžàžàž²àž£àžàž±à¹àžàžà¹àž²"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"à¹àžàžŽàž Assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"àž¥à¹àžàžàž«àžà¹àž²àžàž"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"à¹àžà¹àž²àžªàž¹à¹à¹àž«àž¡àžà¹àž¢àžàž«àžà¹àž²àžàžà¹àžàž¢à¹àžàžàžàž±àžàžàžžàžàž±àžàžàž¢àž¹à¹àžà¹àž²àžàžàž§àž²"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"à¹àžà¹àž²àžªàž¹à¹à¹àž«àž¡àžà¹àž¢àžàž«àžà¹àž²àžàžà¹àžàž¢à¹àžàžàžàž±àžàžàžžàžàž±àžàžàž¢àž¹à¹àžà¹àž²àžàžà¹àž²àž¢"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"à¹àžàž¥àžµà¹àž¢àžàžàž²àžà¹àž«àž¡àžà¹àž¢àžàž«àžà¹àž²àžàžà¹àžà¹àžà¹àžà¹àž¡àž«àžà¹àž²àžàž"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"àž£àž°àž«àž§à¹àž²àžà¹àžà¹à¹àž«àž¡àžà¹àž¢àžàž«àžà¹àž²àžàž: à¹àžàž¥àžµà¹àž¢àžà¹àžàžàž«àžàž¶à¹àžà¹àžà¹àžàžàžµàžà¹àžàžàž«àžàž¶à¹àž"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"àžàžŽàžàžàžžàž"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"à¹àžàž¥àžµà¹àž¢àžà¹àžà¹àžàž àž²àž©àž²àžàž±àžà¹àž"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"àžàž¥à¹àžàžàžàž¹àžàžàž¥à¹àžàžàžàž¢àž¹à¹"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"àžàž¥à¹àžàžà¹àž¥àž°à¹àž¡à¹àžàž£à¹àžàžàžàž¹àžàžàž¥à¹àžàžàžàž¢àž¹à¹"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"à¹àž¡à¹àžàž£à¹àžàžàžàž¹àžàžàž¥à¹àžàžàžàž¢àž¹à¹"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"àž«à¹àž²àž¡àž£àžàžàž§àž"</string>
<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>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index ec3e2b6..1ecd905 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -59,7 +59,7 @@
<string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Hiniling ng ibang device na palitan ang wika ng system"</string>
<string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Palitan ang wika"</string>
<string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Huwag palitan ang wika"</string>
- <string name="share_wifi_button_text" msgid="1285273973812029240">"Ibahagi ang WiâFi"</string>
+ <string name="share_wifi_button_text" msgid="1285273973812029240">"I-share ang WiâFi"</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Payagan ang wireless na pag-debug sa network na ito?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Pangalan ng Network (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAddress ng WiâFi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Palaging payagan sa network na ito"</string>
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Na-block ng iyong IT admin ang pagkuha ng mga screenshot"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"I-edit"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"I-edit ang screenshot"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Ibahagi ang screenshot"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mag-capture pa"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"I-dismiss ang screenshot"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Pinapamahalaan ng iyong magulang ang device na ito. Makikita at mapapamahalaan ng iyong magulang ang impormasyon tulad ng mga app na ginagamit mo, iyong lokasyon, at tagal ng paggamit mo sa device."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pinanatiling naka-unlock ng TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Theft protection\nNa-lock ang device, sobrang pag-unlock"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Na-lock ang device, masyadong maraming pagsubok sa pag-authenticate"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Na-lock ang device\nHindi pumasa sa pag-authenticate"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Mga setting ng tunog"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"I-autocaption ang media"</string>
@@ -752,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Mag-cycle pasulong sa mga kamakailang app"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Mag-cycle pabalik sa mga kamakailang app"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Buksan ang listahan ng mga app"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Ipakita ang taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Buksan ang mga setting"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buksan ang assistant"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"I-lock ang screen"</string>
@@ -761,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Lumipat sa split screen nang nasa RHS ang kasalukuyang app"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Lumipat sa split screen nang nasa LHS ang kasalukuyang app"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Lumipat sa full screen mula sa split screen"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Habang nasa split screen: magpalit-palit ng app"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Lumipat sa susunod na wika"</string>
@@ -1259,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Naka-block ang camera"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Naka-block ang camera at mikropono"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Naka-block ang mikropono"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Huwag istorbohin"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Na-detect ang presensya ng user"</string>
<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>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 3c9d479..7d10bb8 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"BT yöneticiniz ekran görüntüsü almayı engelledi"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Düzenle"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Ekran görüntüsünü düzenle"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Ekranı paylaÅ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Alanı geniÅlet"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran görüntüsünü kapat"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu cihaz ebeveyniniz tarafından yönetiliyor. KullandıÄınız uygulamalar, konumunuz ve ekran baÅında kalma süreniz gibi bilgiler ebeveyniniz tarafından görülüp yönetilebilir."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tarafından kilit açık tutuldu"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Hırsızlık koruması\nCihaz kilitlendi, çok fazla kilit açma denemesi"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Ses ayarları"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Otomatik medya altyazısı"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sesi kapat"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Yayınla"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Zil sesi kapatıldıÄı için kullanılamıyor"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Rahatsız Etmeyin açık olduÄu için kullanılamıyor"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Rahatsız Etmeyin açık olduÄu için kullanılamıyor"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sesi açmak için dokunun."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. TitreÅime ayarlamak için dokunun. EriÅilebilirlik hizmetlerinin sesi kapatılabilir."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. EriÅilebilirlik hizmetlerinin sesi kapatılabilir."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreÅim"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ses denetimleri"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Aramalar ve bildirimler telefonun zilini çaldıracak (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÇıkıŠayarlarını gir"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Ses seviyesi kaydırma çubukları geniÅletildi"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Ses seviyesi kaydırma çubukları daraltıldı"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s sesini kapatma"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s sesini açma"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> Åurada çalacak:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ses Åurada çalacak:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sistem Arayüzü Ayarlayıcısı"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Son uygulamalarda ileriye doÄru git"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Son uygulamalarda geriye doÄru git"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Uygulama listesini aç"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Görev çubuÄunu göster"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Ayarları aç"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Asistan\'ı aç"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Kilit ekranı"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Mevcut uygulamayı saÄ tarafa alarak bölünmüÅ ekrana geç"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Mevcut uygulamayı sol tarafa alarak bölünmüÅ ekrana geç"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"BölünmüÅ ekrandan tam ekrana geç"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"BölünmüÅ ekran etkinken: Bir uygulamayı baÅkasıyla deÄiÅtir"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"GiriÅ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Sonraki dile geç"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera engellendi"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ve mikrofon engellendi"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon engellendi"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Rahatsız etmeyin"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kullanıcı varlıÄı algılandı"</string>
<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>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index bc557c6..b52d25e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"СОÑÑеЌМОй аЎЌÑМÑÑÑÑаÑÐŸÑ Ð·Ð°Ð±Ð»ÐŸÐºÑвав ЌПжлОвÑÑÑÑ ÑПбОÑО зМÑЌкО екÑаМа"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"РеЎагÑваÑО"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"РеЎагÑваÑО зМÑЌПк екÑаМа"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"ÐПЎÑлОÑОÑÑ Ð·ÐœÑЌкПЌ екÑаМа"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ÐклÑÑОÑО бÑлÑÑе ЎеÑалей"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ÐакÑОÑО зМÑЌПк екÑаМа"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ЊОЌ пÑОÑÑÑПÑÐŒ кеÑÑÑÑÑ ÑÐ²ÐŸÑ Ð±Ð°ÑÑкО. ÐПМО ЌПжÑÑÑ Ð±Ð°ÑОÑО Ñа кПМÑÑПлÑваÑО, ÑкОЌО ЎПЎаÑкаЌО ÑО кПÑОÑÑÑÑÑÑÑ, Ўе пеÑебÑваÑÑ Ñ ÑкÑлÑкО ÑаÑÑ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑ Ð·Ð° пÑОÑÑÑПÑÐŒ."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"РПзблПкПвÑÑ ÐŽÐŸÐ²ÑÑÑОй агеМÑ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÐаÑ
ОÑÑ Ð²ÑÐŽ кÑаЎÑжкО\nÐÑОÑÑÑÑй заблПкПваМП (забагаÑП ÑпÑПб)"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ÐалаÑÑÑÐ²Ð°ÐœÐœÑ Ð·Ð²ÑкÑ"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"ÐвÑПЌаÑОÑÐœÑ ÑÑбÑОÑÑО (ЌеЎÑа)"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ðез звÑкÑ"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ТÑаМÑлÑÑÑÑ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"ÐеЎПÑÑÑпМП: звÑк ЎзвÑМкÑв вОЌкМеМП"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ÐеЎПÑÑÑпМП: ÑвÑЌкМеМП ÑежОЌ \"Ðе ÑÑÑбÑваÑО\""</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ÐеЎПÑÑÑпМП: ÑвÑЌкМеМП ÑежОЌ \"Ðе ÑÑÑбÑваÑО\""</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ТПÑкМÑÑÑÑÑ, ÑПб ÑвÑЌкМÑÑО звÑк."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ТПÑкМÑÑÑÑÑ, ÑПб МалаÑÑÑваÑО вÑбÑПÑОгМал. СпеÑÑалÑÐœÑ ÐŒÐŸÐ¶Ð»ÐžÐ²ÐŸÑÑÑ ÐŒÐŸÐ¶Ðµ бÑÑО вОЌкМеМП."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ТПÑкМÑÑÑÑÑ, ÑПб вОЌкМÑÑО звÑк. СпеÑÑалÑÐœÑ ÐŒÐŸÐ¶Ð»ÐžÐ²ÐŸÑÑÑ ÐŒÐŸÐ¶Ðµ бÑÑО вОЌкМеМП."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÑвÑЌкМÑÑО вÑбÑПÑОгМал"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"РегÑлÑÑПÑÑв гÑÑМПÑÑÑ: %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ÐÐ»Ñ Ð²ÐžÐºÐ»ÐžÐºÑв Ñ ÑпПвÑÑÐµÐœÑ ÐœÐ°Ð»Ð°ÑÑПваМП звÑкПвОй ÑОгМал (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ÐÑЎкÑОÑО МалаÑÑÑÐ²Ð°ÐœÐœÑ Ð²ÑÐŽÑвПÑеММÑ"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÐПвзÑМкО гÑÑМПÑÑÑ ÑПзгПÑМÑÑП"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÐПвзÑМкО гÑÑМПÑÑÑ Ð·Ð³ÐŸÑМÑÑП"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"вОЌкМÑÑО звÑк %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ÑвÑЌкМÑÑО звÑк %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"ÐÑÐŽÑвПÑÑÑÑÑÑÑ <xliff:g id="LABEL">%s</xliff:g> Ма:"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"ÐÑÐŽÑП гÑаÑОЌе Ма:"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ÐеÑеЌОкаÑОÑÑ ÐŒÑж МеÑПЎавМÑЌО ЎПЎаÑкаЌО впеÑеЎ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ÐеÑеЌОкаÑОÑÑ ÐŒÑж МеÑПЎавМÑЌО ЎПЎаÑкаЌО МазаЎ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ÐÑЎкÑОÑО ÑпОÑПк ЎПЎаÑкÑв"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ÐПказаÑО Ð¿Ð°ÐœÐµÐ»Ñ Ð·Ð°Ð²ÐŽÐ°ÐœÑ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ÐÑЎкÑОÑО МалаÑÑÑваММÑ"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"ÐÑЎкÑОÑО ЎПЎаÑПк ÐÑОÑÑеМÑ"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"ÐаблПкÑваÑО екÑаМ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"РПзЎÑлОÑО екÑаМ Ñз пПÑПÑМОЌ ЎПЎаÑкПЌ пÑавПÑÑÑ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"РПзЎÑлОÑО екÑаМ Ñз пПÑПÑМОЌ ЎПЎаÑкПЌ лÑвПÑÑÑ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ÐеÑейÑО з ÑПзЎÑÐ»ÐµÐœÐœÑ ÐµÐºÑаМа Ма веÑÑ ÐµÐºÑаМ"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"ÐÑÐŽ ÑÐ°Ñ ÑПзЎÑÐ»ÐµÐœÐœÑ ÐµÐºÑаМа: заЌÑМОÑО ЎПЎаÑПк ÑМÑОЌ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ÐеÑПЎ ввеЎеММÑ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"ÐОбÑаÑО МаÑÑÑÐ¿ÐœÑ ÐŒÐŸÐ²Ñ"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ÐаЌеÑÑ Ð·Ð°Ð±Ð»ÐŸÐºÐŸÐ²Ð°ÐœÐŸ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ÐаЌеÑÑ Ð¹ ÐŒÑкÑПÑПМ заблПкПваМП"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ÐÑкÑПÑПМ заблПкПваМП"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ðе ÑÑÑбÑваÑО"</string>
<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>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 5bd251d..69ab8df 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"IT Ù
ÙØªØžÙ
ÙÛ Ø§Ø³Ú©Ø±Û٠؎اٹس ÙÛÙØ§ Ù
Ø³Ø¯ÙØ¯ کر Ø¯ÛØ§ ÛÛ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ترÙ
ÛÙ
کرÛÚº"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"اسکرÛ٠؎اٹ Ù
ÛÚº ترÙ
ÛÙ
کرÛÚº"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"اسکرÛ٠؎اٹ کا ا؎تراک کرÛÚº"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Ù
Ø²ÛØ¯ Ú©ÛÙŸÚØ± کرÛÚº"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"اسکرÛ٠؎اٹ ؚرخاست کرÛÚº"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ÛÛ Ø¢ÙÛ Ø¢ÙŸ Ú©Û ÙØ§ÙدÛÙ Ú©Û Ø²ÛØ± Ø§ÙØªØžØ§Ù
ÛÛÛ Ø¢ÙŸ Ú©Û ÙØ§ÙدÛ٠آٟ Ú©Û Ø§Ø³ØªØ¹Ù
Ø§Ù ÙØ§ÙÛ Ø§ÛÙŸØ³Ø Ø¢ÙŸ کا Ù
ÙØ§Ù
Ø§ÙØ± آٟ Ú©Û Ø§Ø³Ú©Ø±ÛÙ Ú©Û ÙÙØª Ø¬ÛØ³Û Ù
عÙÙÙ
ات ک٠دÛÚ©ÚŸ Ø§ÙØ± اس کا ÙØžÙ
کر Ø³Ú©ØªÛ ÛÛÚºÛ"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ٹرسٹ Ø§ÛØ¬ÙÙ¹ ÙÛ ØºÛØ± Ù
ÙÙ٠رکڟا ÛÛ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"ÚÙØ±Û Ø³Û ØªØÙØž\n Ø¢ÙÛ Ù
ÙÙÙ ÛÛØ ØšÛØª Ø²ÛØ§Ø¯Û ØºÛØ± Ù
ÙÙ٠کرÙÛ Ú©Û Ú©ÙØŽØŽÛÚº"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>Û <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"ØµÙØªÛ ØªØ±ØªÛØšØ§Øª"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Ø®ÙØ¯Ú©Ø§Ø± Ø·ÙØ± ٟر Ù
ÛÚÛØ§ ٟر Ú©ÛÙŸØŽÙ Ùگا؊ÛÚº"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"خاÙ
ÙØŽ Ú©Ø±ÛÚº"</string>
<string name="media_device_cast" msgid="4786241789687569892">"کاسٹ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ø¯Ø³ØªÛØ§Øš ÙÛÛÚº ÛÛ Ú©ÛÙÙÚ©Û Ø±ÙÚ¯ خاÙ
ÙØŽ ÛÛ"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ØºÛØ± Ø¯Ø³ØªÛØ§Øš ÛÛ Ú©ÛÙÙÚ©Û ÚØ³Ù¹Ø±Øš ÙÛ Ú©Ø±ÛÚº Ø¢Ù ÛÛ"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ØºÛØ± Ø¯Ø³ØªÛØ§Øš ÛÛ Ú©ÛÙÙÚ©Û ÚØ³Ù¹Ø±Øš ÙÛ Ú©Ø±ÛÚº Ø¢Ù ÛÛ"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sÛ Ø¢ÙØ§Ø² ÚØ§Ù٠کرÙÛ Ú©ÛÙØŠÛ تڟٟتڟٟا؊ÛÚºÛ"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sÛ Ø§Ø±ØªØ¹Ø§ØŽ ٟر سÛÙ¹ کرÙÛ Ú©ÛÙØŠÛ تڟٟتڟٟا؊ÛÚºÛ Ø§ÛÚ©Ø³ÛØ³ØšÛÙÙ¹Û Ø³Ø±ÙØ³Ø² ØŽØ§ÛØ¯ خاÙ
ÙØŽ ÛÙÚºÛ"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sÛ Ø®Ø§Ù
ÙØŽ Ú©Ø±ÙÛ Ú©ÛÙØŠÛ تڟٟتڟٟا؊ÛÚºÛ Ø§ÛÚ©Ø³ÛØ³ØšÛÙÙ¹Û Ø³Ø±ÙØ³Ø² ØŽØ§ÛØ¯ خاÙ
ÙØŽ ÛÙÚºÛ"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ÙØ§ØŠØšØ±ÛÙ¹"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s ÙØ§ÙÛÙÙ
Ú©Û Ú©ÙٹرÙÙØ²"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Ú©Ø§ÙØ² Ø§ÙØ± Ø§Ø·ÙØ§Ø¹Ø§Øª Ù
ÙØµÙÙ ÛÙÙÛ ÙŸØ± Ú¯ÚŸÙÙ¹Û ØšØ¬Û Ú¯Û (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"آ؀ٹ ٟٹ Ú©Û ØªØ±ØªÛØšØ§Øª درج کرÛÚº"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ÙØ§ÙÛÙÙ
Ø³ÙØ§ØŠÛÚØ±Ø² Ú©Ù ÙŸÚŸÛÙØ§ Ø¯ÛØ§ Ú¯ÛØ§"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ÙØ§ÙÛÙÙ
Ø³ÙØ§ØŠÛÚØ±Ø² سکÛÚØ§ Ú¯ÛØ§"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s خاÙ
ÙØŽ Ú©Ø±ÛÚº"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ØºÛØ± خاÙ
ÙØŽ Ú©Ø±ÛÚº"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ٟر Ú٠رÛÛ ÛÛ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Ø¢ÚÛÙ ÚÙØªÛ رÛÛ Ú¯Û"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"سسٹÙ
UI Ù¹ÛÙÙØ±"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ØØ§ÙÛÛ Ø§Ûٟس Ú©Û Ø°Ø±ÛØ¹Û Ø¢Ú¯Û Ú©Û Ø·Ø±Ù Ø³Ø§ØŠÛک٠کرÛÚº"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"ØØ§ÙÛÛ Ø§Ûٟس Ú©Û Ø°Ø±ÛØ¹Û ÙŸÛÚÚŸÛ Ú©Û Ø·Ø±Ù Ø³Ø§ØŠÛک٠کرÛÚº"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"اÛٟس Ú©Û ÙÛØ±Ø³Øª Ú©ÚŸÙÙÛÚº"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"ٹاسک ؚار دکڟا؊ÛÚº"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"ØªØ±ØªÛØšØ§Øª Ú©ÚŸÙÙÛÚº"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"اسسٹÙÙ¹ Ú©ÚŸÙÙÛÚº"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ù
ÙÙ٠اسکرÛÙ"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Ù
ÙØ¬ÙØ¯Û Ø§ÛÙŸ Ú©Û Ø³Ø§ØªÚŸ دا؊ÛÚº Ø¬Ø§ÙØš Ø§Ø³ÙŸÙÙ¹ اسکرÛ٠اÙٹر کرÛÚº"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Ù
ÙØ¬ÙØ¯Û Ø§ÛÙŸ Ú©Û Ø³Ø§ØªÚŸ ؚا؊ÛÚº Ø¬Ø§ÙØš Ø§Ø³ÙŸÙÙ¹ اسکرÛ٠اÙٹر کرÛÚº"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"اسٟÙÙ¹ اسکرÛÙ Ø³Û ÙŸÙØ±Û سکرÛ٠ٟر Ø³ÙØŠÚ کرÛÚº"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"اسٟÙÙ¹ اسکرÛÙ Ú©Û Ø¯ÙØ±Ø§Ù: اÛÚ© اÛÙŸ Ú©Ù Ø¯ÙØ³Ø±Û Ø³Û ØªØšØ¯Û٠کرÛÚº"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"ا٠ٟٹ"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"اگÙÛ Ø²ØšØ§Ù ÙŸØ± Ø³ÙØŠÚ کرÛÚº"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ú©ÛÙ
را Ù
Ø³Ø¯ÙØ¯ ÛÛ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ú©ÛÙ
را Ø§ÙØ± Ù
ا؊ÛکرÙÙÙÙ Ù
Ø³Ø¯ÙØ¯ ÛÛ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Ù
ا؊ÛکرÙÙÙÙ Ù
Ø³Ø¯ÙØ¯ ÛÛ"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"ÚØ³Ù¹Ø±Øš ÙÛ Ú©Ø±ÛÚº"</string>
<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>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7d3f2af..1fab322 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Skrinshot olishni AT administratori taqiqlagan"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Tahrirlash"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinshotni tahrirlash"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Skrinshot yuborish"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Skrinshot sohasini kengaytirish"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
@@ -266,7 +268,7 @@
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Yangi qurilmani ulash"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Hammasi"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth ishlatish"</string>
- <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ulandi"</string>
+ <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ulangan"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saqlangan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"uzish"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"faollashtirish"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Bu – ota-onangiz tomonidan boshqariladigan qurilma. Ota-onangiz siz foydalangan ilovalar, joylashuvingiz va qurilmadan foydalanish vaqti kabi axborotlarni koÊ»rishi va boshqarishi mumkin."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tomonidan ochilgan"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Oʻgʻirlanishdan himoya\nQurilma qulflandi, juda koʻp urinildi"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Tovush sozlamalari"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Avtomatik taglavha yaratish"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ovozsiz"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Translatsiya"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Jiringlash ovozsizligi uchun ishlamaydi"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Bezovta qilinmasin yoniqligi sababli ishlamaydi"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Bezovta qilinmasin yoniqligi sababli ishlamaydi"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tebranishni yoqish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tebranish"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s tovush balandligi tugmalari"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Chaqiruvlar va bildirishnomalar jiringlaydi (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Chiqarish sozlamalarini kiritish"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Tovush slayderlari yoyilgan"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Tovush slayderlari yigʻilgan"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sni ovozsiz qilish"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ovozini chiqarish"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>da ijro etilmoqda"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio ijro etiladi"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"SystemUI Tuner"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Oxirgi ilovalarni oldinga varaqlash"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Oxirgi ilovalarni orqaga varaqlash"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Ilovalar roʻyxatini ochish"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Vazifalar panelini chiqarish"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Sozlamalarni ochish"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistentni ochish"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Ekran qulfi"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Oʻng tomondagi ajratilgan ekran rejimiga kirish"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Chap tomondagi ajratilgan ekran rejimiga kirish"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Ajratilgan ekran rejimidan butun ekranga almashtirish"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ajratilgan rejimda ilovalarni oʻzaro almashtirish"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Kiritish"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Keyingi tilga almashtirish"</string>
@@ -1162,7 +1163,7 @@
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Joriy telefon chaqiruvi"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
- <string name="mobile_data_connection_active" msgid="944490013299018227">"Ulandi"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ulangan"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Vaqtincha ulangan"</string>
<string name="mobile_data_poor_connection" msgid="819617772268371434">"Aloqa beqaror"</string>
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil internetga avtomatik ulanmaydi"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklangan"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera va mikrofon bloklangan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklangan"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Bezovta qilinmasin"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Foydalanuvchi aniqlandi"</string>
<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>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 0a9cbb4..3ddb4db 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Quản trá» viên CNTT chặn tính nÄng chụp ảnh màn hình"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Chá»nh sá»a"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Chá»nh sá»a ảnh chụp màn hình"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"Chia sẻ ảnh chụp màn hình"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Chụp thêm"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Äóng ảnh chụp màn hình"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Thiết bá» này do cha mẹ bạn quản lý. Cha mẹ có thá» có thá» xem và quản lý những thông tin như ứng dụng bạn dùng, vá» trí cá»§a bạn và thá»i gian bạn sá» dụng thiết bá»."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Luôn ÄÆ°á»£c TrustAgent má» khóa"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Chá»ng trá»m\nÄã khoá thiết bá», quá nhiá»u lần má» khoá"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Cài Äặt âm thanh"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Tá»± Äá»ng tạo phụ Äá» cho ná»i dung nghe nhìn"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Tắt tiếng"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Truyá»n"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Không hoạt Äá»ng vì chuông bá» tắt"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Không làm ÄÆ°á»£c vì chế Äá» Không làm phiá»n Äang báºt"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Không làm ÄÆ°á»£c vì chế Äá» Không làm phiá»n Äang báºt"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Nhấn Äá» báºt tiếng."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Nhấn Äá» Äặt chế Äá» rung. Bạn có thá» tắt tiếng dá»ch vụ trợ nÄng."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn Äá» tắt tiếng. Bạn có thá» tắt tiếng dá»ch vụ trợ nÄng."</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"Äiá»u khiá»n âm lượng %s"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Cuá»c gá»i và thông báo sẜ Äá» chuông (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Má» phần cài Äặt thiết bá» Äầu ra"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Äã má» rá»ng thanh trượt âm lượng"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Äã thu gá»n thanh trượt âm lượng"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"tắt tiếng %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"báºt tiếng %s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Äang phát <xliff:g id="LABEL">%s</xliff:g> trên"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Âm thanh sẜ phát ra"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Bá» Äiá»u hưá»ng giao diá»n ngưá»i dùng há» thá»ng"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Di chuyá»n tiến trong danh sách các ứng dụng gần Äây"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Di chuyá»n lùi trong danh sách các ứng dụng gần Äây"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Má» danh sách ứng dụng"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Hiá»n thanh tác vụ"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Má» phần cài Äặt"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Má» Trợ lý"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Màn hình khoá"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Vào chế Äá» chia Äôi màn hình, ứng dụng hiá»n tại á» màn hình bên phải"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Vào chế Äá» chia Äôi màn hình, ứng dụng hiá»n tại á» màn hình bên trái"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Chuyá»n từ chế Äá» chia Äôi màn hình sang chế Äá» toàn màn hình"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"Trong chế Äá» chia Äôi màn hình: thay má»t ứng dụng bằng ứng dụng khác"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Äầu vào"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Chuyá»n sang ngôn ngữ tiếp theo"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bá» chặn"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bá» chặn"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bá» chặn"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Không làm phiá»n"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Phát hiá»n thấy ngưá»i dùng Äang hiá»n diá»n"</string>
<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>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 874286a..b98643e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"æšç IT 管çåå·²çŠæ¢æªåå±å¹æªåŸ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"çŒèŸ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"çŒèŸå±å¹æªåŸ"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"å享å±å¹æªåŸ"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"æªåæŽå€å
容"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"å
³éå±å¹æªåŸ"</string>
@@ -538,7 +540,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"æ€è®Ÿå€ç±æšçå®¶é¿ç®¡çãæšçå®¶é¿å¯ä»¥æ¥çå管ççžå
³ä¿¡æ¯ïŒäŸåŠæšäœ¿çšçåºçšãæšçäœçœ®ä¿¡æ¯å讟å€äœ¿çšæ¶éŽã"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ç± TrustAgent ä¿æè§£éç¶æ"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"é²çä¿æ€\n讟å€å·²éå®ïŒå 䞺å°è¯è§£éçæ¬¡æ°è¿å€"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>ïŒ<xliff:g id="EXIT_CONDITION">%2$s</xliff:g>ïŒ"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"声é³è®Ÿçœ®"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"èªåšçæåªäœåå¹"</string>
@@ -583,10 +588,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"éé³"</string>
<string name="media_device_cast" msgid="4786241789687569892">"æå±"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"该åèœæ æ³äœ¿çšïŒå 䞺é声被éé³"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"“å¿æ°”æš¡åŒå·²åŒå¯ïŒå æ€æ æ³è°æŽé³é"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"“å¿æ°”æš¡åŒå·²åŒå¯ïŒå æ€æ æ³è°æŽé³é"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sãç¹æå³å¯åæ¶éé³ã"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sãç¹æå³å¯è®Ÿäžºæ¯åšïŒäœå¯èœäŒåæ¶å°æ éç¢æå¡è®Ÿäžºéé³ã"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sãç¹æå³å¯è®Ÿäžºéé³ïŒäœå¯èœäŒåæ¶å°æ éç¢æå¡è®Ÿäžºéé³ã"</string>
@@ -603,16 +606,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"æ¯åš"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%sé³éæ§ä»¶"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"ææ¥çµåéç¥æ¶äŒåé (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"è¿å
¥èŸåºè®Ÿçœ®"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"é³éæ»åå·²å±åŒ"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"é³éæ»åå·²æ¶èµ·"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"é鳓%s”"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"åæ¶é鳓%s”"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>ææŸäœçœ®ïŒ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"é³é¢ææŸäœçœ®ïŒ"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"ç³»ç»çé¢è°èå·¥å
·"</string>
@@ -759,7 +757,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"åååŸªç¯æµè§æè¿çšè¿çåºçš"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"åååŸªç¯æµè§æè¿çšè¿çåºçš"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"æåŒåºçšå衚"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"æŸç€ºä»»å¡æ "</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"æåŒè®Ÿçœ®"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"æåŒ Google å©ç"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"éå®å±å¹"</string>
@@ -768,6 +765,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"è¿å
¥å屿š¡åŒïŒåœååºçšæŸç€ºäºå³äŸ§"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"è¿å
¥å屿š¡åŒïŒåœååºçšæŸç€ºäºå·ŠäŸ§"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"ä»å屿š¡åŒåæ¢äžºå
šå±"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"åšå屿éŽïŒå°äžäžªåºçšæ¿æ¢äžºåŠäžäžªåºçš"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"èŸå
¥"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"忢å°äžäžç§è¯èš"</string>
@@ -1266,8 +1267,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"å·²çŠçšæå倎"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"å·²çŠçšæå倎å麊å
é£"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"å·²çŠçšéºŠå
é£"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"å¿æ°"</string>
<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>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index bb7919b..9080ff5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"äœ ç IT 管çå¡å·²çŠæ¢æ·åè¢å¹æªå"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"線茯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"線茯è¢å¹æªå"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"å享è¢å¹æªå"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"æ·åæŽå€§ç¯åçè¢å¹å
§å®¹"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ééè¢å¹æªå"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"æ€è£çœ®ç±äœ çå®¶é·ç®¡çãå®¶é·å¯ä»¥æ¥çå管çè£çœ®äžçè³æïŒäŸåŠäœ 䜿çšçæçšçšåŒãäœçœ®åè£çœ®äœ¿çšæéã"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ç±ä¿¡ä»»ç代çä¿æè§£éçæ
"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"é²çä¿è·\nåè©Šè§£éæ¬¡æžéå€ïŒè£çœ®å·²äžé"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"é©èé¯èª€æ¬¡æžéå€ïŒè£çœ®å·²éå®"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"è£çœ®å·²éå®\né©è倱æ"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>ã<xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"鳿èšå®"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"èªåçºåªé«å å
¥åå¹"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"éé³"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ææŸ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"éŽè²å·²èšå®çºéé³ïŒå æ€ç¡æ³äœ¿çš"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ãè«å¿éš·æŸãå·²éåïŒå æ€ç¡æ³äœ¿çš"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ãè«å¿éš·æŸãå·²éåïŒå æ€ç¡æ³äœ¿çš"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sãèŒæå³å¯åæ¶éé³ã"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sãèŒæå³å¯èšçºéåãç¡éç€åèœæåå¯èœå·²ç¶èšçºéé³ã"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sãèŒæå³å¯èšçºéé³ãç¡éç€åèœæåå¯èœå·²ç¶èšçºéé³ã"</string>
@@ -603,16 +604,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"éå"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%sé³éæ§å¶é
"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"æäŸé»åéç¥ææçŒåºéŽè² (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"茞å
¥èŒžåºèšå®"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"æéåé³éæ»æ¡¿"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"éååé³éæ»æ¡¿"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"å°%sèšå®çºéé³"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"åæ¶%sçéé³èšå®"</string>
<string name="media_output_label_title" msgid="872824698593182505">"æ£åšææŸã<xliff:g id="LABEL">%s</xliff:g>ãçè£çœ®ïŒ"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"é³èšææŸåªé«"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"系統䜿çšè
ä»é¢èª¿è«§åš"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"茪æµåææè¿äœ¿çšçæçšçšåŒ (åå)"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"茪æµåææè¿äœ¿çšçæçšçšåŒ (ååŸ)"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"éåæçšçšåŒæž
å®"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"顯瀺工äœå"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"éåèšå®"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"éåãGoogle å©çã"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"äžéç«é¢"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"é²å
¥åå²è¢å¹æš¡åŒïŒäžŠå°ç®åçæçšçšåŒé¡¯ç€ºåšå³åŽ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"é²å
¥åå²è¢å¹æš¡åŒïŒäžŠå°ç®åçæçšçšåŒé¡¯ç€ºåšå·ŠåŽ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"å°åå²è¢å¹åæçºå
šè¢å¹"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"䜿çšåå²è¢å¹æéïŒæŽææçšçšåŒ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"茞å
¥"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"åæè³äžäžåèªèš"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"å·²å°éçžæ©"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"å·²å°éçžæ©å麥å
颚"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"å·²å°é麥å
颚"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"è«å¿éš·æŸ"</string>
<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>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index e48e483..9c0c376 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -86,6 +86,8 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"äœ ç IT 管çå¡å·²çŠæ¢æ·åè¢å¹ç«é¢"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"線茯"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"線茯è¢å¹æªå"</string>
+ <!-- no translation found for screenshot_share_label (1653061117238861559) -->
+ <skip />
<string name="screenshot_share_description" msgid="2861628935812656612">"å享è¢å¹æªå"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"æŽå€§è¢å¹æªåç¯å"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ééè¢å¹æªå"</string>
@@ -538,7 +540,8 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"éåè£çœ®æ¯ç±äœ çå®¶é·ç®¡çãå®¶é·å¯ä»¥æ¥çå管çè£çœ®äžçè³èšïŒäŸåŠäœ 䜿çšçæçšçšåŒãæåšäœçœ®åè¢å¹æéã"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ç± TrustAgent ç¶æè§£éçæ
"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"é²çä¿è·\nè§£éå€±ææ¬¡æžéå€ïŒè£çœ®å·²éå®"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"é©èé¯èª€æ¬¡æžéå€ïŒè£çœ®å·²éå®"</string>
+ <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"è£çœ®å·²éå®\né©è倱æ"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>ã<xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"鳿èšå®"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"èªåç¢çåªé«åå¹"</string>
@@ -583,10 +586,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"éé³"</string>
<string name="media_device_cast" msgid="4786241789687569892">"ææŸ"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"éŽè²å·²èšçºéé³ïŒå æ€ç¡æ³äœ¿çš"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"ãé¶ææŸãæš¡åŒå·²éåïŒå æ€ç¡æ³èª¿æŽé³é"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"ãé¶ææŸãæš¡åŒå·²éåïŒå æ€ç¡æ³èª¿æŽé³é"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$sãèŒè§žå³å¯åæ¶éé³ã"</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$sãèŒè§žå³å¯èšçºéåïŒäœç³»çµ±å¯èœæå°ç¡éç€æåäžäœµèšçºéé³ã"</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$sãèŒè§žå³å¯èšçºéé³ïŒäœç³»çµ±å¯èœæå°ç¡éç€æåäžäœµèšçºéé³ã"</string>
@@ -603,18 +604,13 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"éå"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"ã%sãé³éæ§å¶é
"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"æäŸé»åéç¥ææé¿éŽ (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"é²å
¥èŒžåºèšå®"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"é³éæ»æ¡¿å·²å±é"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"é³éæ»æ¡¿å·²æ¶å"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"å°%sèšçºéé³"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"å°%såæ¶éé³"</string>
<string name="media_output_label_title" msgid="872824698593182505">"æ£åšææŸã<xliff:g id="LABEL">%s</xliff:g>ãçè£çœ®ïŒ"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"å°ææŸé³èšçåªé«ïŒ"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"é³èšææŸäœçœ®"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"系統䜿çšè
ä»é¢èª¿æŽç²Ÿé"</string>
<string name="status_bar" msgid="4357390266055077437">"çæ
å"</string>
<string name="demo_mode" msgid="263484519766901593">"系統 UI å±ç€ºæš¡åŒ"</string>
@@ -759,7 +755,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"ååŸæè¿éåçæçšçšåŒ"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"è¿åæè¿éåçæçšçšåŒ"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"éåæçšçšåŒæž
å®"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"顯瀺工äœå"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"éåèšå®"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"éå Google å©ç"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"è¢å¹éå®"</string>
@@ -768,6 +763,10 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"é²å
¥åå²ç«é¢æš¡åŒïŒäžŠå°ç®åçæçšçšåŒé¡¯ç€ºæŒå³åŽ"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"é²å
¥åå²ç«é¢æš¡åŒïŒäžŠå°ç®åçæçšçšåŒé¡¯ç€ºæŒå·ŠåŽ"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"åŸåå²ç«é¢åæå°å®æŽç«é¢"</string>
+ <!-- no translation found for system_multitasking_splitscreen_focus_rhs (3838578650313318508) -->
+ <skip />
+ <!-- no translation found for system_multitasking_splitscreen_focus_lhs (3164261844398662518) -->
+ <skip />
<string name="system_multitasking_replace" msgid="7410071959803642125">"䜿çšåå²ç«é¢æéïŒæŽææçšçšåŒ"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"茞å
¥"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"åæå°äžäžåèªèš"</string>
@@ -1266,8 +1265,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"å·²å°éæåœ±æ©"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"å·²å°éæåœ±æ©å麥å
颚"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"å·²å°é麥å
颚"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"é¶ææŸ"</string>
<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>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index da75c5d..8b03cba 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -86,6 +86,7 @@
<string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"Ukuthatha isithombe-skrini kuvinjwe umlawuli wakho we-IT"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Hlela"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Hlela isithombe-skrini"</string>
+ <string name="screenshot_share_label" msgid="1653061117238861559">"Yabelana"</string>
<string name="screenshot_share_description" msgid="2861628935812656612">"Yabelana ngesithombe-skrini"</string>
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Thwebula okuningi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cashisa isithombe-skrini"</string>
@@ -538,7 +539,10 @@
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Le divayisi iphethwe ngumzali wakho. Umzali wakho angabona futhi aphathe ulwazi olunjengezinhlelo zokusebenza ozisebenzisayo, indawo yakho, kanye nesikhathi sesikrini."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"I-VPN"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Igcinwa ivuliwe ngo-TrustAgent"</string>
- <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Isivikelo sokweba\nIdivayisi ikhiyiwe, imizamo yokuvula eminingi kakhulu"</string>
+ <!-- no translation found for kg_prompt_after_adaptive_auth_lock (2587481497846342760) -->
+ <skip />
+ <!-- no translation found for keyguard_indication_after_adaptive_auth_lock (2323400645470712787) -->
+ <skip />
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"Izilungiselelo zomsindo"</string>
<string name="volume_odi_captions_tip" msgid="8825655463280990941">"Yenza amagama-ngcazo ngokuzenzakalela emidiya"</string>
@@ -583,10 +587,8 @@
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Thulisa"</string>
<string name="media_device_cast" msgid="4786241789687569892">"Sakaza"</string>
<string name="stream_notification_unavailable" msgid="4313854556205836435">"Ayitholakali ngoba ukukhala kuthulisiwe"</string>
- <!-- no translation found for stream_alarm_unavailable (4059817189292197839) -->
- <skip />
- <!-- no translation found for stream_media_unavailable (6823020894438959853) -->
- <skip />
+ <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Ayitholakali ngoba okuthi Ungaphazamisi kuvuliwe"</string>
+ <string name="stream_media_unavailable" msgid="6823020894438959853">"Ayitholakali ngoba okuthi Ungaphazamisi kuvuliwe"</string>
<string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Thepha ukuze ususe ukuthula."</string>
<string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
@@ -603,16 +605,11 @@
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s izilawuli zevolomu"</string>
<string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Amakholi nezaziso zizokhala (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
- <!-- no translation found for volume_panel_enter_media_output_settings (8824244246272552669) -->
- <skip />
- <!-- no translation found for volume_panel_expanded_sliders (1885750987768506271) -->
- <skip />
- <!-- no translation found for volume_panel_collapsed_sliders (1413383759434791450) -->
- <skip />
- <!-- no translation found for volume_panel_hint_mute (6962563028495243738) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (7489063242934477382) -->
- <skip />
+ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Faka amasethingi wokuphumayo"</string>
+ <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Izilayidi zevolumu zinwetshiwe"</string>
+ <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Izilayidi zevolumu zigoqiwe"</string>
+ <string name="volume_panel_hint_mute" msgid="6962563028495243738">"thulisa i-%s"</string>
+ <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"susa ukuthula kwe-%s"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Idlala ku-<xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Umsindo uzodlala"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Isishuni se-UI yesistimu"</string>
@@ -759,7 +756,6 @@
<string name="group_system_cycle_forward" msgid="5478663965957647805">"Zungeza ubheke phambili ngama-app akamuva"</string>
<string name="group_system_cycle_back" msgid="8194102916946802902">"Zungeza ubuyele emuva ngama-app akamuva"</string>
<string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Vula uhlu lwama-app"</string>
- <string name="group_system_hide_reshow_taskbar" msgid="6108733797075862081">"Bonisa i-taskbar"</string>
<string name="group_system_access_system_settings" msgid="8731721963449070017">"Vula amasethingi"</string>
<string name="group_system_access_google_assistant" msgid="7210074957915968110">"Vula umsizi"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Khiya isikrini"</string>
@@ -768,6 +764,8 @@
<string name="system_multitasking_rhs" msgid="2454557648974553729">"Faka ukuhlukanisa isikrini nge-app yamanje kuya ku-RHS"</string>
<string name="system_multitasking_lhs" msgid="3516599774920979402">"Faka ukuhlukanisa isikrini nge-app yamanje kuya ku-LHS"</string>
<string name="system_multitasking_full_screen" msgid="336048080383640562">"Shintsha usuka ekuhlukaniseni isikrini uye kusikrini esigcwele"</string>
+ <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Shintshela ku-app ngakwesokudla noma ngezansi ngenkathi usebenzisa uhlukanisa isikrini"</string>
+ <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Shintshela ku-app ngakwesokunxele noma ngaphezulu ngenkathi usebenzisa ukuhlukanisa isikrini"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ngesikhathi sokuhlukaniswa kwesikrini: shintsha i-app ngenye"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Okokufaka"</string>
<string name="input_switch_input_language_next" msgid="3782155659868227855">"Shintshela olimini olulandelayo"</string>
@@ -1266,8 +1264,7 @@
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string>
- <!-- no translation found for priority_mode_dream_overlay_content_description (3361628029609329182) -->
- <skip />
+ <string name="priority_mode_dream_overlay_content_description" msgid="3361628029609329182">"Ungaphazamisi"</string>
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Ubukhona bomsebenzisi butholakele"</string>
<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>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 307a619..590dc68 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -140,9 +140,6 @@
<color name="biometric_dialog_gray">#ff757575</color>
<color name="biometric_dialog_accent">@color/material_dynamic_primary40</color>
<color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 -->
- <!-- Color for biometric prompt content view -->
- <color name="biometric_prompt_content_background_color">#8AB4F8</color>
- <color name="biometric_prompt_content_list_item_bullet_color">#1d873b</color>
<!-- SFPS colors -->
<color name="sfps_chevron_fill">@color/material_dynamic_primary90</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2285550..e004ee9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1101,15 +1101,15 @@
<dimen name="biometric_dialog_width">240dp</dimen>
<dimen name="biometric_dialog_height">240dp</dimen>
- <!-- Dimensions for biometric prompt content view. -->
- <dimen name="biometric_prompt_space_above_content">48dp</dimen>
- <dimen name="biometric_prompt_content_container_padding_horizontal">24dp</dimen>
- <dimen name="biometric_prompt_content_padding_horizontal">10dp</dimen>
- <dimen name="biometric_prompt_content_list_row_height">24dp</dimen>
- <dimen name="biometric_prompt_content_list_item_padding_horizontal">10dp</dimen>
- <dimen name="biometric_prompt_content_list_item_text_size">14sp</dimen>
- <dimen name="biometric_prompt_content_list_item_bullet_gap_width">10dp</dimen>
- <dimen name="biometric_prompt_content_list_item_bullet_radius">5dp</dimen>
+ <!-- Dimensions for biometric prompt custom content view. -->
+ <dimen name="biometric_prompt_logo_size">32dp</dimen>
+ <dimen name="biometric_prompt_content_corner_radius">28dp</dimen>
+ <dimen name="biometric_prompt_content_padding_horizontal">24dp</dimen>
+ <dimen name="biometric_prompt_content_padding_vertical">16dp</dimen>
+ <dimen name="biometric_prompt_content_space_width_between_items">16dp</dimen>
+ <dimen name="biometric_prompt_content_list_item_padding_top">12dp</dimen>
+ <dimen name="biometric_prompt_content_list_item_bullet_gap_width">8.5dp</dimen>
+ <dimen name="biometric_prompt_content_list_item_bullet_radius">1.5dp</dimen>
<!-- Biometric Auth Credential values -->
<dimen name="biometric_auth_icon_size">48dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bf5eeb9..a9151e8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -235,6 +235,8 @@
<string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
<string name="screenshot_edit_description">Edit screenshot</string>
+ <!-- Label for UI element which allows sharing the screenshot [CHAR LIMIT=30] -->
+ <string name="screenshot_share_label">Share</string>
<!-- Content description indicating that tapping the element will allow sharing the screenshot [CHAR LIMIT=NONE] -->
<string name="screenshot_share_description">Share screenshot</string>
<!-- Label for UI element which allows the user to capture additional off-screen content in a screenshot. [CHAR LIMIT=30] -->
@@ -378,6 +380,8 @@
<!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
<string name="cancel">Cancel</string>
+ <!-- Content description for the app logo icon on biometric prompt. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_logo">App logo</string>
<!-- Message shown when a biometric is authenticated, asking the user to confirm authentication [CHAR LIMIT=30] -->
<string name="biometric_dialog_confirm">Confirm</string>
<!-- Button name on BiometricPrompt shown when a biometric is detected but not authenticated. Tapping the button resumes authentication [CHAR LIMIT=30] -->
@@ -406,6 +410,8 @@
<string name="biometric_dialog_authenticated">Authenticated</string>
<!-- Talkback string when a canceling authentication [CHAR LIMIT=NONE] -->
<string name="biometric_dialog_cancel_authentication">Cancel Authentication</string>
+ <!-- Content description for the more options button on biometric prompt content view. [CHAR LIMIT=60] -->
+ <string name="biometric_dialog_content_view_more_options_button">More Options</string>
<!-- Button text shown on BiometricPrompt giving the user the option to use an alternate form of authentication (Pin) [CHAR LIMIT=30] -->
<string name="biometric_dialog_use_pin">Use PIN</string>
@@ -2011,6 +2017,10 @@
<string name="system_multitasking_lhs">Enter split screen with current app to LHS</string>
<!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
<string name="system_multitasking_full_screen">Switch from split screen to full screen</string>
+ <!-- User visible title for the keyboard shortcut that switches to app on right or below while using split screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_splitscreen_focus_rhs">Switch to app on right or below while using split screen</string>
+ <!-- User visible title for the keyboard shortcut that switches to app on left or above while using split screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_splitscreen_focus_lhs">Switch to app on left or above while using split screen</string>
<!-- User visible title for the keyboard shortcut that replaces an app from one to another during split screen [CHAR LIMIT=70] -->
<string name="system_multitasking_replace">During split screen: replace an app from one to another</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0483a07..455b192 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -174,43 +174,61 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="TextAppearance.AuthCredential.Title">
+ <style name="TextAppearance.AuthCredential.OldTitle">
<item name="android:fontFamily">google-sans</item>
<item name="android:paddingTop">12dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">24sp</item>
</style>
- <style name="TextAppearance.AuthCredential.Subtitle">
+ <style name="TextAppearance.AuthCredential.OldSubtitle">
<item name="android:fontFamily">google-sans</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">16sp</item>
</style>
- <style name="TextAppearance.AuthCredential.Description">
+ <style name="TextAppearance.AuthCredential.OldDescription">
<item name="android:fontFamily">google-sans</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">14sp</item>
</style>
- <style name="TextAppearance.AuthCredential.ContentViewTitle">
- <item name="android:fontFamily">google-sans</item>
- <item name="android:paddingTop">8dp</item>
- <item name="android:paddingHorizontal">24dp</item>
- <item name="android:textSize">14sp</item>
- <item name="android:gravity">start</item>
+ <style name="TextAppearance.AuthCredential.LogoDescription" parent="TextAppearance.Material3.LabelLarge" >
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:gravity">@integer/biometric_dialog_text_gravity</item>
+ <item name="android:marqueeRepeatLimit">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
</style>
- <style name="TextAppearance.AuthCredential.ContentViewListItem">
- <item name="android:fontFamily">google-sans</item>
- <item name="android:paddingTop">8dp</item>
- <item name="android:paddingHorizontal">
- @dimen/biometric_prompt_content_list_item_padding_horizontal
- </item>
- <item name="android:textSize">@dimen/biometric_prompt_content_list_item_text_size</item>
- <item name="android:gravity">start</item>
+ <style name="TextAppearance.AuthCredential.Title" parent="TextAppearance.Material3.HeadlineSmall" >
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.Subtitle" parent="TextAppearance.Material3.BodyMedium" >
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.Description" parent="TextAppearance.Material3.BodyMedium" >
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.VerticalListContentViewDescription" parent="TextAppearance.Material3.TitleSmall">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.ContentViewWithButtonDescription" parent="TextAppearance.AuthCredential.Description" />
+
+ <style name="TextAppearance.AuthCredential.ContentViewListItem" parent="TextAppearance.Material3.BodySmall">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
+ <item name="android:paddingTop">@dimen/biometric_prompt_content_list_item_padding_top</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.Indicator" parent="TextAppearance.Material3.BodyMedium">
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ <item name="android:marqueeRepeatLimit">marquee_forever</item>
</style>
<style name="TextAppearance.AuthCredential.Error">
@@ -312,9 +330,27 @@
<item name="android:textSize">16sp</item>
</style>
- <style name="AuthCredentialContentLayoutStyle">
- <item name="android:background">@color/biometric_prompt_content_background_color</item>
+ <style name="AuthCredentialContentViewStyle">
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <style name="AuthCredentialVerticalListContentViewStyle" parent="AuthCredentialContentViewStyle">
+ <item name="android:background">@drawable/biometric_prompt_vertical_list_content_view_background</item>
<item name="android:paddingHorizontal">@dimen/biometric_prompt_content_padding_horizontal</item>
+ <item name="android:paddingVertical">@dimen/biometric_prompt_content_padding_vertical</item>
+ </style>
+
+ <style name="AuthCredentialContentViewMoreOptionsButtonStyle" parent="TextAppearance.Material3.LabelLarge">
+ <item name="android:background">@color/transparent</item>
+ <item name="android:gravity">start</item>
+ <item name="enforceTextAppearance">false</item>
+ <item name="android:height">40dp</item>
+ <item name="android:maxWidth">@dimen/m3_btn_max_width</item>
+ <item name="android:minWidth">48dp</item>
+ <item name="android:paddingLeft">0dp</item>
+ <item name="android:paddingRight">12dp</item>
+ <item name="android:textColor">?androidprv:attr/materialColorPrimary</item>
</style>
<style name="DeviceManagementDialogTitle">
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 8a2245d..48271de 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -31,7 +31,6 @@
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
@@ -39,6 +38,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags.REGION_SAMPLING
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -328,7 +328,7 @@
object : KeyguardUpdateMonitorCallback() {
override fun onKeyguardVisibilityChanged(visible: Boolean) {
isKeyguardVisible = visible
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
if (!isKeyguardVisible) {
clock?.run {
smallClock.animations.doze(if (isDozing) 1f else 0f)
@@ -368,7 +368,7 @@
}
private fun refreshTime() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
@@ -427,7 +427,7 @@
parent.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
listenForDozing(this)
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
listenForDozeAmountTransition(this)
listenForAnyStateToAodTransition(this)
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
index 630610d..df77a58 100644
--- a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt
@@ -30,7 +30,7 @@
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import com.android.keyguard.dagger.KeyguardStatusViewComponent
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.res.R
@@ -95,7 +95,7 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
onCreateV2()
} else {
onCreate()
@@ -132,7 +132,7 @@
}
override fun onAttachedToWindow() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
clockRegistry.registerClockChangeListener(clockChangedListener)
clockEventController.registerListeners(clock!!)
@@ -141,7 +141,7 @@
}
override fun onDetachedFromWindow() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
clockEventController.unregisterListeners()
clockRegistry.unregisterClockChangeListener(clockChangedListener)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 28013c6..4a96e9e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -3,7 +3,6 @@
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_X_CLOCK_DESIGN;
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_DESIGN;
import static com.android.keyguard.KeyguardStatusAreaView.TRANSLATE_Y_CLOCK_SIZE;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -23,6 +22,7 @@
import com.android.app.animation.Interpolators;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.clocks.ClockController;
@@ -192,7 +192,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mSmallClockFrame = findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
mStatusArea = findViewById(R.id.keyguard_status_area);
@@ -266,7 +266,7 @@
}
void updateClockTargetRegions() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
if (mClock != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index e621ffe..5b8eb9d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -21,7 +21,6 @@
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.Flags.smartspaceRelocateToBottom;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -45,6 +44,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
@@ -202,7 +202,7 @@
mClockChangedListener = new ClockRegistry.ClockChangeListener() {
@Override
public void onCurrentClockChanged() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
setClock(mClockRegistry.createCurrentClock());
}
}
@@ -245,7 +245,7 @@
protected void onInit() {
mKeyguardSliceViewController.init();
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
}
@@ -340,7 +340,7 @@
addDateWeatherView();
}
}
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
setDateWeatherVisibility();
setWeatherVisibility();
}
@@ -348,7 +348,7 @@
}
int getNotificationIconAreaHeight() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return 0;
} else if (NotificationIconContainerRefactor.isEnabled()) {
return mAodIconContainer != null ? mAodIconContainer.getHeight() : 0;
@@ -391,7 +391,7 @@
}
private void addDateWeatherView() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
mDateWeatherView = (ViewGroup) mSmartspaceController.buildAndConnectDateView(mView);
@@ -407,7 +407,7 @@
}
private void addWeatherView() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
@@ -420,7 +420,7 @@
}
private void addSmartspaceView() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
@@ -528,7 +528,7 @@
*/
void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x;
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
PropertyAnimator.setProperty(mSmallClockFrame, AnimatableProperty.TRANSLATION_X,
x, props, animate);
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X,
@@ -554,7 +554,7 @@
return 0;
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return 0;
}
@@ -589,14 +589,14 @@
}
boolean isClockTopAligned() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return mKeyguardClockInteractor.getClockSize().getValue() == LARGE;
}
return mLargeClockFrame.getVisibility() != View.VISIBLE;
}
private void updateAodIcons() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
NotificationIconContainer nic = (NotificationIconContainer)
mView.findViewById(
com.android.systemui.res.R.id.left_aligned_notification_icon_container);
@@ -616,7 +616,7 @@
}
private void setClock(ClockController clock) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
if (clock != null && mLogBuffer != null) {
@@ -630,8 +630,8 @@
@Nullable
public ClockController getClock() {
- if (migrateClocksToBlueprint()) {
- return mKeyguardClockInteractor.getClock();
+ if (MigrateClocksToBlueprint.isEnabled()) {
+ return mKeyguardClockInteractor.getCurrentClock().getValue();
} else {
return mClockEventController.getClock();
}
@@ -642,7 +642,7 @@
}
private void updateDoubleLineClock() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
mCanShowDoubleLineClock = mSecureSettings.getIntForUser(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 7f9ae5e..603a47e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,7 +20,6 @@
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.animation.Animator;
@@ -52,6 +51,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ViewHierarchyAnimator;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.plugins.clocks.ClockController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
@@ -223,7 +223,7 @@
}
mDumpManager.registerDumpable(getInstanceName(), this);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
startCoroutines(EmptyCoroutineContext.INSTANCE);
mView.setVisibility(View.GONE);
}
@@ -250,7 +250,7 @@
@Override
protected void onViewAttached() {
mStatusArea = mView.findViewById(R.id.keyguard_status_area);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
@@ -261,7 +261,7 @@
@Override
protected void onViewDetached() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
@@ -485,7 +485,7 @@
boolean splitShadeEnabled,
boolean shouldBeCentered,
boolean animate) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
} else {
mKeyguardClockSwitchController.setSplitShadeCentered(
@@ -503,7 +503,7 @@
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(layout);
int guideline;
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
guideline = R.id.split_shade_guideline;
} else {
guideline = R.id.qs_edge_guideline;
@@ -548,7 +548,7 @@
&& clock.getLargeClock().getConfig().getHasCustomPositionUpdatedAnimation();
// When migrateClocksToBlueprint is on, customized clock animation is conducted in
// KeyguardClockViewBinder
- if (customClockAnimation && !migrateClocksToBlueprint()) {
+ if (customClockAnimation && !MigrateClocksToBlueprint.isEnabled()) {
// Find the clock, so we can exclude it from this transition.
FrameLayout clockContainerView = mView.findViewById(R.id.lockscreen_clock_view_large);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index c3c4239..9b09265 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -24,7 +24,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index f5a6cb3..fd8b6d5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -16,7 +16,6 @@
package com.android.keyguard;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -24,6 +23,7 @@
import android.view.View;
import com.android.app.animation.Interpolators;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
@@ -88,7 +88,7 @@
boolean keyguardFadingAway,
boolean goingToFullShade,
int oldStatusBarState) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
log("Ignoring KeyguardVisibilityelper, migrateClocksToBlueprint flag on");
return;
}
@@ -113,7 +113,7 @@
animProps.setDelay(0).setDuration(160);
log("goingToFullShade && !keyguardFadingAway");
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
log("Using LockscreenToGoneTransition 1");
} else {
PropertyAnimator.setProperty(
@@ -171,7 +171,7 @@
animProps,
true /* animate */);
} else if (mScreenOffAnimationController.shouldAnimateInKeyguard()) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
log("Using GoneToAodTransition");
mKeyguardViewVisibilityAnimating = false;
} else {
@@ -187,7 +187,7 @@
mView.setVisibility(View.VISIBLE);
}
} else {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
log("Using LockscreenToGoneTransition 2");
} else {
log("Direct set Visibility to GONE");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 039a2e5..8f1a5f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -22,8 +22,6 @@
import static com.android.keyguard.LockIconView.ICON_FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
-import static com.android.systemui.Flags.keyguardBottomAreaRefactor;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
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;
@@ -68,6 +66,8 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -453,7 +453,7 @@
private void updateLockIconLocation() {
final float scaleFactor = mAuthController.getScaleFactor();
final int scaledPadding = (int) (mDefaultPaddingPx * scaleFactor);
- if (keyguardBottomAreaRefactor() || migrateClocksToBlueprint()) {
+ if (KeyguardBottomAreaRefactor.isEnabled() || MigrateClocksToBlueprint.isEnabled()) {
mView.getLockIcon().setPadding(scaledPadding, scaledPadding, scaledPadding,
scaledPadding);
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index a0f15ef..781f6dd 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -16,8 +16,6 @@
package com.android.keyguard.dagger;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
-
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
@@ -28,6 +26,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.clocks.ClockMessageBuffers;
import com.android.systemui.res.R;
@@ -70,7 +69,7 @@
layoutInflater,
resources,
featureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION),
- migrateClocksToBlueprint()),
+ MigrateClocksToBlueprint.isEnabled()),
context.getString(R.string.lockscreen_clock_id_fallback),
clockBuffers,
/* keepAllLoaded = */ false,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 99cdc01..fd0e7fc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -218,6 +218,11 @@
}
@Override
+ public void onContentViewMoreOptionsButtonPressed() {
+ animateAway(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS);
+ }
+
+ @Override
public void onError() {
animateAway(AuthDialogCallback.DISMISSED_ERROR);
}
@@ -513,7 +518,8 @@
mConfig.mOpPackageName);
final CredentialViewModel vm = mCredentialViewModelProvider.get();
vm.setAnimateContents(animateContents);
- ((CredentialView) mCredentialView).init(vm, this, mPanelController, animatePanel);
+ ((CredentialView) mCredentialView).init(vm, this, mPanelController, animatePanel,
+ mBiometricCallback);
mLayout.addView(mCredentialView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a40b4d7..d85b81d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -205,12 +205,12 @@
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
String reason = intent.getStringExtra("reason");
reason = (reason != null) ? reason : "unknown";
- closeDioalog(reason);
+ closeDialog(reason);
}
}
};
- private void closeDioalog(String reason) {
+ private void closeDialog(String reason) {
if (isShowing()) {
Log.i(TAG, "Close BP, reason :" + reason);
mCurrentDialog.dismissWithoutCallback(true /* animate */);
@@ -571,6 +571,11 @@
credentialAttestation);
break;
+ case AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS:
+ sendResultAndCleanUp(
+ BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
+ credentialAttestation);
+ break;
default:
Log.e(TAG, "Unhandled reason: " + reason);
break;
@@ -579,7 +584,7 @@
@Override
public void handleShowGlobalActionsMenu() {
- closeDioalog("PowerMenu shown");
+ closeDialog("PowerMenu shown");
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index 9a21940..024c6ea 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -32,6 +32,7 @@
int DISMISSED_ERROR = 5;
int DISMISSED_BY_SYSTEM_SERVER = 6;
int DISMISSED_CREDENTIAL_AUTHENTICATED = 7;
+ int DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS = 8;
@IntDef({DISMISSED_USER_CANCELED,
DISMISSED_BUTTON_NEGATIVE,
@@ -39,7 +40,8 @@
DISMISSED_BIOMETRIC_AUTHENTICATED,
DISMISSED_ERROR,
DISMISSED_BY_SYSTEM_SERVER,
- DISMISSED_CREDENTIAL_AUTHENTICATED})
+ DISMISSED_CREDENTIAL_AUTHENTICATED,
+ DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS})
@interface DismissedReason {}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
index 4d88f49..9ad3f43 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
@@ -155,7 +155,8 @@
constraintBp() &&
!Utils.isBiometricAllowed(promptInfo) &&
isDeviceCredentialAllowed(promptInfo) &&
- promptInfo.contentView != null
+ promptInfo.contentView != null &&
+ !promptInfo.isContentViewMoreOptionsButtonUsed
_showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
index 94cea57..b7c0fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
@@ -30,11 +30,11 @@
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.lastOrNull
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
@@ -61,11 +61,12 @@
val isShowing: Flow<Boolean> = biometricPromptRepository.isShowing
/**
- * If biometric prompt without icon needs to show for displaying content prior to credential
- * view.
+ * If vertical list content view is shown, credential view should hide subtitle and content view
*/
- val showBpWithoutIconForCredential: StateFlow<Boolean> =
- biometricPromptRepository.showBpWithoutIconForCredential
+ val showTitleOnly: Flow<Boolean> =
+ biometricPromptRepository.promptInfo.map { promptInfo ->
+ promptInfo?.contentView != null && !promptInfo.isContentViewMoreOptionsButtonUsed
+ }
/** Metadata about the current credential prompt, including app-supplied preferences. */
val prompt: Flow<BiometricPromptRequest.Credential?> =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
index 2f493ac..b28733f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
@@ -10,10 +10,11 @@
import android.view.accessibility.AccessibilityManager
import android.widget.LinearLayout
import android.widget.TextView
-import com.android.systemui.res.R
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
+import com.android.systemui.biometrics.ui.binder.Spaghetti
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
+import com.android.systemui.res.R
/** PIN or password credential view for BiometricPrompt. */
class CredentialPasswordView(context: Context, attrs: AttributeSet?) :
@@ -31,8 +32,16 @@
host: CredentialView.Host,
panelViewController: AuthPanelController,
animatePanel: Boolean,
+ legacyCallback: Spaghetti.Callback,
) {
- CredentialViewBinder.bind(this, host, viewModel, panelViewController, animatePanel)
+ CredentialViewBinder.bind(
+ this,
+ host,
+ viewModel,
+ panelViewController,
+ animatePanel,
+ legacyCallback
+ )
}
override fun onFinishInflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
index 1086897..d9d286f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPatternView.kt
@@ -9,6 +9,7 @@
import android.widget.LinearLayout
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
+import com.android.systemui.biometrics.ui.binder.Spaghetti
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
/** Pattern credential view for BiometricPrompt. */
@@ -21,8 +22,16 @@
host: CredentialView.Host,
panelViewController: AuthPanelController,
animatePanel: Boolean,
+ legacyCallback: Spaghetti.Callback,
) {
- CredentialViewBinder.bind(this, host, viewModel, panelViewController, animatePanel)
+ CredentialViewBinder.bind(
+ this,
+ host,
+ viewModel,
+ panelViewController,
+ animatePanel,
+ legacyCallback
+ )
}
override fun onFinishInflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
index b7c6a45..e2f9895 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialView.kt
@@ -1,6 +1,7 @@
package com.android.systemui.biometrics.ui
import com.android.systemui.biometrics.AuthPanelController
+import com.android.systemui.biometrics.ui.binder.Spaghetti
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
/** A credential variant of BiometricPrompt. */
@@ -27,5 +28,6 @@
host: Host,
panelViewController: AuthPanelController,
animatePanel: Boolean,
+ legacyCallback: Spaghetti.Callback,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
index e58c8ff..88aef56 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
@@ -18,101 +18,167 @@
import android.content.Context
import android.content.res.Resources
-import android.content.res.Resources.Theme
-import android.graphics.Paint
import android.hardware.biometrics.PromptContentItem
import android.hardware.biometrics.PromptContentItemBulletedText
import android.hardware.biometrics.PromptContentItemPlainText
import android.hardware.biometrics.PromptContentView
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptVerticalListContentView
import android.text.SpannableString
import android.text.Spanned
+import android.text.TextPaint
import android.text.style.BulletSpan
import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewTreeObserver
+import android.widget.Button
import android.widget.LinearLayout
import android.widget.Space
import android.widget.TextView
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
+import androidx.lifecycle.lifecycleScope
+import com.android.settingslib.Utils
import com.android.systemui.biometrics.ui.BiometricPromptLayout
-import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import kotlin.math.ceil
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
/** Sub-binder for [BiometricPromptLayout.customized_view_container]. */
object BiometricCustomizedViewBinder {
- fun bind(customizedViewContainer: LinearLayout, spaceAbove: Space, viewModel: PromptViewModel) {
- customizedViewContainer.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- val contentView: PromptContentView? = viewModel.contentView.first()
+ fun bind(
+ customizedViewContainer: LinearLayout,
+ contentView: PromptContentView?,
+ legacyCallback: Spaghetti.Callback
+ ) {
+ customizedViewContainer.repeatWhenAttached { containerView ->
+ lifecycleScope.launch {
+ if (contentView == null) {
+ containerView.visibility = View.GONE
+ return@launch
+ }
- if (contentView != null) {
- val context = customizedViewContainer.context
- customizedViewContainer.addView(contentView.toView(context))
- customizedViewContainer.visibility = View.VISIBLE
- spaceAbove.visibility = View.VISIBLE
- } else {
- customizedViewContainer.visibility = View.GONE
- spaceAbove.visibility = View.GONE
+ containerView.width { containerWidth ->
+ if (containerWidth == 0) {
+ return@width
}
+ (containerView as LinearLayout).addView(
+ contentView.toView(containerView.context, containerWidth, legacyCallback)
+ )
+ containerView.visibility = View.VISIBLE
}
}
}
}
}
-private fun PromptContentView.toView(context: Context): View {
- val resources = context.resources
- val inflater = LayoutInflater.from(context)
- when (this) {
- is PromptVerticalListContentView -> {
- val contentView =
- inflater.inflate(R.layout.biometric_prompt_content_layout, null) as LinearLayout
-
- val descriptionView = contentView.requireViewById<TextView>(R.id.customized_view_title)
- if (!description.isNullOrEmpty()) {
- descriptionView.text = description
- } else {
- descriptionView.visibility = View.GONE
- }
-
- // Show two column by default, once there is an item exceeding max lines, show single
- // item instead.
- val showTwoColumn = listItems.all { !it.doesExceedMaxLinesIfTwoColumn(resources) }
- var currRowView = createNewRowLayout(inflater)
- for (item in listItems) {
- val itemView = item.toView(resources, inflater, context.theme)
- currRowView.addView(itemView)
-
- if (!showTwoColumn || currRowView.childCount == 2) {
- contentView.addView(currRowView)
- currRowView = createNewRowLayout(inflater)
- }
- }
- if (currRowView.childCount > 0) {
- contentView.addView(currRowView)
- }
-
- return contentView
- }
+private fun PromptContentView.toView(
+ context: Context,
+ containerViewWidth: Int,
+ legacyCallback: Spaghetti.Callback
+): View {
+ return when (this) {
+ is PromptVerticalListContentView -> initLayout(context, containerViewWidth)
+ is PromptContentViewWithMoreOptionsButton -> initLayout(context, legacyCallback)
else -> {
throw IllegalStateException("No such PromptContentView: $this")
}
}
}
+private fun LayoutInflater.inflateContentView(id: Int, description: String?): LinearLayout {
+ val contentView = inflate(id, null) as LinearLayout
+
+ val descriptionView = contentView.requireViewById<TextView>(R.id.customized_view_description)
+ if (!description.isNullOrEmpty()) {
+ descriptionView.text = description
+ } else {
+ descriptionView.visibility = View.GONE
+ }
+ return contentView
+}
+
+private fun PromptContentViewWithMoreOptionsButton.initLayout(
+ context: Context,
+ legacyCallback: Spaghetti.Callback
+): View {
+ val inflater = LayoutInflater.from(context)
+ val contentView =
+ inflater.inflateContentView(
+ R.layout.biometric_prompt_content_with_button_layout,
+ description
+ )
+ val buttonView = contentView.requireViewById<Button>(R.id.customized_view_more_options_button)
+ buttonView.setOnClickListener { legacyCallback.onContentViewMoreOptionsButtonPressed() }
+ return contentView
+}
+
+private fun PromptVerticalListContentView.initLayout(
+ context: Context,
+ containerViewWidth: Int
+): View {
+ val inflater = LayoutInflater.from(context)
+ val resources = context.resources
+ val contentView =
+ inflater.inflateContentView(
+ R.layout.biometric_prompt_vertical_list_content_layout,
+ description
+ )
+ // Show two column by default, once there is an item exceeding max lines, show single
+ // item instead.
+ val showTwoColumn =
+ listItems.all { !it.doesExceedMaxLinesIfTwoColumn(context, containerViewWidth) }
+ var currRowView = createNewRowLayout(inflater)
+ for (item in listItems) {
+ val itemView = item.toView(context, inflater)
+ // If this item will be in the first row (contentView only has description view) and
+ // description is empty, remove top padding of this item.
+ if (contentView.childCount == 1 && description.isNullOrEmpty()) {
+ itemView.setPadding(
+ itemView.paddingLeft,
+ 0,
+ itemView.paddingRight,
+ itemView.paddingBottom
+ )
+ }
+ currRowView.addView(itemView)
+
+ // If this is the first item in the current row, add space behind it.
+ if (currRowView.childCount == 1 && showTwoColumn) {
+ currRowView.addSpaceView(
+ resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_content_space_width_between_items
+ ),
+ MATCH_PARENT
+ )
+ }
+
+ // If there are already two items (plus the space view) in the current row, or it
+ // should be one column, start a new row
+ if (currRowView.childCount == 3 || !showTwoColumn) {
+ contentView.addView(currRowView)
+ currRowView = createNewRowLayout(inflater)
+ }
+ }
+ if (currRowView.childCount > 0) {
+ contentView.addView(currRowView)
+ }
+ return contentView
+}
+
private fun createNewRowLayout(inflater: LayoutInflater): LinearLayout {
return inflater.inflate(R.layout.biometric_prompt_content_row_layout, null) as LinearLayout
}
+private fun LinearLayout.addSpaceView(width: Int, height: Int) {
+ addView(Space(context), LinearLayout.LayoutParams(width, height))
+}
+
private fun PromptContentItem.doesExceedMaxLinesIfTwoColumn(
- resources: Resources,
+ context: Context,
+ containerViewWidth: Int,
): Boolean {
+ val resources = context.resources
val passedInText: String =
when (this) {
is PromptContentItemPlainText -> text
@@ -125,32 +191,26 @@
when (this) {
is PromptContentItemPlainText,
is PromptContentItemBulletedText -> {
- val dialogMargin =
- resources.getDimensionPixelSize(R.dimen.biometric_dialog_border_padding)
- val halfDialogWidth =
- Resources.getSystem().displayMetrics.widthPixels / 2 - dialogMargin
- val containerPadding =
- resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_content_container_padding_horizontal
- )
- val contentPadding =
+ val contentViewPadding =
resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_padding_horizontal)
val listItemPadding = getListItemPadding(resources)
- val maxWidth = halfDialogWidth - containerPadding - contentPadding - listItemPadding
+ val maxWidth = containerViewWidth / 2 - contentViewPadding - listItemPadding
- val text = "$passedInText"
- val textSize =
- resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_content_list_item_text_size
+ val paint = TextPaint()
+ val attributes =
+ context.obtainStyledAttributes(
+ R.style.TextAppearance_AuthCredential_ContentViewListItem,
+ intArrayOf(android.R.attr.textSize)
)
- val paint = Paint()
- paint.textSize = textSize.toFloat()
+ paint.textSize = attributes.getDimensionPixelSize(0, 0).toFloat()
+ val textWidth = paint.measureText(passedInText)
+ attributes.recycle()
val maxLines =
resources.getInteger(
R.integer.biometric_prompt_content_list_item_max_lines_if_two_column
)
- val numLines = ceil(paint.measureText(text).toDouble() / maxWidth).toInt()
+ val numLines = ceil(textWidth / maxWidth).toInt()
return numLines > maxLines
}
else -> {
@@ -160,10 +220,10 @@
}
private fun PromptContentItem.toView(
- resources: Resources,
+ context: Context,
inflater: LayoutInflater,
- theme: Theme,
): TextView {
+ val resources = context.resources
val textView =
inflater.inflate(R.layout.biometric_prompt_content_row_item_text_view, null) as TextView
val lp = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)
@@ -178,7 +238,7 @@
val span =
BulletSpan(
getListItemBulletGapWidth(resources),
- getListItemBulletColor(resources, theme),
+ getListItemBulletColor(context),
getListItemBulletRadius(resources)
)
bulletedText.setSpan(span, 0 /* start */, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
@@ -194,8 +254,8 @@
private fun PromptContentItem.getListItemPadding(resources: Resources): Int {
var listItemPadding =
resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_content_list_item_padding_horizontal
- ) * 2
+ R.dimen.biometric_prompt_content_space_width_between_items
+ ) / 2
when (this) {
is PromptContentItemPlainText -> {}
is PromptContentItemBulletedText -> {
@@ -215,5 +275,20 @@
private fun getListItemBulletGapWidth(resources: Resources): Int =
resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_list_item_bullet_gap_width)
-private fun getListItemBulletColor(resources: Resources, theme: Theme): Int =
- resources.getColor(R.color.biometric_prompt_content_list_item_bullet_color, theme)
+private fun getListItemBulletColor(context: Context): Int =
+ Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.materialColorOnSurface)
+
+private fun <T : View> T.width(function: (Int) -> Unit) {
+ if (width == 0)
+ viewTreeObserver.addOnGlobalLayoutListener(
+ object : ViewTreeObserver.OnGlobalLayoutListener {
+ override fun onGlobalLayout() {
+ if (measuredWidth > 0) {
+ viewTreeObserver.removeOnGlobalLayoutListener(this)
+ }
+ function(measuredWidth)
+ }
+ }
+ )
+ else function(measuredWidth)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 7bb75bf..b2ade4f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -135,7 +135,7 @@
val confirmationButton = view.requireViewById<Button>(R.id.button_confirm)
val retryButton = view.requireViewById<Button>(R.id.button_try_again)
- // TODO(b/251476085): temporary workaround for the unsafe callbacks & legacy controllers
+ // TODO(b/330788871): temporary workaround for the unsafe callbacks & legacy controllers
val adapter =
Spaghetti(
view = view,
@@ -171,8 +171,8 @@
if (Flags.customBiometricPrompt() && constraintBp()) {
BiometricCustomizedViewBinder.bind(
customizedViewContainer,
- view.requireViewById(R.id.space_above_content),
- viewModel
+ viewModel.contentView.first(),
+ legacyCallback
)
}
@@ -476,7 +476,7 @@
*
* Do not reference the [view] for anything other than [asView].
*/
-@Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+@Deprecated("TODO(b/330788871): remove after replacing AuthContainerView")
class Spaghetti(
private val view: View,
private val viewModel: PromptViewModel,
@@ -484,19 +484,20 @@
private val applicationScope: CoroutineScope,
) {
- @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ @Deprecated("TODO(b/330788871): remove after replacing AuthContainerView")
interface Callback {
fun onAuthenticated()
fun onUserCanceled()
fun onButtonNegative()
fun onButtonTryAgain()
+ fun onContentViewMoreOptionsButtonPressed()
fun onError()
fun onUseDeviceCredential()
fun onStartDelayedFingerprintSensor()
fun onAuthenticatedAndConfirmed()
}
- @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ @Deprecated("TODO(b/330788871): remove after replacing AuthContainerView")
enum class BiometricState {
/** Authentication hardware idle. */
STATE_IDLE,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 1dfd2e5f..e3c0cba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -121,10 +121,6 @@
val largeConstraintSet = ConstraintSet()
largeConstraintSet.clone(mediumConstraintSet)
- largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
- largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
- largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
- largeConstraintSet.setVisibility(R.id.scrollView, View.GONE)
// TODO: Investigate better way to handle 180 rotations
val flipConstraintSet = ConstraintSet()
@@ -286,6 +282,10 @@
fun setVisibilities(size: PromptSize) {
viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) }
+ largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
+ largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
+ largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
+ largeConstraintSet.setVisibility(R.id.scrollView, View.GONE)
if (viewModel.showBpWithoutIconForCredential.value) {
smallConstraintSet.setVisibility(iconHolderView.id, View.GONE)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index ce52e1d..18e2a56 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -1,20 +1,23 @@
package com.android.systemui.biometrics.ui.binder
+import android.hardware.biometrics.Flags
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
+import android.widget.LinearLayout
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
-import com.android.systemui.res.R
+import com.android.systemui.Flags.constraintBp
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
import com.android.systemui.biometrics.ui.CredentialPatternView
import com.android.systemui.biometrics.ui.CredentialView
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filter
@@ -40,12 +43,15 @@
viewModel: CredentialViewModel,
panelViewController: AuthPanelController,
animatePanel: Boolean,
+ legacyCallback: Spaghetti.Callback,
maxErrorDuration: Long = 3_000L,
requestFocusForInput: Boolean = true,
) {
val titleView: TextView = view.requireViewById(R.id.title)
val subtitleView: TextView = view.requireViewById(R.id.subtitle)
val descriptionView: TextView = view.requireViewById(R.id.description)
+ val customizedViewContainer: LinearLayout =
+ view.requireViewById(R.id.customized_view_container)
val iconView: ImageView? = view.findViewById(R.id.icon)
val errorView: TextView = view.requireViewById(R.id.error)
val cancelButton: Button? = view.findViewById(R.id.cancel_button)
@@ -76,6 +82,13 @@
subtitleView.textOrHide = header.subtitle
descriptionView.textOrHide = header.description
+ if (Flags.customBiometricPrompt() && constraintBp()) {
+ BiometricCustomizedViewBinder.bind(
+ customizedViewContainer,
+ header.contentView,
+ legacyCallback
+ )
+ }
iconView?.setImageDrawable(header.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
index c6d9085..8b8c90a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
@@ -1,6 +1,7 @@
package com.android.systemui.biometrics.ui.viewmodel
import android.graphics.drawable.Drawable
+import android.hardware.biometrics.PromptContentView
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
/** View model for the top-level header / info area of BiometricPrompt. */
@@ -9,6 +10,7 @@
val title: String
val subtitle: String
val description: String
+ val contentView: PromptContentView?
val icon: Drawable
val showEmergencyCallButton: Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
index 46be8c7..31af126 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
@@ -2,8 +2,11 @@
import android.content.Context
import android.graphics.drawable.Drawable
+import android.hardware.biometrics.Flags.customBiometricPrompt
+import android.hardware.biometrics.PromptContentView
import android.text.InputType
import com.android.internal.widget.LockPatternView
+import com.android.systemui.Flags.constraintBp
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.domain.interactor.CredentialStatus
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
@@ -34,14 +37,19 @@
val header: Flow<CredentialHeaderViewModel> =
combine(
credentialInteractor.prompt.filterIsInstance<BiometricPromptRequest.Credential>(),
- credentialInteractor.showBpWithoutIconForCredential
- ) { request, showBpWithoutIconForCredential ->
+ credentialInteractor.showTitleOnly
+ ) { request, showTitleOnly ->
+ val flagEnabled = customBiometricPrompt() && constraintBp()
+ val showTitleOnlyForCredential = showTitleOnly && flagEnabled
BiometricPromptHeaderViewModelImpl(
request,
user = request.userInfo,
title = request.title,
- subtitle = if (showBpWithoutIconForCredential) "" else request.subtitle,
- description = if (showBpWithoutIconForCredential) "" else request.description,
+ subtitle = if (showTitleOnlyForCredential) "" else request.subtitle,
+ contentView =
+ if (flagEnabled && !showTitleOnlyForCredential) request.contentView else null,
+ description =
+ if (flagEnabled && request.contentView != null) "" else request.description,
icon = applicationContext.asLockIcon(request.userInfo.deviceCredentialOwnerId),
showEmergencyCallButton = request.showEmergencyCallButton
)
@@ -188,6 +196,7 @@
override val title: String,
override val subtitle: String,
override val description: String,
+ override val contentView: PromptContentView?,
override val icon: Drawable,
override val showEmergencyCallButton: Boolean,
) : CredentialHeaderViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
index d849b3a..94e0854 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
@@ -20,7 +20,6 @@
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableStateFlow
/** Provides access to bouncer-related application state. */
@SysUISingleton
@@ -29,9 +28,6 @@
constructor(
private val flags: FeatureFlagsClassic,
) {
- /** The user-facing message to show in the bouncer. */
- val message = MutableStateFlow<String?>(null)
-
/** Whether the user switcher should be displayed within the bouncer UI on large screens. */
val isUserSwitcherVisible: Boolean
get() = flags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)
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 d8be1af..aeb564d5 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
@@ -16,13 +16,8 @@
package com.android.systemui.bouncer.domain.interactor
-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
@@ -31,7 +26,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
@@ -41,7 +35,6 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
/** Encapsulates business logic and application state accessing use-cases. */
@SysUISingleton
@@ -49,16 +42,14 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- @Application private val applicationContext: Context,
private val repository: BouncerRepository,
private val authenticationInteractor: AuthenticationInteractor,
private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
private val falsingInteractor: FalsingInteractor,
private val powerInteractor: PowerInteractor,
- private val simBouncerInteractor: SimBouncerInteractor,
) {
- /** The user-facing message to show in the bouncer when lockout is not active. */
- val message: StateFlow<String?> = repository.message
+ private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>()
+ val onIncorrectBouncerInput: SharedFlow<Unit> = _onIncorrectBouncerInput
/** Whether the auto confirm feature is enabled for the currently-selected user. */
val isAutoConfirmEnabled: StateFlow<Boolean> = authenticationInteractor.isAutoConfirmEnabled
@@ -119,25 +110,6 @@
)
}
- fun setMessage(message: String?) {
- repository.message.value = message
- }
-
- /**
- * Resets the user-facing message back to the default according to the current authentication
- * method.
- */
- fun resetMessage() {
- applicationScope.launch {
- setMessage(promptMessage(authenticationInteractor.getAuthenticationMethod()))
- }
- }
-
- /** Removes the user-facing message. */
- fun clearMessage() {
- setMessage(null)
- }
-
/**
* Attempts to authenticate based on the given user input.
*
@@ -176,50 +148,17 @@
.async { authenticationInteractor.authenticate(input, tryAutoConfirm) }
.await()
- if (authenticationInteractor.lockoutEndTimestamp != null) {
- clearMessage()
- } else if (
+ if (
authResult == AuthenticationResult.FAILED ||
(authResult == AuthenticationResult.SKIPPED && !tryAutoConfirm)
) {
- showWrongInputMessage()
+ _onIncorrectBouncerInput.emit(Unit)
}
return authResult
}
- /**
- * 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 showWrongInputMessage() {
- setMessage(wrongInputMessage(authenticationInteractor.getAuthenticationMethod()))
- }
-
/** Notifies that the input method editor (software keyboard) has been hidden by the user. */
suspend fun onImeHiddenByUser() {
_onImeHiddenByUser.emit(Unit)
}
-
- private fun promptMessage(authMethod: AuthenticationMethodModel): String {
- return when (authMethod) {
- 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 wrongInputMessage(authMethod: AuthenticationMethodModel): String {
- return when (authMethod) {
- 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 7f6fc91..d20c607 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
@@ -33,15 +33,17 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.user.data.repository.UserRepository
-import com.android.systemui.util.kotlin.Quint
+import com.android.systemui.util.kotlin.Sextuple
+import com.android.systemui.util.kotlin.combine
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
@@ -56,6 +58,7 @@
private const val TAG = "BouncerMessageInteractor"
/** Handles business logic for the primary bouncer message area. */
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class BouncerMessageInteractor
@Inject
@@ -63,23 +66,24 @@
private val repository: BouncerMessageRepository,
private val userRepository: UserRepository,
private val countDownTimerUtil: CountDownTimerUtil,
- private val updateMonitor: KeyguardUpdateMonitor,
+ updateMonitor: KeyguardUpdateMonitor,
trustRepository: TrustRepository,
biometricSettingsRepository: BiometricSettingsRepository,
private val systemPropertiesHelper: SystemPropertiesHelper,
primaryBouncerInteractor: PrimaryBouncerInteractor,
@Application private val applicationScope: CoroutineScope,
private val facePropertyRepository: FacePropertyRepository,
- deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
faceAuthRepository: DeviceEntryFaceAuthRepository,
private val securityModel: KeyguardSecurityModel,
) {
- private val isFingerprintAuthCurrentlyAllowed =
- deviceEntryFingerprintAuthRepository.isLockedOut
- .isFalse()
- .and(biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed)
- .stateIn(applicationScope, SharingStarted.Eagerly, false)
+ private val isFingerprintAuthCurrentlyAllowedOnBouncer =
+ deviceEntryFingerprintAuthInteractor.isFingerprintCurrentlyAllowedOnBouncer.stateIn(
+ applicationScope,
+ SharingStarted.Eagerly,
+ false
+ )
private val currentSecurityMode
get() = securityModel.getSecurityMode(currentUserId)
@@ -99,13 +103,13 @@
BiometricSourceType.FACE ->
BouncerMessageStrings.incorrectFaceInput(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
else ->
BouncerMessageStrings.defaultMessage(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
}
@@ -144,11 +148,12 @@
biometricSettingsRepository.authenticationFlags,
trustRepository.isCurrentUserTrustManaged,
isAnyBiometricsEnabledAndEnrolled,
- deviceEntryFingerprintAuthRepository.isLockedOut,
+ deviceEntryFingerprintAuthInteractor.isLockedOut,
faceAuthRepository.isLockedOut,
- ::Quint
+ isFingerprintAuthCurrentlyAllowedOnBouncer,
+ ::Sextuple
)
- .map { (flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut) ->
+ .map { (flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut, _) ->
val isTrustUsuallyManaged = trustRepository.isCurrentUserTrustUsuallyManaged.value
val trustOrBiometricsAvailable =
(isTrustUsuallyManaged || biometricsEnrolledAndEnabled)
@@ -193,14 +198,14 @@
} else {
BouncerMessageStrings.faceLockedOut(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
}
} else if (flags.isSomeAuthRequiredAfterAdaptiveAuthRequest) {
BouncerMessageStrings.authRequiredAfterAdaptiveAuthRequest(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
} else if (
@@ -209,19 +214,19 @@
) {
BouncerMessageStrings.nonStrongAuthTimeout(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
} else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterUserRequest) {
BouncerMessageStrings.trustAgentDisabled(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
} else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
BouncerMessageStrings.trustAgentDisabled(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
} else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
@@ -265,7 +270,7 @@
repository.setMessage(
BouncerMessageStrings.incorrectSecurityInput(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
)
@@ -274,14 +279,22 @@
fun setFingerprintAcquisitionMessage(value: String?) {
if (!Flags.revampedBouncerMessages()) return
repository.setMessage(
- defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
+ defaultMessage(
+ currentSecurityMode,
+ value,
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ )
)
}
fun setFaceAcquisitionMessage(value: String?) {
if (!Flags.revampedBouncerMessages()) return
repository.setMessage(
- defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
+ defaultMessage(
+ currentSecurityMode,
+ value,
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ )
)
}
@@ -289,7 +302,11 @@
if (!Flags.revampedBouncerMessages()) return
repository.setMessage(
- defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
+ defaultMessage(
+ currentSecurityMode,
+ value,
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
+ )
)
}
@@ -297,7 +314,7 @@
get() =
BouncerMessageStrings.defaultMessage(
currentSecurityMode.toAuthModel(),
- isFingerprintAuthCurrentlyAllowed.value
+ isFingerprintAuthCurrentlyAllowedOnBouncer.value
)
.toMessage()
@@ -355,11 +372,6 @@
private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) =
this.combine(anotherFlow) { a, b -> a || b }
-private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>) =
- this.combine(anotherFlow) { a, b -> a && b }
-
-private fun Flow<Boolean>.isFalse() = this.map { !it }
-
private fun defaultMessage(
securityMode: SecurityMode,
secondaryMessage: String?,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
index f3903de..aebc50f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt
@@ -18,6 +18,7 @@
import android.app.AlertDialog
import android.content.Context
+import com.android.systemui.bouncer.ui.viewmodel.BouncerMessageViewModelModule
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModelModule
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -30,6 +31,7 @@
includes =
[
BouncerViewModelModule::class,
+ BouncerMessageViewModelModule::class,
],
)
interface BouncerViewModule {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index 0d7f6dc..4fbf735 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -57,17 +57,11 @@
*/
@get:StringRes abstract val lockoutMessageId: Int
- /** Notifies that the UI has been shown to the user. */
- fun onShown() {
- interactor.resetMessage()
- }
-
/**
* Notifies that the UI has been hidden from the user (after any transitions have completed).
*/
open fun onHidden() {
clearInput()
- interactor.resetMessage()
}
/** Notifies that the user has placed down a pointer. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
new file mode 100644
index 0000000..6cb9b16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
@@ -0,0 +1,436 @@
+/*
+ * 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.bouncer.ui.viewmodel
+
+import android.content.Context
+import android.util.PluralsMessageFormatter
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
+import com.android.systemui.bouncer.shared.model.BouncerMessagePair
+import com.android.systemui.bouncer.shared.model.BouncerMessageStrings
+import com.android.systemui.bouncer.shared.model.primaryMessage
+import com.android.systemui.bouncer.shared.model.secondaryMessage
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.shared.model.DeviceEntryRestrictionReason
+import com.android.systemui.deviceentry.shared.model.FaceFailureMessage
+import com.android.systemui.deviceentry.shared.model.FaceLockoutMessage
+import com.android.systemui.deviceentry.shared.model.FaceTimeoutMessage
+import com.android.systemui.deviceentry.shared.model.FingerprintFailureMessage
+import com.android.systemui.deviceentry.shared.model.FingerprintLockoutMessage
+import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.user.ui.viewmodel.UserViewModel
+import com.android.systemui.util.kotlin.Utils.Companion.sample
+import com.android.systemui.util.time.SystemClock
+import dagger.Module
+import dagger.Provides
+import kotlin.math.ceil
+import kotlin.math.max
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/** Holds UI state for the 2-line status message shown on the bouncer. */
+@OptIn(ExperimentalCoroutinesApi::class)
+class BouncerMessageViewModel(
+ @Application private val applicationContext: Context,
+ @Application private val applicationScope: CoroutineScope,
+ private val bouncerInteractor: BouncerInteractor,
+ private val simBouncerInteractor: SimBouncerInteractor,
+ private val authenticationInteractor: AuthenticationInteractor,
+ selectedUser: Flow<UserViewModel>,
+ private val clock: SystemClock,
+ private val biometricMessageInteractor: BiometricMessageInteractor,
+ private val faceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ private val deviceEntryInteractor: DeviceEntryInteractor,
+ private val fingerprintInteractor: DeviceEntryFingerprintAuthInteractor,
+ flags: ComposeBouncerFlags,
+) {
+ /**
+ * A message shown when the user has attempted the wrong credential too many times and now must
+ * wait a while before attempting to authenticate again.
+ *
+ * This is updated every second (countdown) during the lockout. When lockout is not active, this
+ * is `null` and no lockout message should be shown.
+ */
+ private val lockoutMessage: MutableStateFlow<MessageViewModel?> = MutableStateFlow(null)
+
+ /** Whether there is a lockout message that is available to be shown in the status message. */
+ val isLockoutMessagePresent: Flow<Boolean> = lockoutMessage.map { it != null }
+
+ /** The user-facing message to show in the bouncer. */
+ val message: MutableStateFlow<MessageViewModel?> = MutableStateFlow(null)
+
+ /** Initializes the bouncer message to default whenever it is shown. */
+ fun onShown() {
+ showDefaultMessage()
+ }
+
+ /** Reset the message shown on the bouncer to the default message. */
+ fun showDefaultMessage() {
+ resetToDefault.tryEmit(Unit)
+ }
+
+ private val resetToDefault = MutableSharedFlow<Unit>(replay = 1)
+
+ private var lockoutCountdownJob: Job? = null
+
+ private fun defaultBouncerMessageInitializer() {
+ applicationScope.launch {
+ resetToDefault.emit(Unit)
+ authenticationInteractor.authenticationMethod
+ .flatMapLatest { authMethod ->
+ if (authMethod == AuthenticationMethodModel.Sim) {
+ resetToDefault.map {
+ MessageViewModel(simBouncerInteractor.getDefaultMessage())
+ }
+ } else if (authMethod.isSecure) {
+ combine(
+ deviceEntryInteractor.deviceEntryRestrictionReason,
+ lockoutMessage,
+ fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer,
+ resetToDefault,
+ ) { deviceEntryRestrictedReason, lockoutMsg, isFpAllowedInBouncer, _ ->
+ lockoutMsg
+ ?: deviceEntryRestrictedReason.toMessage(
+ authMethod,
+ isFpAllowedInBouncer
+ )
+ }
+ } else {
+ emptyFlow()
+ }
+ }
+ .collectLatest { messageViewModel -> message.value = messageViewModel }
+ }
+ }
+
+ private fun listenForSimBouncerEvents() {
+ // Listen for any events from the SIM bouncer and update the message shown on the bouncer.
+ applicationScope.launch {
+ authenticationInteractor.authenticationMethod
+ .flatMapLatest { authMethod ->
+ if (authMethod == AuthenticationMethodModel.Sim) {
+ simBouncerInteractor.bouncerMessageChanged.map { simMsg ->
+ simMsg?.let { MessageViewModel(it) }
+ }
+ } else {
+ emptyFlow()
+ }
+ }
+ .collectLatest {
+ if (it != null) {
+ message.value = it
+ } else {
+ resetToDefault.emit(Unit)
+ }
+ }
+ }
+ }
+
+ private fun listenForFaceMessages() {
+ // Listen for any events from face authentication and update the message shown on the
+ // bouncer.
+ applicationScope.launch {
+ biometricMessageInteractor.faceMessage
+ .sample(
+ authenticationInteractor.authenticationMethod,
+ fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer,
+ )
+ .collectLatest { (faceMessage, authMethod, fingerprintAllowedOnBouncer) ->
+ val isFaceAuthStrong = faceAuthInteractor.isFaceAuthStrong()
+ val defaultPrimaryMessage =
+ BouncerMessageStrings.defaultMessage(
+ authMethod,
+ fingerprintAllowedOnBouncer
+ )
+ .primaryMessage
+ .toResString()
+ message.value =
+ when (faceMessage) {
+ is FaceTimeoutMessage ->
+ MessageViewModel(
+ text = defaultPrimaryMessage,
+ secondaryText = faceMessage.message,
+ isUpdateAnimated = true
+ )
+ is FaceLockoutMessage ->
+ if (isFaceAuthStrong)
+ BouncerMessageStrings.class3AuthLockedOut(authMethod)
+ .toMessage()
+ else
+ BouncerMessageStrings.faceLockedOut(
+ authMethod,
+ fingerprintAllowedOnBouncer
+ )
+ .toMessage()
+ is FaceFailureMessage ->
+ BouncerMessageStrings.incorrectFaceInput(
+ authMethod,
+ fingerprintAllowedOnBouncer
+ )
+ .toMessage()
+ else ->
+ MessageViewModel(
+ text = defaultPrimaryMessage,
+ secondaryText = faceMessage.message,
+ isUpdateAnimated = false
+ )
+ }
+ delay(MESSAGE_DURATION)
+ resetToDefault.emit(Unit)
+ }
+ }
+ }
+
+ private fun listenForFingerprintMessages() {
+ applicationScope.launch {
+ // Listen for any events from fingerprint authentication and update the message shown
+ // on the bouncer.
+ biometricMessageInteractor.fingerprintMessage
+ .sample(
+ authenticationInteractor.authenticationMethod,
+ fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer
+ )
+ .collectLatest { (fingerprintMessage, authMethod, isFingerprintAllowed) ->
+ val defaultPrimaryMessage =
+ BouncerMessageStrings.defaultMessage(authMethod, isFingerprintAllowed)
+ .primaryMessage
+ .toResString()
+ message.value =
+ when (fingerprintMessage) {
+ is FingerprintLockoutMessage ->
+ BouncerMessageStrings.class3AuthLockedOut(authMethod).toMessage()
+ is FingerprintFailureMessage ->
+ BouncerMessageStrings.incorrectFingerprintInput(authMethod)
+ .toMessage()
+ else ->
+ MessageViewModel(
+ text = defaultPrimaryMessage,
+ secondaryText = fingerprintMessage.message,
+ isUpdateAnimated = false
+ )
+ }
+ delay(MESSAGE_DURATION)
+ resetToDefault.emit(Unit)
+ }
+ }
+ }
+
+ private fun listenForBouncerEvents() {
+ // Keeps the lockout message up-to-date.
+ applicationScope.launch {
+ bouncerInteractor.onLockoutStarted.collect { startLockoutCountdown() }
+ }
+
+ // Listens to relevant bouncer events
+ applicationScope.launch {
+ bouncerInteractor.onIncorrectBouncerInput
+ .sample(
+ authenticationInteractor.authenticationMethod,
+ fingerprintInteractor.isFingerprintCurrentlyAllowedOnBouncer
+ )
+ .collectLatest { (_, authMethod, isFingerprintAllowed) ->
+ message.emit(
+ BouncerMessageStrings.incorrectSecurityInput(
+ authMethod,
+ isFingerprintAllowed
+ )
+ .toMessage()
+ )
+ delay(MESSAGE_DURATION)
+ resetToDefault.emit(Unit)
+ }
+ }
+ }
+
+ private fun DeviceEntryRestrictionReason?.toMessage(
+ authMethod: AuthenticationMethodModel,
+ isFingerprintAllowedOnBouncer: Boolean,
+ ): MessageViewModel {
+ return when (this) {
+ DeviceEntryRestrictionReason.UserLockdown ->
+ BouncerMessageStrings.authRequiredAfterUserLockdown(authMethod)
+ DeviceEntryRestrictionReason.DeviceNotUnlockedSinceReboot ->
+ BouncerMessageStrings.authRequiredAfterReboot(authMethod)
+ DeviceEntryRestrictionReason.PolicyLockdown ->
+ BouncerMessageStrings.authRequiredAfterAdminLockdown(authMethod)
+ DeviceEntryRestrictionReason.UnattendedUpdate ->
+ BouncerMessageStrings.authRequiredForUnattendedUpdate(authMethod)
+ DeviceEntryRestrictionReason.DeviceNotUnlockedSinceMainlineUpdate ->
+ BouncerMessageStrings.authRequiredForMainlineUpdate(authMethod)
+ DeviceEntryRestrictionReason.SecurityTimeout ->
+ BouncerMessageStrings.authRequiredAfterPrimaryAuthTimeout(authMethod)
+ DeviceEntryRestrictionReason.StrongBiometricsLockedOut ->
+ BouncerMessageStrings.class3AuthLockedOut(authMethod)
+ DeviceEntryRestrictionReason.NonStrongFaceLockedOut ->
+ BouncerMessageStrings.faceLockedOut(authMethod, isFingerprintAllowedOnBouncer)
+ DeviceEntryRestrictionReason.NonStrongBiometricsSecurityTimeout ->
+ BouncerMessageStrings.nonStrongAuthTimeout(
+ authMethod,
+ isFingerprintAllowedOnBouncer
+ )
+ DeviceEntryRestrictionReason.TrustAgentDisabled ->
+ BouncerMessageStrings.trustAgentDisabled(authMethod, isFingerprintAllowedOnBouncer)
+ DeviceEntryRestrictionReason.AdaptiveAuthRequest ->
+ BouncerMessageStrings.authRequiredAfterAdaptiveAuthRequest(
+ authMethod,
+ isFingerprintAllowedOnBouncer
+ )
+ else -> BouncerMessageStrings.defaultMessage(authMethod, isFingerprintAllowedOnBouncer)
+ }.toMessage()
+ }
+
+ private fun BouncerMessagePair.toMessage(): MessageViewModel {
+ val primaryMsg = this.primaryMessage.toResString()
+ val secondaryMsg =
+ if (this.secondaryMessage == 0) "" else this.secondaryMessage.toResString()
+ return MessageViewModel(primaryMsg, secondaryText = secondaryMsg, isUpdateAnimated = true)
+ }
+
+ /** Shows the countdown message and refreshes it every second. */
+ private fun startLockoutCountdown() {
+ lockoutCountdownJob?.cancel()
+ lockoutCountdownJob =
+ applicationScope.launch {
+ authenticationInteractor.authenticationMethod.collectLatest { authMethod ->
+ do {
+ val remainingSeconds = remainingLockoutSeconds()
+ val authLockedOutMsg =
+ BouncerMessageStrings.primaryAuthLockedOut(authMethod)
+ lockoutMessage.value =
+ if (remainingSeconds > 0) {
+ MessageViewModel(
+ text =
+ kg_too_many_failed_attempts_countdown.toPluralString(
+ mutableMapOf<String, Any>(
+ Pair("count", remainingSeconds)
+ )
+ ),
+ secondaryText = authLockedOutMsg.secondaryMessage.toResString(),
+ isUpdateAnimated = false
+ )
+ } else {
+ null
+ }
+ delay(1.seconds)
+ } while (remainingSeconds > 0)
+ lockoutCountdownJob = null
+ }
+ }
+ }
+
+ private fun remainingLockoutSeconds(): Int {
+ val endTimestampMs = authenticationInteractor.lockoutEndTimestamp ?: 0
+ val remainingMs = max(0, endTimestampMs - clock.elapsedRealtime())
+ return ceil(remainingMs / 1000f).toInt()
+ }
+
+ private fun Int.toPluralString(formatterArgs: Map<String, Any>): String =
+ PluralsMessageFormatter.format(applicationContext.resources, formatterArgs, this)
+
+ private fun Int.toResString(): String = applicationContext.getString(this)
+
+ init {
+ if (flags.isComposeBouncerOrSceneContainerEnabled()) {
+ applicationScope.launch {
+ // Update the lockout countdown whenever the selected user is switched.
+ selectedUser.collect { startLockoutCountdown() }
+ }
+
+ defaultBouncerMessageInitializer()
+
+ listenForSimBouncerEvents()
+ listenForBouncerEvents()
+ listenForFaceMessages()
+ listenForFingerprintMessages()
+ }
+ }
+
+ companion object {
+ private const val MESSAGE_DURATION = 2000L
+ }
+}
+
+/** Data class that represents the status message show on the bouncer. */
+data class MessageViewModel(
+ val text: String,
+ val secondaryText: String? = null,
+ /**
+ * Whether updates to the message should be cross-animated from one message to another.
+ *
+ * If `false`, no animation should be applied, the message text should just be replaced
+ * instantly.
+ */
+ val isUpdateAnimated: Boolean = true,
+)
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@Module
+object BouncerMessageViewModelModule {
+
+ @Provides
+ @SysUISingleton
+ fun viewModel(
+ @Application applicationContext: Context,
+ @Application applicationScope: CoroutineScope,
+ bouncerInteractor: BouncerInteractor,
+ simBouncerInteractor: SimBouncerInteractor,
+ authenticationInteractor: AuthenticationInteractor,
+ clock: SystemClock,
+ biometricMessageInteractor: BiometricMessageInteractor,
+ faceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ deviceEntryInteractor: DeviceEntryInteractor,
+ fingerprintInteractor: DeviceEntryFingerprintAuthInteractor,
+ flags: ComposeBouncerFlags,
+ userSwitcherViewModel: UserSwitcherViewModel,
+ ): BouncerMessageViewModel {
+ return BouncerMessageViewModel(
+ applicationContext = applicationContext,
+ applicationScope = applicationScope,
+ bouncerInteractor = bouncerInteractor,
+ simBouncerInteractor = simBouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
+ clock = clock,
+ biometricMessageInteractor = biometricMessageInteractor,
+ faceAuthInteractor = faceAuthInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
+ fingerprintInteractor = fingerprintInteractor,
+ flags = flags,
+ selectedUser = userSwitcherViewModel.selectedUser,
+ )
+ }
+}
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 6287578..5c07cc5 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
@@ -21,7 +21,6 @@
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
@@ -40,18 +39,12 @@
import com.android.systemui.user.ui.viewmodel.UserActionViewModel
import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
import com.android.systemui.user.ui.viewmodel.UserViewModel
-import com.android.systemui.util.time.SystemClock
import dagger.Module
import dagger.Provides
-import kotlin.math.ceil
-import kotlin.math.max
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -72,13 +65,13 @@
private val simBouncerInteractor: SimBouncerInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val selectedUserInteractor: SelectedUserInteractor,
+ private val devicePolicyManager: DevicePolicyManager,
+ bouncerMessageViewModel: BouncerMessageViewModel,
flags: ComposeBouncerFlags,
selectedUser: Flow<UserViewModel>,
users: Flow<List<UserViewModel>>,
userSwitcherMenu: Flow<List<UserActionViewModel>>,
actionButton: Flow<BouncerActionButtonModel?>,
- private val clock: SystemClock,
- private val devicePolicyManager: DevicePolicyManager,
) {
val selectedUserImage: StateFlow<Bitmap?> =
selectedUser
@@ -89,6 +82,8 @@
initialValue = null,
)
+ val message: BouncerMessageViewModel = bouncerMessageViewModel
+
val userSwitcherDropdown: StateFlow<List<UserSwitcherDropdownItemViewModel>> =
combine(
users,
@@ -163,24 +158,6 @@
)
/**
- * A message shown when the user has attempted the wrong credential too many times and now must
- * wait a while before attempting to authenticate again.
- *
- * This is updated every second (countdown) during the lockout duration. When lockout is not
- * active, this is `null` and no lockout message should be shown.
- */
- private val lockoutMessage = MutableStateFlow<String?>(null)
-
- /** The user-facing message to show in the bouncer. */
- val message: StateFlow<MessageViewModel> =
- combine(bouncerInteractor.message, lockoutMessage) { _, _ -> createMessageViewModel() }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = createMessageViewModel(),
- )
-
- /**
* The bouncer action button (Return to Call / Emergency Call). If `null`, the button should not
* be shown.
*/
@@ -222,31 +199,16 @@
)
private val isInputEnabled: StateFlow<Boolean> =
- lockoutMessage
- .map { it == null }
+ bouncerMessageViewModel.isLockoutMessagePresent
+ .map { lockoutMessagePresent -> !lockoutMessagePresent }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = authenticationInteractor.lockoutEndTimestamp == null,
)
- private var lockoutCountdownJob: Job? = null
-
init {
if (flags.isComposeBouncerOrSceneContainerEnabled()) {
- // Keeps the lockout dialog up-to-date.
- applicationScope.launch {
- bouncerInteractor.onLockoutStarted.collect {
- showLockoutDialog()
- startLockoutCountdown()
- }
- }
-
- applicationScope.launch {
- // Update the lockout countdown whenever the selected user is switched.
- selectedUser.collect { startLockoutCountdown() }
- }
-
// Keeps the upcoming wipe dialog up-to-date.
applicationScope.launch {
authenticationInteractor.upcomingWipe.collect { wipeModel ->
@@ -256,48 +218,6 @@
}
}
- private fun showLockoutDialog() {
- applicationScope.launch {
- val failedAttempts = authenticationInteractor.failedAuthenticationAttempts.value
- lockoutDialogMessage.value =
- authMethodViewModel.value?.lockoutMessageId?.let { messageId ->
- applicationContext.getString(
- messageId,
- failedAttempts,
- remainingLockoutSeconds()
- )
- }
- }
- }
-
- /** Shows the countdown message and refreshes it every second. */
- private fun startLockoutCountdown() {
- lockoutCountdownJob?.cancel()
- lockoutCountdownJob =
- applicationScope.launch {
- do {
- val remainingSeconds = remainingLockoutSeconds()
- lockoutMessage.value =
- if (remainingSeconds > 0) {
- applicationContext.getString(
- R.string.lockscreen_too_many_failed_attempts_countdown,
- remainingSeconds,
- )
- } else {
- null
- }
- delay(1.seconds)
- } while (remainingSeconds > 0)
- lockoutCountdownJob = null
- }
- }
-
- private fun remainingLockoutSeconds(): Int {
- val endTimestampMs = authenticationInteractor.lockoutEndTimestamp ?: 0
- val remainingMs = max(0, endTimestampMs - clock.elapsedRealtime())
- return ceil(remainingMs / 1000f).toInt()
- }
-
private fun isSideBySideSupported(authMethod: AuthMethodBouncerViewModel?): Boolean {
return isUserSwitcherVisible || authMethod !is PasswordBouncerViewModel
}
@@ -306,15 +226,6 @@
return authMethod !is PasswordBouncerViewModel
}
- private fun createMessageViewModel(): MessageViewModel {
- val isLockedOut = lockoutMessage.value != null
- return MessageViewModel(
- // A lockout message takes precedence over the non-lockout message.
- text = lockoutMessage.value ?: bouncerInteractor.message.value ?: "",
- isUpdateAnimated = !isLockedOut,
- )
- }
-
private fun getChildViewModel(
authenticationMethod: AuthenticationMethodModel,
): AuthMethodBouncerViewModel? {
@@ -336,7 +247,8 @@
interactor = bouncerInteractor,
isInputEnabled = isInputEnabled,
simBouncerInteractor = simBouncerInteractor,
- authenticationMethod = authenticationMethod
+ authenticationMethod = authenticationMethod,
+ onIntentionalUserInput = ::onIntentionalUserInput
)
is AuthenticationMethodModel.Sim ->
PinBouncerViewModel(
@@ -346,6 +258,7 @@
isInputEnabled = isInputEnabled,
simBouncerInteractor = simBouncerInteractor,
authenticationMethod = authenticationMethod,
+ onIntentionalUserInput = ::onIntentionalUserInput
)
is AuthenticationMethodModel.Password ->
PasswordBouncerViewModel(
@@ -354,6 +267,7 @@
interactor = bouncerInteractor,
inputMethodInteractor = inputMethodInteractor,
selectedUserInteractor = selectedUserInteractor,
+ onIntentionalUserInput = ::onIntentionalUserInput
)
is AuthenticationMethodModel.Pattern ->
PatternBouncerViewModel(
@@ -361,11 +275,17 @@
viewModelScope = newViewModelScope,
interactor = bouncerInteractor,
isInputEnabled = isInputEnabled,
+ onIntentionalUserInput = ::onIntentionalUserInput
)
else -> null
}
}
+ private fun onIntentionalUserInput() {
+ message.showDefaultMessage()
+ bouncerInteractor.onIntentionalUserInput()
+ }
+
private fun createChildCoroutineScope(parentScope: CoroutineScope): CoroutineScope {
return CoroutineScope(
SupervisorJob(parent = parentScope.coroutineContext.job) + mainDispatcher
@@ -437,18 +357,6 @@
}
}
- data class MessageViewModel(
- val text: String,
-
- /**
- * Whether updates to the message should be cross-animated from one message to another.
- *
- * If `false`, no animation should be applied, the message text should just be replaced
- * instantly.
- */
- val isUpdateAnimated: Boolean,
- )
-
data class DialogViewModel(
val text: String,
@@ -480,8 +388,8 @@
selectedUserInteractor: SelectedUserInteractor,
flags: ComposeBouncerFlags,
userSwitcherViewModel: UserSwitcherViewModel,
- clock: SystemClock,
devicePolicyManager: DevicePolicyManager,
+ bouncerMessageViewModel: BouncerMessageViewModel,
): BouncerViewModel {
return BouncerViewModel(
applicationContext = applicationContext,
@@ -497,8 +405,8 @@
users = userSwitcherViewModel.users,
userSwitcherMenu = userSwitcherViewModel.menu,
actionButton = actionButtonInteractor.actionButton,
- clock = clock,
devicePolicyManager = devicePolicyManager,
+ bouncerMessageViewModel = bouncerMessageViewModel,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index b42eda1..052fb6b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -40,6 +40,7 @@
viewModelScope: CoroutineScope,
isInputEnabled: StateFlow<Boolean>,
interactor: BouncerInteractor,
+ private val onIntentionalUserInput: () -> Unit,
private val inputMethodInteractor: InputMethodInteractor,
private val selectedUserInteractor: SelectedUserInteractor,
) :
@@ -96,12 +97,8 @@
/** Notifies that the user has changed the password input. */
fun onPasswordInputChanged(newPassword: String) {
- if (this.password.value.isEmpty() && newPassword.isNotEmpty()) {
- interactor.clearMessage()
- }
-
if (newPassword.isNotEmpty()) {
- interactor.onIntentionalUserInput()
+ onIntentionalUserInput()
}
_password.value = newPassword
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 69f8032..a401600 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -40,6 +40,7 @@
viewModelScope: CoroutineScope,
interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
+ private val onIntentionalUserInput: () -> Unit,
) :
AuthMethodBouncerViewModel(
viewModelScope = viewModelScope,
@@ -84,7 +85,7 @@
/** Notifies that the user has started a drag gesture across the dot grid. */
fun onDragStart() {
- interactor.clearMessage()
+ onIntentionalUserInput()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index e910a92..62da5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -41,6 +41,7 @@
viewModelScope: CoroutineScope,
interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
+ private val onIntentionalUserInput: () -> Unit,
private val simBouncerInteractor: SimBouncerInteractor,
authenticationMethod: AuthenticationMethodModel,
) :
@@ -131,11 +132,8 @@
/** Notifies that the user clicked on a PIN button with the given digit value. */
fun onPinButtonClicked(input: Int) {
val pinInput = mutablePinInput.value
- if (pinInput.isEmpty()) {
- interactor.clearMessage()
- }
- interactor.onIntentionalUserInput()
+ onIntentionalUserInput()
mutablePinInput.value = pinInput.append(input)
tryAuthenticate(useAutoConfirm = true)
@@ -149,7 +147,6 @@
/** Notifies that the user long-pressed the backspace button. */
fun onBackspaceButtonLongPressed() {
clearInput()
- interactor.clearMessage()
}
/** Notifies that the user clicked the "enter" button. */
@@ -173,7 +170,6 @@
/** Resets the sim screen and shows a default message. */
private fun onResetSimFlow() {
simBouncerInteractor.resetSimPukUserInput()
- interactor.resetMessage()
clearInput()
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/NotificationContainerBounds.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/NotificationContainerBounds.kt
index 3063ebd..fdd98bec 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/NotificationContainerBounds.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/NotificationContainerBounds.kt
@@ -18,12 +18,8 @@
/** Models the bounds of the notification container. */
data class NotificationContainerBounds(
- /** The position of the left of the container in its window coordinate system, in pixels. */
- val left: Float = 0f,
/** The position of the top of the container in its window coordinate system, in pixels. */
val top: Float = 0f,
- /** The position of the right of the container in its window coordinate system, in pixels. */
- val right: Float = 0f,
/** The position of the bottom of the container in its window coordinate system, in pixels. */
val bottom: Float = 0f,
/** Whether any modifications to top/bottom should be smoothly animated. */
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
index 964eb6f..578389b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -54,6 +54,18 @@
}
/**
+ * Returns a [Flow] that emits a dimension pixel size that is kept in sync with the device
+ * configuration.
+ *
+ * @see android.content.res.Resources.getDimensionPixelSize
+ */
+ fun getDimensionPixelOffset(@DimenRes id: Int): Flow<Int> {
+ return configurationController.onDensityOrFontScaleChanged.emitOnStart().map {
+ context.resources.getDimensionPixelOffset(id)
+ }
+ }
+
+ /**
* Returns a [Flow] that emits a color that is kept in sync with the device theme.
*
* @see Utils.getColorAttrDefaultColor
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 5fabd3c..fc8d658 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -154,5 +154,5 @@
fun isWidgetContent() = this is WidgetContent
- fun isSmartspace() = this is Smartspace
+ fun isLiveContent() = this is Smartspace || this is Umo
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index bfe751a..afa7c37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -16,24 +16,36 @@
package com.android.systemui.communal.ui.viewmodel
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProviderInfo
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.util.Log
+import androidx.activity.result.ActivityResultLauncher
import com.android.internal.logging.UiEventLogger
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
import javax.inject.Inject
import javax.inject.Named
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.withContext
/** The view model for communal hub in edit mode. */
@SysUISingleton
@@ -45,6 +57,7 @@
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
private val uiEventLogger: UiEventLogger,
@CommunalLog logBuffer: LogBuffer,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) : BaseCommunalViewModel(communalInteractor, mediaHost) {
private val logger = Logger(logBuffer, "CommunalEditModeViewModel")
@@ -86,10 +99,77 @@
uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
}
- /** Returns the widget categories to show on communal hub. */
- val getCommunalWidgetCategories: Int
- get() = communalSettingsInteractor.communalWidgetCategories.value
+ /** Launch the widget picker activity using the given {@link ActivityResultLauncher}. */
+ suspend fun onOpenWidgetPicker(
+ resources: Resources,
+ packageManager: PackageManager,
+ activityLauncher: ActivityResultLauncher<Intent>
+ ): Boolean =
+ withContext(backgroundDispatcher) {
+ val widgets = communalInteractor.widgetContent.first()
+ val excludeList = widgets.mapTo(ArrayList()) { it.providerInfo }
+ getWidgetPickerActivityIntent(resources, packageManager, excludeList)?.let {
+ try {
+ activityLauncher.launch(it)
+ return@withContext true
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to launch widget picker activity", e)
+ }
+ }
+ false
+ }
+
+ private fun getWidgetPickerActivityIntent(
+ resources: Resources,
+ packageManager: PackageManager,
+ excludeList: ArrayList<AppWidgetProviderInfo>
+ ): Intent? {
+ val packageName =
+ getLauncherPackageName(packageManager)
+ ?: run {
+ Log.e(TAG, "Couldn't resolve launcher package name")
+ return@getWidgetPickerActivityIntent null
+ }
+
+ return Intent(Intent.ACTION_PICK).apply {
+ setPackage(packageName)
+ putExtra(
+ EXTRA_DESIRED_WIDGET_WIDTH,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
+ )
+ putExtra(
+ EXTRA_DESIRED_WIDGET_HEIGHT,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
+ )
+ putExtra(
+ AppWidgetManager.EXTRA_CATEGORY_FILTER,
+ communalSettingsInteractor.communalWidgetCategories.value
+ )
+ putExtra(EXTRA_UI_SURFACE_KEY, EXTRA_UI_SURFACE_VALUE)
+ putParcelableArrayListExtra(EXTRA_ADDED_APP_WIDGETS_KEY, excludeList)
+ }
+ }
+
+ private fun getLauncherPackageName(packageManager: PackageManager): String? {
+ return packageManager
+ .resolveActivity(
+ Intent(Intent.ACTION_MAIN).also { it.addCategory(Intent.CATEGORY_HOME) },
+ PackageManager.MATCH_DEFAULT_ONLY
+ )
+ ?.activityInfo
+ ?.packageName
+ }
/** Sets whether edit mode is currently open */
fun setEditModeOpen(isOpen: Boolean) = communalInteractor.setEditModeOpen(isOpen)
+
+ companion object {
+ private const val TAG = "CommunalEditModeViewModel"
+
+ private const val EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width"
+ private const val EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height"
+ private const val EXTRA_UI_SURFACE_KEY = "ui_surface"
+ private const val EXTRA_UI_SURFACE_VALUE = "widgets_hub"
+ const val EXTRA_ADDED_APP_WIDGETS_KEY = "added_app_widgets"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index b6ad26b..ba18f01 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -16,9 +16,7 @@
package com.android.systemui.communal.widgets
-import android.appwidget.AppWidgetManager
import android.content.Intent
-import android.content.pm.PackageManager
import android.os.Bundle
import android.os.RemoteException
import android.util.Log
@@ -32,6 +30,8 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
+import androidx.lifecycle.lifecycleScope
+import com.android.app.tracing.coroutines.launch
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.theme.PlatformTheme
import com.android.internal.logging.UiEventLogger
@@ -43,8 +43,8 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
-import com.android.systemui.res.R
import javax.inject.Inject
+import kotlinx.coroutines.launch
/** An Activity for editing the widgets that appear in hub mode. */
class EditWidgetsActivity
@@ -57,11 +57,8 @@
@CommunalLog logBuffer: LogBuffer,
) : ComponentActivity() {
companion object {
- private const val EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag"
- private const val EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width"
- private const val EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height"
-
private const val TAG = "EditWidgetsActivity"
+ private const val EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag"
const val EXTRA_PRESELECTED_KEY = "preselected_key"
}
@@ -136,39 +133,13 @@
}
private fun onOpenWidgetPicker() {
- val intent = Intent(Intent.ACTION_MAIN).also { it.addCategory(Intent.CATEGORY_HOME) }
- packageManager
- .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
- ?.activityInfo
- ?.packageName
- ?.let { packageName ->
- try {
- addWidgetActivityLauncher.launch(
- Intent(Intent.ACTION_PICK).apply {
- setPackage(packageName)
- putExtra(
- EXTRA_DESIRED_WIDGET_WIDTH,
- resources.getDimensionPixelSize(
- R.dimen.communal_widget_picker_desired_width
- )
- )
- putExtra(
- EXTRA_DESIRED_WIDGET_HEIGHT,
- resources.getDimensionPixelSize(
- R.dimen.communal_widget_picker_desired_height
- )
- )
- putExtra(
- AppWidgetManager.EXTRA_CATEGORY_FILTER,
- communalViewModel.getCommunalWidgetCategories
- )
- }
- )
- } catch (e: Exception) {
- Log.e(TAG, "Failed to launch widget picker activity", e)
- }
- }
- ?: run { Log.e(TAG, "Couldn't resolve launcher package name") }
+ lifecycleScope.launch {
+ communalViewModel.onOpenWidgetPicker(
+ resources,
+ packageManager,
+ addWidgetActivityLauncher
+ )
+ }
}
private fun onEditDone() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 4c1e77b..778d8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -16,9 +16,14 @@
package com.android.systemui.communal.widgets
+import android.app.ActivityOptions
import android.app.PendingIntent
+import android.content.Intent
+import android.util.Pair
import android.view.View
import android.widget.RemoteViews
+import androidx.core.util.component1
+import androidx.core.util.component2
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.common.ui.view.getNearestParent
import com.android.systemui.plugins.ActivityStarter
@@ -33,21 +38,33 @@
view: View,
pendingIntent: PendingIntent,
response: RemoteViews.RemoteResponse
- ): Boolean =
- when {
- pendingIntent.isActivity -> startActivity(view, pendingIntent)
- else ->
- RemoteViews.startPendingIntent(view, pendingIntent, response.getLaunchOptions(view))
+ ): Boolean {
+ val launchOptions = response.getLaunchOptions(view)
+ return when {
+ pendingIntent.isActivity ->
+ // Forward the fill-in intent and activity options retrieved from the response
+ // to populate the pending intent, so that list items can launch respective
+ // activities.
+ startActivity(view, pendingIntent, launchOptions)
+ else -> RemoteViews.startPendingIntent(view, pendingIntent, launchOptions)
}
+ }
- private fun startActivity(view: View, pendingIntent: PendingIntent): Boolean {
+ private fun startActivity(
+ view: View,
+ pendingIntent: PendingIntent,
+ launchOptions: Pair<Intent, ActivityOptions>,
+ ): Boolean {
val hostView = view.getNearestParent<CommunalAppWidgetHostView>()
val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
+ val (fillInIntent, activityOptions) = launchOptions
activityStarter.startPendingIntentMaybeDismissingKeyguard(
pendingIntent,
/* intentSentUiThreadCallback = */ null,
- animationController
+ animationController,
+ fillInIntent,
+ activityOptions.toBundle(),
)
return true
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
index 7e5b267..c110d06 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
@@ -28,7 +28,6 @@
import android.service.controls.Control
import android.service.controls.ControlsProviderService
import android.util.Log
-import java.lang.ClassCastException
/**
* Proxy to launch in user 0
@@ -61,22 +60,28 @@
}
val targetComponent = try {
- intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
- } catch (e: ClassCastException) {
+ intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName::class.java)
+ } catch (e: Exception) {
Log.e(TAG, "Malformed intent extra ComponentName", e)
return
+ } ?: run {
+ Log.e(TAG, "Null target component")
+ return
}
val control = try {
- intent.getParcelableExtra<Control>(ControlsProviderService.EXTRA_CONTROL)
- } catch (e: ClassCastException) {
+ intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL, Control::class.java)
+ } catch (e: Exception) {
Log.e(TAG, "Malformed intent extra Control", e)
return
+ } ?: run {
+ Log.e(TAG, "Null control")
+ return
}
- val packageName = targetComponent?.packageName
+ val packageName = targetComponent.packageName
- if (packageName == null || !isPackageInForeground(context, packageName)) {
+ if (!isPackageInForeground(context, packageName)) {
return
}
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 8059993..c4e0ef7 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
@@ -29,6 +29,8 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@OptIn(ExperimentalCoroutinesApi::class)
@@ -72,4 +74,14 @@
*/
val isSensorUnderDisplay =
fingerprintPropertyRepository.sensorType.map(FingerprintSensorType::isUdfps)
+
+ /** Whether fingerprint authentication is currently allowed while on the bouncer. */
+ val isFingerprintCurrentlyAllowedOnBouncer =
+ isSensorUnderDisplay.flatMapLatest { sensorBelowDisplay ->
+ if (sensorBelowDisplay) {
+ flowOf(false)
+ } else {
+ isFingerprintAuthCurrentlyAllowed
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt
index 289dbd9..195aa5f 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt
@@ -74,8 +74,13 @@
keyguardInteractor.isKeyguardShowing,
primaryBouncerInteractor.isShowing,
alternateBouncerInteractor.isVisible,
- ) { occluded, showing, primaryBouncerShowing, alternateBouncerVisible ->
- occluded && showing && !primaryBouncerShowing && !alternateBouncerVisible
+ keyguardInteractor.isDozing,
+ ) { occluded, showing, primaryBouncerShowing, alternateBouncerVisible, dozing ->
+ occluded &&
+ showing &&
+ !primaryBouncerShowing &&
+ !alternateBouncerVisible &&
+ !dozing
}
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 298da13..1bcee74 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -23,13 +23,11 @@
import com.android.server.notification.Flags.politeNotifications
import com.android.server.notification.Flags.vibrateWhileUnlocked
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
-import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
-import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
import com.android.systemui.Flags.communalHub
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
@@ -58,11 +56,11 @@
SceneContainerFlag.getMainStaticFlag() dependsOn MIGRATE_KEYGUARD_STATUS_BAR_VIEW
// ComposeLockscreen dependencies
- ComposeLockscreen.token dependsOn keyguardBottomAreaRefactor
- ComposeLockscreen.token dependsOn migrateClocksToBlueprint
+ ComposeLockscreen.token dependsOn KeyguardBottomAreaRefactor.token
+ ComposeLockscreen.token dependsOn MigrateClocksToBlueprint.token
// CommunalHub dependencies
- communalHub dependsOn migrateClocksToBlueprint
+ communalHub dependsOn MigrateClocksToBlueprint.token
}
private inline val politeNotifications
@@ -71,10 +69,6 @@
get() = FlagToken(FLAG_CROSS_APP_POLITE_NOTIFICATIONS, crossAppPoliteNotifications())
private inline val vibrateWhileUnlockedToken: FlagToken
get() = FlagToken(FLAG_VIBRATE_WHILE_UNLOCKED, vibrateWhileUnlocked())
- private inline val keyguardBottomAreaRefactor
- get() = FlagToken(FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor())
- private inline val migrateClocksToBlueprint
- get() = FlagToken(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, migrateClocksToBlueprint())
private inline val communalHub
get() = FlagToken(FLAG_COMMUNAL_HUB, communalHub())
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/CommandLineKeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/CommandLineKeyboardRepository.kt
new file mode 100644
index 0000000..f49cfdd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/CommandLineKeyboardRepository.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.keyboard.data.repository
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.model.Keyboard
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+/**
+ * Helper class for development to mock various keyboard states with command line. Alternative for
+ * [KeyboardRepositoryImpl] which relies on real data from framework. [KeyboardRepositoryImpl] is
+ * the default implementation so to use this class you need to substitute it in [KeyboardModule].
+ *
+ * For usage information: see [KeyboardCommand.help] or run `adb shell cmd statusbar keyboard`.
+ */
+@SysUISingleton
+class CommandLineKeyboardRepository @Inject constructor(commandRegistry: CommandRegistry) :
+ KeyboardRepository {
+
+ private val _isAnyKeyboardConnected = MutableStateFlow(false)
+ override val isAnyKeyboardConnected: Flow<Boolean> = _isAnyKeyboardConnected
+
+ private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
+ // filtering to make sure backlight doesn't have default initial value
+ override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
+
+ private val _newlyConnectedKeyboard: MutableStateFlow<Keyboard?> = MutableStateFlow(null)
+ override val newlyConnectedKeyboard: Flow<Keyboard> = _newlyConnectedKeyboard.filterNotNull()
+
+ init {
+ Log.i(TAG, "initializing shell command $COMMAND")
+ commandRegistry.registerCommand(COMMAND) { KeyboardCommand() }
+ }
+
+ inner class KeyboardCommand : Command {
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ Log.i(TAG, "$COMMAND command was called with args: $args")
+ if (args.isEmpty()) {
+ help(pw)
+ return
+ }
+ when (args[0]) {
+ "keyboard-connected" -> _isAnyKeyboardConnected.value = args[1].toBoolean()
+ "backlight" -> {
+ @Suppress("Since15")
+ val level = Math.clamp(args[1].toInt().toLong(), 0, MAX_BACKLIGHT_LEVEL)
+ _backlightState.value = BacklightModel(level, MAX_BACKLIGHT_LEVEL)
+ }
+ "new-keyboard" -> {
+ _newlyConnectedKeyboard.value =
+ Keyboard(vendorId = args[1].toInt(), productId = args[2].toInt())
+ }
+ else -> help(pw)
+ }
+ }
+
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar $COMMAND <command>")
+ pw.println(
+ "Note: this command only mocks setting these values on the framework level" +
+ " but in reality doesn't change anything and is only used for testing UI"
+ )
+ pw.println("Available commands:")
+ pw.println(" keyboard-connected [true|false]")
+ pw.println(" Notify any physical keyboard connected/disconnected.")
+ pw.println(" backlight <level>")
+ pw.println(" Notify new keyboard backlight level: min 0, max $MAX_BACKLIGHT_LEVEL.")
+ pw.println(" new-keyboard <vendor-id> <product-id>")
+ pw.println(" Notify new physical keyboard with specified parameters got connected.")
+ }
+ }
+
+ companion object {
+ private const val TAG = "CommandLineKeyboardRepository"
+ private const val COMMAND = "keyboard"
+ private const val MAX_BACKLIGHT_LEVEL = 5
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index 2fac40a..91d5280 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -46,6 +46,10 @@
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.shareIn
+/**
+ * Provides information about physical keyboard states. [CommandLineKeyboardRepository] can be
+ * useful command line-driven implementation during development.
+ */
interface KeyboardRepository {
/** Emits true if any physical keyboard is connected to the device, false otherwise. */
val isAnyKeyboardConnected: Flow<Boolean>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardBottomAreaRefactor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardBottomAreaRefactor.kt
new file mode 100644
index 0000000..779b27b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardBottomAreaRefactor.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.systemui.keyguard
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the keyguard bottom area refactor flag. */
+@Suppress("NOTHING_TO_INLINE")
+object KeyguardBottomAreaRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.keyguardBottomAreaRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 5565ee2..d9d7470 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -36,7 +36,6 @@
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardStatusViewComponent
import com.android.systemui.CoreStartable
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
@@ -166,7 +165,7 @@
fun bindIndicationArea() {
indicationAreaHandle?.dispose()
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled) {
keyguardRootView.findViewById<View?>(R.id.keyguard_indication_area)?.let {
keyguardRootView.removeView(it)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b34750..a293afc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,7 +40,6 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.refactorGetCurrentUser;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -155,7 +154,7 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -3404,7 +3403,8 @@
}
// Ensure that keyguard becomes visible if the going away animation is canceled
- if (showKeyguard && !KeyguardWmStateRefactor.isEnabled() && migrateClocksToBlueprint()) {
+ if (showKeyguard && !KeyguardWmStateRefactor.isEnabled()
+ && MigrateClocksToBlueprint.isEnabled()) {
mKeyguardInteractor.showKeyguard();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/MigrateClocksToBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/MigrateClocksToBlueprint.kt
new file mode 100644
index 0000000..5a2943b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/MigrateClocksToBlueprint.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.systemui.keyguard
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the migrate clocks to blueprint flag. */
+@Suppress("NOTHING_TO_INLINE")
+object MigrateClocksToBlueprint {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.migrateClocksToBlueprint()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 7ad5aac..3f4d3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -18,7 +18,6 @@
import android.os.UserHandle
import android.provider.Settings
-import androidx.annotation.VisibleForTesting
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch.ClockSize
import com.android.keyguard.KeyguardClockSwitch.LARGE
@@ -52,14 +51,14 @@
val clockSize: StateFlow<Int>
/** clock size selected in picker, DYNAMIC or SMALL */
- val selectedClockSize: Flow<SettingsClockSize>
+ val selectedClockSize: StateFlow<SettingsClockSize>
/** clock id, selected from clock carousel in wallpaper picker */
val currentClockId: Flow<ClockId>
val currentClock: StateFlow<ClockController?>
- val previewClockPair: StateFlow<Pair<ClockController, ClockController>>
+ val previewClock: Flow<ClockController>
val clockEventController: ClockEventController
fun setClockSize(@ClockSize size: Int)
@@ -84,14 +83,19 @@
_clockSize.value = size
}
- override val selectedClockSize: Flow<SettingsClockSize> =
+ override val selectedClockSize: StateFlow<SettingsClockSize> =
secureSettings
.observerFlow(
names = arrayOf(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
userId = UserHandle.USER_SYSTEM,
)
.onStart { emit(Unit) } // Forces an initial update.
- .map { getClockSize() }
+ .map { withContext(backgroundDispatcher) { getClockSize() } }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = getClockSize()
+ )
override val currentClockId: Flow<ClockId> =
callbackFlow {
@@ -113,37 +117,35 @@
override val currentClock: StateFlow<ClockController?> =
currentClockId
- .map { clockRegistry.createCurrentClock() }
+ .map {
+ clockEventController.clock = clockRegistry.createCurrentClock()
+ clockEventController.clock
+ }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = clockRegistry.createCurrentClock()
)
- override val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
- currentClockId
- .map { Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock()) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue =
- Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock())
- )
+ override val previewClock: Flow<ClockController> =
+ currentClockId.map {
+ // We should create a new instance for each collect call
+ // cause in preview, the same clock will be attached to different view
+ // at the same time
+ clockRegistry.createCurrentClock()
+ }
- @VisibleForTesting
- suspend fun getClockSize(): SettingsClockSize {
- return withContext(backgroundDispatcher) {
- if (
- secureSettings.getIntForUser(
- Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
- 1,
- UserHandle.USER_CURRENT
- ) == 1
- ) {
- SettingsClockSize.DYNAMIC
- } else {
- SettingsClockSize.SMALL
- }
+ private fun getClockSize(): SettingsClockSize {
+ return if (
+ secureSettings.getIntForUser(
+ Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
+ 1,
+ UserHandle.USER_CURRENT
+ ) == 1
+ ) {
+ SettingsClockSize.DYNAMIC
+ } else {
+ SettingsClockSize.SMALL
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 9c68c45..a36bf8b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -119,24 +119,7 @@
init {
// Seed with transitions signaling a boot into lockscreen state. If updating this, please
// also update FakeKeyguardTransitionRepository.
- emitTransition(
- TransitionStep(
- KeyguardState.OFF,
- KeyguardState.LOCKSCREEN,
- 0f,
- TransitionState.STARTED,
- KeyguardTransitionRepositoryImpl::class.simpleName!!,
- )
- )
- emitTransition(
- TransitionStep(
- KeyguardState.OFF,
- KeyguardState.LOCKSCREEN,
- 1f,
- TransitionState.FINISHED,
- KeyguardTransitionRepositoryImpl::class.simpleName!!,
- )
- )
+ initialTransitionSteps.forEach(::emitTransition)
}
override fun startTransition(info: TransitionInfo): UUID? {
@@ -256,5 +239,31 @@
companion object {
private const val TAG = "KeyguardTransitionRepository"
+
+ /**
+ * Transition steps to seed the repository with, so that all of the transition interactor
+ * flows emit reasonable initial values.
+ */
+ val initialTransitionSteps: List<TransitionStep> =
+ listOf(
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.OFF,
+ 1f,
+ TransitionState.FINISHED,
+ ),
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.LOCKSCREEN,
+ 0f,
+ TransitionState.STARTED,
+ ),
+ TransitionStep(
+ KeyguardState.OFF,
+ KeyguardState.LOCKSCREEN,
+ 1f,
+ TransitionState.FINISHED,
+ ),
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 9040e03..d09ee54 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -252,5 +252,6 @@
val TO_LOCKSCREEN_DURATION = 500.milliseconds
val TO_GONE_DURATION = DEFAULT_DURATION
val TO_OCCLUDED_DURATION = DEFAULT_DURATION
+ val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 7f752b4..1f24fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -231,6 +231,7 @@
private val DEFAULT_DURATION = 500.milliseconds
val TO_GLANCEABLE_HUB_DURATION = 1.seconds
val TO_LOCKSCREEN_DURATION = 1167.milliseconds
+ val TO_AOD_DURATION = 300.milliseconds
val TO_GONE_DURATION = DEFAULT_DURATION
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 12b27eb..2649d43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -289,7 +289,10 @@
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- startTransitionTo(KeyguardState.GONE)
+ startTransitionTo(
+ KeyguardState.GONE,
+ modeOnCanceled = TransitionModeOnCanceled.RESET,
+ )
}
}
}
@@ -303,20 +306,6 @@
startTransitionTo(KeyguardState.GONE)
}
}
-
- return
- }
-
- scope.launch {
- keyguardInteractor.isKeyguardGoingAway
- .sample(startedKeyguardTransitionStep, ::Pair)
- .collect { pair ->
- KeyguardWmStateRefactor.assertInLegacyMode()
- val (isKeyguardGoingAway, lastStartedStep) = pair
- if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- startTransitionTo(KeyguardState.GONE)
- }
- }
}
}
@@ -413,7 +402,7 @@
val TO_OCCLUDED_DURATION = 450.milliseconds
val TO_AOD_DURATION = 500.milliseconds
val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
- val TO_GONE_DURATION = DEFAULT_DURATION
+ val TO_GONE_DURATION = 633.milliseconds
val TO_GLANCEABLE_HUB_DURATION = 1.seconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt
index b9ec58c..53f2416 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt
@@ -39,7 +39,7 @@
/** The position of the keyguard clock. */
private val _clockPosition = MutableStateFlow(Position(0, 0))
/** See [ClockSection] */
- @Deprecated("with migrateClocksToBlueprint()")
+ @Deprecated("with MigrateClocksToBlueprint.isEnabled")
val clockPosition: Flow<Position> = _clockPosition.asStateFlow()
fun setClockPosition(x: Int, y: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 2cf9156..d492135 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -38,14 +38,13 @@
private val keyguardClockRepository: KeyguardClockRepository,
) {
- val selectedClockSize: Flow<SettingsClockSize> = keyguardClockRepository.selectedClockSize
+ val selectedClockSize: StateFlow<SettingsClockSize> = keyguardClockRepository.selectedClockSize
val currentClockId: Flow<ClockId> = keyguardClockRepository.currentClockId
val currentClock: StateFlow<ClockController?> = keyguardClockRepository.currentClock
- val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
- keyguardClockRepository.previewClockPair
+ val previewClock: Flow<ClockController> = keyguardClockRepository.previewClock
var clock: ClockController? by keyguardClockRepository.clockEventController::clock
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index e6655ee..0cd7d18 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -91,11 +91,46 @@
}
}
+ val transitions = repository.transitions
+
+ /**
+ * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
+ * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
+ * and that the previous step was *to* the state the STARTED step is *from*.
+ *
+ * This flow can be used to access the previous step to determine whether it was CANCELED or
+ * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
+ * from when we were canceled.
+ */
+ val startedStepWithPrecedingStep =
+ transitions
+ .pairwise()
+ .filter { it.newValue.transitionState == TransitionState.STARTED }
+ .shareIn(scope, SharingStarted.Eagerly)
+
init {
+ // Collect non-canceled steps and emit transition values.
scope.launch(mainDispatcher) {
- repository.transitions.collect { step ->
- getTransitionValueFlow(step.from).emit(1f - step.value)
- getTransitionValueFlow(step.to).emit(step.value)
+ repository.transitions
+ .filter { it.transitionState != TransitionState.CANCELED }
+ .collect { step ->
+ getTransitionValueFlow(step.from).emit(1f - step.value)
+ getTransitionValueFlow(step.to).emit(step.value)
+ }
+ }
+
+ // If a transition from state A -> B is canceled in favor of a transition from B -> C, we
+ // need to ensure we emit transitionValue(A) = 0f, since no further steps will be emitted
+ // where the from or to states are A. This would leave transitionValue(A) stuck at an
+ // arbitrary non-zero value.
+ scope.launch(mainDispatcher) {
+ startedStepWithPrecedingStep.collect { (prevStep, startedStep) ->
+ if (
+ prevStep.transitionState == TransitionState.CANCELED &&
+ startedStep.to != prevStep.from
+ ) {
+ getTransitionValueFlow(prevStep.from).emit(0f)
+ }
}
}
}
@@ -202,8 +237,6 @@
val dozingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DOZING, LOCKSCREEN)
- val transitions = repository.transitions
-
/** Receive all [TransitionStep] matching a filter of [from]->[to] */
fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> {
return repository.transition(from, to)
@@ -250,21 +283,6 @@
.stateIn(scope, SharingStarted.Eagerly, DOZING)
/**
- * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
- * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
- * and that the previous step was *to* the state the STARTED step is *from*.
- *
- * This flow can be used to access the previous step to determine whether it was CANCELED or
- * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
- * from when we were canceled.
- */
- val startedStepWithPrecedingStep =
- transitions
- .pairwise()
- .filter { it.newValue.transitionState == TransitionState.STARTED }
- .stateIn(scope, SharingStarted.Eagerly, null)
-
- /**
* The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
*
* WARNING: This will NOT emit a value if a transition is CANCELED, and will also not emit a
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index 4812e03..7e3ddf9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -26,9 +26,9 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
@@ -105,7 +105,7 @@
var transition =
if (
- !keyguardBottomAreaRefactor() &&
+ !KeyguardBottomAreaRefactor.isEnabled &&
prevBluePrint != null &&
prevBluePrint != blueprint
) {
@@ -213,9 +213,10 @@
cs: ConstraintSet,
viewModel: KeyguardClockViewModel
) {
- if (!DEBUG || viewModel.clock == null) return
+ val currentClock = viewModel.currentClock.value
+ if (!DEBUG || currentClock == null) return
val smallClockViewId = R.id.lockscreen_clock_view
- val largeClockViewId = viewModel.clock!!.largeClock.layout.views[0].id
+ val largeClockViewId = currentClock.largeClock.layout.views[0].id
Log.i(
TAG,
"applyCsToSmallClock: vis=${cs.getVisibility(smallClockViewId)} " +
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index 01596ed..6255f0d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -19,6 +19,7 @@
import android.transition.TransitionManager
import android.transition.TransitionSet
import android.view.View.INVISIBLE
+import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.helper.widget.Layer
import androidx.constraintlayout.widget.ConstraintLayout
@@ -27,7 +28,7 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.keyguard.KeyguardClockSwitch.SMALL
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
@@ -40,7 +41,8 @@
object KeyguardClockViewBinder {
private val TAG = KeyguardClockViewBinder::class.simpleName!!
-
+ // When changing to new clock, we need to remove old clock views from burnInLayer
+ private var lastClock: ClockController? = null
@JvmStatic
fun bind(
clockSection: ClockSection,
@@ -55,28 +57,27 @@
}
}
keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
viewModel.currentClock.collect { currentClock ->
- cleanupClockViews(viewModel.clock, keyguardRootView, viewModel.burnInLayer)
- viewModel.clock = currentClock
+ cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer)
addClockViews(currentClock, keyguardRootView)
updateBurnInLayer(keyguardRootView, viewModel)
applyConstraints(clockSection, keyguardRootView, true)
}
}
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
viewModel.clockSize.collect {
updateBurnInLayer(keyguardRootView, viewModel)
blueprintInteractor.refreshBlueprint(Type.ClockSize)
}
}
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
viewModel.clockShouldBeCentered.collect { clockShouldBeCentered ->
- viewModel.clock?.let {
+ viewModel.currentClock.value?.let {
// Weather clock also has hasCustomPositionUpdatedAnimation as true
// TODO(b/323020908): remove ID check
if (
@@ -91,9 +92,9 @@
}
}
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
viewModel.isAodIconsVisible.collect { isAodIconsVisible ->
- viewModel.clock?.let {
+ viewModel.currentClock.value?.let {
// Weather clock also has hasCustomPositionUpdatedAnimation as true
if (
viewModel.useLargeClock && it.config.id == "DIGITAL_CLOCK_WEATHER"
@@ -132,11 +133,14 @@
}
private fun cleanupClockViews(
- clockController: ClockController?,
+ currentClock: ClockController?,
rootView: ConstraintLayout,
burnInLayer: Layer?
) {
- clockController?.let { clock ->
+ if (lastClock == currentClock) {
+ return
+ }
+ lastClock?.let { clock ->
clock.smallClock.layout.views.forEach {
burnInLayer?.removeView(it)
rootView.removeView(it)
@@ -150,6 +154,7 @@
}
clock.largeClock.layout.views.forEach { rootView.removeView(it) }
}
+ lastClock = currentClock
}
@VisibleForTesting
@@ -157,11 +162,19 @@
clockController: ClockController?,
rootView: ConstraintLayout,
) {
+ // We'll collect the same clock when exiting wallpaper picker without changing clock
+ // so we need to remove clock views from parent before addView again
clockController?.let { clock ->
clock.smallClock.layout.views.forEach {
+ if (it.parent != null) {
+ (it.parent as ViewGroup).removeView(it)
+ }
rootView.addView(it).apply { it.visibility = INVISIBLE }
}
clock.largeClock.layout.views.forEach {
+ if (it.parent != null) {
+ (it.parent as ViewGroup).removeView(it)
+ }
rootView.addView(it).apply { it.visibility = INVISIBLE }
}
}
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 841f52d..267d68e 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
@@ -22,8 +22,8 @@
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
@@ -69,7 +69,10 @@
launch {
// Do not independently apply alpha, as [KeyguardRootViewModel] should work
// for this and all its children
- if (!(migrateClocksToBlueprint() || keyguardBottomAreaRefactor())) {
+ if (
+ !(MigrateClocksToBlueprint.isEnabled ||
+ KeyguardBottomAreaRefactor.isEnabled)
+ ) {
viewModel.alpha.collect { alpha -> view.alpha = alpha }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 46c354a..d9f12c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -32,7 +32,6 @@
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.keyguard.ClockEventController
import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.shared.model.SettingsClockSize
import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer
@@ -44,12 +43,10 @@
import com.android.systemui.res.R
import com.android.systemui.util.Utils
import kotlin.reflect.KSuspendFunction1
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
/** Binder for the small clock view, large clock view. */
object KeyguardPreviewClockViewBinder {
-
@JvmStatic
fun bind(
largeClockHostView: View,
@@ -72,52 +69,38 @@
@JvmStatic
fun bind(
context: Context,
- displayId: Int,
rootView: ConstraintLayout,
viewModel: KeyguardPreviewClockViewModel,
- clockEventController: ClockEventController,
updateClockAppearance: KSuspendFunction1<ClockController, Unit>,
) {
- // TODO(b/327668072): When this function is called multiple times, the clock view can be
- // gone due to a race condition on removeView and addView.
rootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
- combine(viewModel.selectedClockSize, viewModel.previewClockPair) { _, clock ->
- clock
+ var lastClock: ClockController? = null
+ viewModel.previewClock.collect { currentClock ->
+ lastClock?.let { clock ->
+ (clock.largeClock.layout.views + clock.smallClock.layout.views)
+ .forEach { rootView.removeView(it) }
}
- .collect { previewClockPair ->
- viewModel.lastClockPair?.let { clockPair ->
- (clockPair.first.largeClock.layout.views +
- clockPair.first.smallClock.layout.views)
- .forEach { rootView.removeView(it) }
- (clockPair.second.largeClock.layout.views +
- clockPair.second.smallClock.layout.views)
- .forEach { rootView.removeView(it) }
- }
- viewModel.lastClockPair = previewClockPair
- val clockPreview =
- if (displayId == 0) previewClockPair.first
- else previewClockPair.second
- clockEventController.clock = clockPreview
- updateClockAppearance(clockPreview)
+ lastClock = currentClock
+ updateClockAppearance(currentClock)
- if (viewModel.shouldHighlightSelectedAffordance) {
- (clockPreview.largeClock.layout.views +
- clockPreview.smallClock.layout.views)
- .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA }
- }
- clockPreview.largeClock.layout.views.forEach {
- (it.parent as? ViewGroup)?.removeView(it)
- rootView.addView(it)
- }
-
- clockPreview.smallClock.layout.views.forEach {
- (it.parent as? ViewGroup)?.removeView(it)
- rootView.addView(it)
- }
- applyPreviewConstraints(context, rootView, viewModel)
+ if (viewModel.shouldHighlightSelectedAffordance) {
+ (currentClock.largeClock.layout.views +
+ currentClock.smallClock.layout.views)
+ .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA }
}
+ currentClock.largeClock.layout.views.forEach {
+ (it.parent as? ViewGroup)?.removeView(it)
+ rootView.addView(it)
+ }
+
+ currentClock.smallClock.layout.views.forEach {
+ (it.parent as? ViewGroup)?.removeView(it)
+ rootView.addView(it)
+ }
+ applyPreviewConstraints(context, rootView, currentClock, viewModel)
+ }
}
}
}
@@ -170,15 +153,13 @@
private fun applyPreviewConstraints(
context: Context,
rootView: ConstraintLayout,
+ previewClock: ClockController,
viewModel: KeyguardPreviewClockViewModel
) {
val cs = ConstraintSet().apply { clone(rootView) }
- val clockPair = viewModel.previewClockPair.value
applyClockDefaultConstraints(context, cs)
- clockPair.first.largeClock.layout.applyPreviewConstraints(cs)
- clockPair.first.smallClock.layout.applyPreviewConstraints(cs)
- clockPair.second.largeClock.layout.applyPreviewConstraints(cs)
- clockPair.second.smallClock.layout.applyPreviewConstraints(cs)
+ previewClock.largeClock.layout.applyPreviewConstraints(cs)
+ previewClock.smallClock.layout.applyPreviewConstraints(cs)
// When selectedClockSize is the initial value, make both clocks invisible to avoid
// flickering
@@ -194,12 +175,9 @@
SettingsClockSize.SMALL -> VISIBLE
null -> INVISIBLE
}
-
cs.apply {
- setVisibility(clockPair.first.largeClock.layout.views, largeClockVisibility)
- setVisibility(clockPair.first.smallClock.layout.views, smallClockVisibility)
- setVisibility(clockPair.second.largeClock.layout.views, largeClockVisibility)
- setVisibility(clockPair.second.smallClock.layout.views, smallClockVisibility)
+ setVisibility(previewClock.largeClock.layout.views, largeClockVisibility)
+ setVisibility(previewClock.smallClock.layout.views, smallClockVisibility)
}
cs.applyTo(rootView)
}
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 d0246a8..0ed42ef 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
@@ -36,8 +36,6 @@
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.keyguard.KeyguardClockSwitch.MISSING_CLOCK_ID
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.Flags.newAodTransition
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
@@ -45,6 +43,8 @@
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
@@ -109,7 +109,7 @@
val endButton = R.id.end_button
val lockIcon = R.id.lock_icon_view
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
view.setOnTouchListener { _, event ->
if (falsingManager?.isFalseTap(FalsingManager.LOW_PENALTY) == false) {
viewModel.setRootViewLastTapPosition(Point(event.x.toInt(), event.y.toInt()))
@@ -143,11 +143,13 @@
}
}
- if (keyguardBottomAreaRefactor() || DeviceEntryUdfpsRefactor.isEnabled) {
+ if (
+ KeyguardBottomAreaRefactor.isEnabled || DeviceEntryUdfpsRefactor.isEnabled
+ ) {
launch {
viewModel.alpha(viewState).collect { alpha ->
view.alpha = alpha
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
childViews[statusViewId]?.alpha = alpha
childViews[burnInLayerId]?.alpha = alpha
}
@@ -155,7 +157,7 @@
}
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
launch {
viewModel.burnInLayerVisibility.collect { visibility ->
childViews[burnInLayerId]?.visibility = visibility
@@ -342,13 +344,13 @@
}
}
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
burnInParams.update { current ->
current.copy(clockControllerProvider = clockControllerProvider)
}
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
burnInParams.update { current ->
current.copy(translationY = { childViews[burnInLayerId]?.translationY })
}
@@ -439,7 +441,7 @@
burnInParams.update { current ->
current.copy(
minViewY =
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
// To ensure burn-in doesn't enroach the top inset, get the min top Y
childViews.entries.fold(Int.MAX_VALUE) { currentMin, (viewId, view) ->
min(
@@ -472,7 +474,7 @@
configuration: ConfigurationState,
screenOffAnimationController: ScreenOffAnimationController,
) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
throw IllegalStateException("should only be called in legacy code paths")
}
if (NotificationIconContainerRefactor.isUnexpectedlyInLegacyMode()) return
@@ -503,7 +505,7 @@
}
when {
!isVisible.isAnimating -> {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
translationY = 0f
}
visibility =
@@ -553,7 +555,7 @@
animatorListener: Animator.AnimatorListener,
) {
if (animate) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
translationY = -iconAppearTranslation.toFloat()
}
alpha = 0f
@@ -561,19 +563,19 @@
.alpha(1f)
.setInterpolator(Interpolators.LINEAR)
.setDuration(AOD_ICONS_APPEAR_DURATION)
- .apply { if (migrateClocksToBlueprint()) animateInIconTranslation() }
+ .apply { if (MigrateClocksToBlueprint.isEnabled) animateInIconTranslation() }
.setListener(animatorListener)
.start()
} else {
alpha = 1.0f
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
translationY = 0f
}
}
}
private fun View.animateInIconTranslation() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
animate().animateInIconTranslation().setDuration(AOD_ICONS_APPEAR_DURATION).start()
}
}
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 b77f0c5..9aebf66 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
@@ -21,7 +21,7 @@
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
@@ -41,9 +41,9 @@
blueprintInteractor: KeyguardBlueprintInteractor,
) {
keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
clockViewModel.hasCustomWeatherDataDisplay.collect { hasCustomWeatherDataDisplay
->
updateDateWeatherToBurnInLayer(
@@ -62,7 +62,7 @@
}
launch {
- if (!migrateClocksToBlueprint()) return@launch
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
smartspaceViewModel.bcSmartspaceVisibility.collect {
updateBCSmartspaceInBurnInLayer(keyguardRootView, clockViewModel)
blueprintInteractor.refreshBlueprint(
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 7c76e6a..14ab17f 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
@@ -50,8 +50,6 @@
import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -61,6 +59,8 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
@@ -90,6 +90,7 @@
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
+import com.android.systemui.util.kotlin.DisposableHandles
import com.android.systemui.util.settings.SecureSettings
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
@@ -173,7 +174,7 @@
private lateinit var smallClockHostView: FrameLayout
private var smartSpaceView: View? = null
- private val disposables = mutableSetOf<DisposableHandle>()
+ private val disposables = DisposableHandles()
private var isDestroyed = false
private val shortcutsBindings = mutableSetOf<KeyguardQuickAffordanceViewBinder.Binding>()
@@ -183,9 +184,9 @@
init {
coroutineScope = CoroutineScope(applicationScope.coroutineContext + Job())
- disposables.add(DisposableHandle { coroutineScope.cancel() })
+ disposables += DisposableHandle { coroutineScope.cancel() }
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
quickAffordancesCombinedViewModel.enablePreviewMode(
initiallySelectedSlotId =
bundle.getString(
@@ -203,7 +204,7 @@
shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
)
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
clockViewModel.shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance
}
runBlocking(mainDispatcher) {
@@ -214,7 +215,7 @@
if (hostToken == null) null else InputTransferToken(hostToken),
"KeyguardPreviewRenderer"
)
- disposables.add(DisposableHandle { host.release() })
+ disposables += DisposableHandle { host.release() }
}
}
@@ -230,7 +231,7 @@
setupKeyguardRootView(previewContext, rootView)
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled) {
setUpBottomArea(rootView)
}
@@ -274,7 +275,7 @@
}
fun onSlotSelected(slotId: String) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
quickAffordancesCombinedViewModel.onPreviewSlotSelected(slotId = slotId)
} else {
bottomAreaViewModel.onPreviewSlotSelected(slotId = slotId)
@@ -284,8 +285,8 @@
fun destroy() {
isDestroyed = true
lockscreenSmartspaceController.disconnect()
- disposables.forEach { it.dispose() }
- if (keyguardBottomAreaRefactor()) {
+ disposables.dispose()
+ if (KeyguardBottomAreaRefactor.isEnabled) {
shortcutsBindings.forEach { it.destroy() }
}
}
@@ -371,8 +372,8 @@
@OptIn(ExperimentalCoroutinesApi::class)
private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) {
val keyguardRootView = KeyguardRootView(previewContext, null)
- if (!keyguardBottomAreaRefactor()) {
- disposables.add(
+ if (!KeyguardBottomAreaRefactor.isEnabled) {
+ disposables +=
KeyguardRootViewBinder.bind(
keyguardRootView,
keyguardRootViewModel,
@@ -387,7 +388,6 @@
null, // device entry haptics not required for preview mode
null, // falsing manager not required for preview mode
)
- )
}
rootView.addView(
keyguardRootView,
@@ -397,21 +397,22 @@
),
)
- setUpUdfps(previewContext, if (migrateClocksToBlueprint()) keyguardRootView else rootView)
+ setUpUdfps(
+ previewContext,
+ if (MigrateClocksToBlueprint.isEnabled) keyguardRootView else rootView
+ )
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
setupShortcuts(keyguardRootView)
}
if (!shouldHideClock) {
setUpClock(previewContext, rootView)
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
KeyguardPreviewClockViewBinder.bind(
context,
- displayId,
keyguardRootView,
clockViewModel,
- clockController,
::updateClockAppearance
)
} else {
@@ -482,7 +483,7 @@
) as View
// Place the UDFPS view in the proper sensor location
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
finger.id = R.id.lock_icon_view
parentView.addView(finger)
val cs = ConstraintSet()
@@ -509,7 +510,7 @@
private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
val resources = parentView.resources
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
largeClockHostView = FrameLayout(previewContext)
largeClockHostView.layoutParams =
FrameLayout.LayoutParams(
@@ -547,7 +548,7 @@
}
// TODO (b/283465254): Move the listeners to KeyguardClockRepository
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
val clockChangeListener =
object : ClockRegistry.ClockChangeListener {
override fun onCurrentClockChanged() {
@@ -555,14 +556,12 @@
}
}
clockRegistry.registerClockChangeListener(clockChangeListener)
- disposables.add(
- DisposableHandle {
- clockRegistry.unregisterClockChangeListener(clockChangeListener)
- }
- )
+ disposables += DisposableHandle {
+ clockRegistry.unregisterClockChangeListener(clockChangeListener)
+ }
clockController.registerListeners(parentView)
- disposables.add(DisposableHandle { clockController.unregisterListeners() })
+ disposables += DisposableHandle { clockController.unregisterListeners() }
}
val receiver =
@@ -581,9 +580,9 @@
addAction(Intent.ACTION_TIME_CHANGED)
},
)
- disposables.add(DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) })
+ disposables += DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) }
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
val layoutChangeListener =
View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
if (clockController.clock !is DefaultClockController) {
@@ -602,9 +601,9 @@
}
}
parentView.addOnLayoutChangeListener(layoutChangeListener)
- disposables.add(
- DisposableHandle { parentView.removeOnLayoutChangeListener(layoutChangeListener) }
- )
+ disposables += DisposableHandle {
+ parentView.removeOnLayoutChangeListener(layoutChangeListener)
+ }
}
onClockChanged()
@@ -631,7 +630,7 @@
}
}
private fun onClockChanged() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
return
}
coroutineScope.launch {
@@ -678,7 +677,7 @@
}
private fun updateLargeClock(clock: ClockController) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
return
}
clock.largeClock.events.onTargetRegionChanged(
@@ -692,7 +691,7 @@
}
private fun updateSmallClock(clock: ClockController) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
return
}
clock.smallClock.events.onTargetRegionChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index f20c4ac..3b21141 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -22,10 +22,12 @@
import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
@@ -89,6 +91,12 @@
@Binds
@IntoSet
+ abstract fun aodToPrimaryBouncer(
+ impl: AodToPrimaryBouncerTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition
@Binds
@@ -111,6 +119,10 @@
@Binds
@IntoSet
+ abstract fun dreamingToAod(impl: DreamingToAodTransitionViewModel): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun dreamingToLockscreen(
impl: DreamingToLockscreenTransitionViewModel
): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
index 9c9df80..a215efa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
@@ -41,7 +41,7 @@
private fun excludeClockAndSmartspaceViews(transition: Transition) {
transition.excludeTarget(SmartspaceView::class.java, true)
- clockViewModel.clock?.let { clock ->
+ clockViewModel.currentClock.value?.let { clock ->
clock.largeClock.layout.views.forEach { view -> transition.excludeTarget(view, true) }
clock.smallClock.layout.views.forEach { view -> transition.excludeTarget(view, true) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
index 3adeb2a..c69d868 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
@@ -57,7 +57,9 @@
when (config.type) {
Type.NoTransition -> {}
Type.DefaultClockStepping ->
- addTransition(clockViewModel.clock?.let { DefaultClockSteppingTransition(it) })
+ addTransition(
+ clockViewModel.currentClock.value?.let { DefaultClockSteppingTransition(it) }
+ )
else -> addTransition(ClockSizeTransition(config, clockViewModel, smartspaceViewModel))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
index cd46d6c..2e96638 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
@@ -25,9 +25,9 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -49,14 +49,14 @@
private val vibratorHelper: VibratorHelper,
) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
addLeftShortcut(constraintLayout)
addRightShortcut(constraintLayout)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
leftShortcutHandle =
KeyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.start_button),
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 88ce9dc..d639978 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
@@ -23,7 +23,7 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
@@ -47,7 +47,7 @@
}
}
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
@@ -62,14 +62,14 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
clockViewModel.burnInLayer = burnInLayer
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
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 3d9c04e..2832e9d 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
@@ -26,8 +26,8 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
@@ -58,7 +58,7 @@
private lateinit var nic: NotificationIconContainer
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
nic =
@@ -77,7 +77,7 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
@@ -98,7 +98,7 @@
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
val 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 a183b72..881467f 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
@@ -30,8 +30,8 @@
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.constraintlayout.widget.ConstraintSet.VISIBLE
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
-import com.android.systemui.Flags
import com.android.systemui.customization.R as customizationR
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.KeyguardSection
@@ -70,7 +70,7 @@
override fun addViews(constraintLayout: ConstraintLayout) {}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!Flags.migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
KeyguardClockViewBinder.bind(
@@ -83,10 +83,10 @@
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!Flags.migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
- clockInteractor.clock?.let { clock ->
+ keyguardClockViewModel.currentClock.value?.let { clock ->
constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 8fd8bec..4c846e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -28,13 +28,12 @@
import androidx.constraintlayout.widget.ConstraintSet
import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.biometrics.AuthController
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -72,8 +71,8 @@
override fun addViews(constraintLayout: ConstraintLayout) {
if (
- !keyguardBottomAreaRefactor() &&
- !migrateClocksToBlueprint() &&
+ !KeyguardBottomAreaRefactor.isEnabled &&
+ !DeviceEntryUdfpsRefactor.isEnabled &&
!DeviceEntryUdfpsRefactor.isEnabled
) {
return
@@ -87,7 +86,7 @@
if (DeviceEntryUdfpsRefactor.isEnabled) {
DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
} else {
- // keyguardBottomAreaRefactor() or migrateClocksToBlueprint()
+ // KeyguardBottomAreaRefactor.isEnabled or MigrateClocksToBlueprint.isEnabled
LockIconView(context, null).apply { id = R.id.lock_icon_view }
}
constraintLayout.addView(view)
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 3361343..af0528a 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
@@ -21,7 +21,7 @@
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
+import com.android.systemui.keyguard.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
@@ -42,14 +42,14 @@
private var indicationAreaHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
val view = KeyguardIndicationArea(context, null)
constraintLayout.addView(view)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
indicationAreaHandle =
KeyguardIndicationAreaBinder.bind(
constraintLayout.requireViewById(R.id.keyguard_indication_area),
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 6a3b920..380e361 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
@@ -25,58 +25,42 @@
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.Flags.centralizedStatusBarHeightFix
-import com.android.systemui.Flags.migrateClocksToBlueprint
-import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.res.R
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.shade.NotificationPanelView
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import dagger.Lazy
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
/** Single column format for notifications (default for phones) */
class DefaultNotificationStackScrollLayoutSection
@Inject
constructor(
context: Context,
- sceneContainerFlags: SceneContainerFlags,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
- notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
- ambientState: AmbientState,
- controller: NotificationStackScrollLayoutController,
- notificationStackSizeCalculator: NotificationStackSizeCalculator,
+ sharedNotificationContainerBinder: SharedNotificationContainerBinder,
private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
- @Main mainDispatcher: CoroutineDispatcher,
) :
NotificationStackScrollLayoutSection(
context,
- sceneContainerFlags,
notificationPanelView,
sharedNotificationContainer,
sharedNotificationContainerViewModel,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
- notificationStackSizeCalculator,
- mainDispatcher,
+ sharedNotificationContainerBinder,
) {
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
constraintSet.apply {
val bottomMargin =
context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
val useLargeScreenHeader =
context.resources.getBoolean(R.bool.config_use_large_screen_shade_header)
val marginTopLargeScreen =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
index a203c53..32e76d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
@@ -29,9 +29,9 @@
import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
import androidx.core.view.isVisible
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
@@ -56,7 +56,7 @@
private var settingsPopupMenuHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled) {
return
}
val view =
@@ -71,7 +71,7 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
settingsPopupMenuHandle =
KeyguardSettingsViewBinder.bind(
constraintLayout.requireViewById<View>(R.id.keyguard_settings_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index 0c0eb8a..45b8257 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -25,8 +25,8 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.RIGHT
import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -48,14 +48,14 @@
private val vibratorHelper: VibratorHelper,
) : BaseShortcutSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
addLeftShortcut(constraintLayout)
addRightShortcut(constraintLayout)
}
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
leftShortcutHandle =
KeyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.start_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 6e8605b..45641db 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -31,8 +31,8 @@
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.dagger.KeyguardStatusViewComponent
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.res.R
@@ -58,7 +58,7 @@
private val statusViewId = R.id.keyguard_status_view
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
// At startup, 2 views with the ID `R.id.keyguard_status_view` will be available.
@@ -83,7 +83,7 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
constraintLayout.findViewById<KeyguardStatusView?>(R.id.keyguard_status_view)?.let {
val statusViewComponent =
keyguardStatusViewComponentFactory.build(it, context.display)
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 3265d79..2abb7ba 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
@@ -20,10 +20,10 @@
import android.content.Context
import androidx.constraintlayout.widget.ConstraintLayout
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.DeviceEntryUdfpsAccessibilityOverlayViewModel
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
import javax.inject.Inject
@@ -66,7 +66,7 @@
ConstraintSet.BOTTOM,
)
- if (Flags.keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
connect(
viewId,
ConstraintSet.BOTTOM,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
index d572c51..a17c5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/KeyguardSliceViewSection.kt
@@ -22,7 +22,7 @@
import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
@@ -34,7 +34,7 @@
val smartspaceController: LockscreenSmartspaceController,
) : KeyguardSection() {
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (smartspaceController.isEnabled()) return
constraintLayout.findViewById<View?>(R.id.keyguard_slice_view)?.let {
@@ -46,7 +46,7 @@
override fun bindData(constraintLayout: ConstraintLayout) {}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (smartspaceController.isEnabled()) return
constraintSet.apply {
@@ -81,7 +81,7 @@
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (smartspaceController.isEnabled()) return
constraintLayout.removeView(R.id.keyguard_slice_view)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
index 5dea7cb..2b601cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
@@ -25,38 +25,26 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.NotificationPanelView
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
-import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
abstract class NotificationStackScrollLayoutSection
constructor(
protected val context: Context,
- private val sceneContainerFlags: SceneContainerFlags,
private val notificationPanelView: NotificationPanelView,
private val sharedNotificationContainer: SharedNotificationContainer,
private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
- private val notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
- private val ambientState: AmbientState,
- private val controller: NotificationStackScrollLayoutController,
- private val notificationStackSizeCalculator: NotificationStackSizeCalculator,
- private val mainDispatcher: CoroutineDispatcher,
+ private val sharedNotificationContainerBinder: SharedNotificationContainerBinder,
) : KeyguardSection() {
private val placeHolderId = R.id.nssl_placeholder
- private val disposableHandles: MutableList<DisposableHandle> = mutableListOf()
+ private var disposableHandle: DisposableHandle? = null
/**
* Align the notification placeholder bottom to the top of either the lock icon or the ambient
@@ -82,7 +70,7 @@
}
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
// This moves the existing NSSL view to a different parent, as the controller is a
@@ -98,43 +86,21 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
- disposeHandles()
- disposableHandles.add(
- SharedNotificationContainerBinder.bind(
+ disposableHandle?.dispose()
+ disposableHandle =
+ sharedNotificationContainerBinder.bind(
sharedNotificationContainer,
sharedNotificationContainerViewModel,
- sceneContainerFlags,
- controller,
- notificationStackSizeCalculator,
- mainImmediateDispatcher = mainDispatcher,
)
- )
-
- if (sceneContainerFlags.isEnabled()) {
- disposableHandles.add(
- NotificationStackAppearanceViewBinder.bind(
- context,
- sharedNotificationContainer,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
- mainImmediateDispatcher = mainDispatcher,
- )
- )
- }
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- disposeHandles()
+ disposableHandle?.dispose()
+ disposableHandle = null
constraintLayout.removeView(placeHolderId)
}
-
- private fun disposeHandles() {
- disposableHandles.forEach { it.dispose() }
- disposableHandles.clear()
- }
}
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 b0f7a25..1847d27 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
@@ -23,8 +23,8 @@
import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
import com.android.systemui.keyguard.shared.model.KeyguardSection
@@ -56,7 +56,7 @@
private var pastVisibility: Int = -1
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
smartspaceView = smartspaceController.buildAndConnectView(constraintLayout)
weatherView = smartspaceController.buildAndConnectWeatherView(constraintLayout)
@@ -83,7 +83,7 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
KeyguardSmartspaceViewBinder.bind(
constraintLayout,
@@ -94,7 +94,7 @@
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
val horizontalPaddingStart =
context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) +
@@ -191,7 +191,7 @@
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) return
+ if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
listOf(smartspaceView, dateView, weatherView).forEach {
it?.let {
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 21e9455..5dbba75 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
@@ -28,7 +28,7 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.res.R
@@ -46,7 +46,7 @@
private val mediaContainerId = R.id.status_view_media_container
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
@@ -73,7 +73,7 @@
override fun bindData(constraintLayout: ConstraintLayout) {}
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
@@ -87,7 +87,7 @@
}
override fun removeViews(constraintLayout: ConstraintLayout) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 2545302..1a73866 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -23,51 +23,33 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.migrateClocksToBlueprint
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.res.R
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.NotificationPanelView
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
/** Large-screen format for notifications, shown as two columns on the device */
class SplitShadeNotificationStackScrollLayoutSection
@Inject
constructor(
context: Context,
- sceneContainerFlags: SceneContainerFlags,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
- notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
- ambientState: AmbientState,
- controller: NotificationStackScrollLayoutController,
- notificationStackSizeCalculator: NotificationStackSizeCalculator,
- private val smartspaceViewModel: KeyguardSmartspaceViewModel,
- @Main mainDispatcher: CoroutineDispatcher,
+ sharedNotificationContainerBinder: SharedNotificationContainerBinder,
) :
NotificationStackScrollLayoutSection(
context,
- sceneContainerFlags,
notificationPanelView,
sharedNotificationContainer,
sharedNotificationContainerViewModel,
- notificationStackAppearanceViewModel,
- ambientState,
- controller,
- notificationStackSizeCalculator,
- mainDispatcher,
+ sharedNotificationContainerBinder,
) {
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
return
}
constraintSet.apply {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 6184c82..4d3a78d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -216,7 +216,9 @@
captureSmartspace = !viewModel.useLargeClock && smartspaceViewModel.isSmartspaceEnabled
if (viewModel.useLargeClock) {
- viewModel.clock?.let { it.largeClock.layout.views.forEach { addTarget(it) } }
+ viewModel.currentClock.value?.let {
+ it.largeClock.layout.views.forEach { addTarget(it) }
+ }
} else {
addTarget(R.id.lockscreen_clock_view)
}
@@ -276,7 +278,9 @@
if (viewModel.useLargeClock) {
addTarget(R.id.lockscreen_clock_view)
} else {
- viewModel.clock?.let { it.largeClock.layout.views.forEach { addTarget(it) } }
+ viewModel.currentClock.value?.let {
+ it.largeClock.layout.views.forEach { addTarget(it) }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
index d26356e..ac2713d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.util.MathUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -47,13 +48,16 @@
to = KeyguardState.GONE,
)
- val lockscreenAlpha: Flow<Float> =
- transitionAnimation.sharedFlow(
+ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ var startAlpha = 1f
+ return transitionAnimation.sharedFlow(
duration = 200.milliseconds,
- onStep = { 1 - it },
+ onStart = { startAlpha = viewState.alpha() },
+ onStep = { MathUtils.lerp(startAlpha, 0f, it) },
onFinish = { 0f },
- onCancel = { 1f },
+ onCancel = { startAlpha },
)
+ }
/** Scrim alpha values */
val scrimAlpha: Flow<ScrimAlpha> =
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
index 5741b94..1e5f5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
@@ -18,8 +18,8 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -60,7 +60,7 @@
emit(goneToAodAlpha)
} else if (step.from == GONE && step.to == DOZING) {
emit(goneToDozingAlpha)
- } else if (!migrateClocksToBlueprint()) {
+ } else if (!MigrateClocksToBlueprint.isEnabled) {
emit(keyguardAlpha)
}
}
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
index f961e08..2054932 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -22,9 +22,9 @@
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.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -145,7 +145,7 @@
// 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()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
max(params.topInset - params.minViewY, burnInY)
} else {
max(params.topInset, params.minViewY + burnInY) - params.minViewY
@@ -168,8 +168,8 @@
private fun clockController(
provider: Provider<ClockController>?,
): Provider<ClockController>? {
- return if (Flags.migrateClocksToBlueprint()) {
- Provider { keyguardClockViewModel.clock }
+ return if (MigrateClocksToBlueprint.isEnabled) {
+ Provider { keyguardClockViewModel.currentClock.value }
} else {
provider
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
index c409028..cbbb820 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
@@ -30,8 +30,6 @@
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
/**
* Breaks down AOD->LOCKSCREEN transition into discrete steps for corresponding views to consume.
@@ -53,6 +51,8 @@
to = KeyguardState.LOCKSCREEN,
)
+ private var isShadeExpanded = false
+
/**
* Begin the transition from wherever the y-translation value is currently. This helps ensure a
* smooth transition if a transition in canceled.
@@ -77,22 +77,21 @@
}
val notificationAlpha: Flow<Float> =
- combine(
- shadeInteractor.shadeExpansion.map { it > 0f },
- shadeInteractor.qsExpansion.map { it > 0f },
- transitionAnimation.sharedFlow(
- duration = 500.milliseconds,
- onStep = { it },
- onCancel = { 1f },
- ),
- ) { isShadeExpanded, isQsExpanded, alpha ->
- if (isShadeExpanded || isQsExpanded) {
- // One example of this happening is dragging a notification while pulsing on AOD
- 1f
- } else {
- alpha
- }
- }
+ transitionAnimation.sharedFlow(
+ duration = 500.milliseconds,
+ onStart = {
+ isShadeExpanded =
+ shadeInteractor.shadeExpansion.value > 0f ||
+ shadeInteractor.qsExpansion.value > 0f
+ },
+ onStep = {
+ if (isShadeExpanded) {
+ 1f
+ } else {
+ it
+ }
+ },
+ )
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModel.kt
new file mode 100644
index 0000000..9a23007
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModel.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down AOD->PRIMARY BOUNCER transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AodToPrimaryBouncerTransitionViewModel
+@Inject
+constructor(
+ animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ animationFlow.setup(
+ duration = FromAodTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
+ from = KeyguardState.AOD,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ )
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 4c0a949..1b91c49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -55,6 +55,8 @@
lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel,
+ dreamingToAodTransitionViewModel: DreamingToAodTransitionViewModel,
+ primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
) {
val color: Flow<Int> =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -96,6 +98,9 @@
lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
dozingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ dreamingToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ primaryBouncerToLockscreenTransitionViewModel
+ .deviceEntryBackgroundViewAlpha,
)
.merge()
.onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 1a01897..bc4fd1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -19,6 +19,7 @@
import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
@@ -33,9 +34,11 @@
import com.android.systemui.util.kotlin.sample
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -45,6 +48,7 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
/** Models the UI state for the containing device entry icon & long-press handling view. */
@ExperimentalCoroutinesApi
@@ -62,6 +66,7 @@
private val keyguardViewController: Lazy<KeyguardViewController>,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
+ @Application private val scope: CoroutineScope,
) {
val isUdfpsSupported: StateFlow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
private val intEvaluator = IntEvaluator()
@@ -73,7 +78,10 @@
private val qsProgress: Flow<Float> = shadeInteractor.qsExpansion.onStart { emit(0f) }
private val shadeExpansion: Flow<Float> = shadeInteractor.shadeExpansion.onStart { emit(0f) }
private val transitionAlpha: Flow<Float> =
- transitions.map { it.deviceEntryParentViewAlpha }.merge()
+ transitions
+ .map { it.deviceEntryParentViewAlpha }
+ .merge()
+ .shareIn(scope, SharingStarted.WhileSubscribed())
private val alphaMultiplierFromShadeExpansion: Flow<Float> =
combine(
showingAlternateBouncer,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModel.kt
new file mode 100644
index 0000000..0fa7475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/** Breaks down DREAMING->AOD transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DreamingToAodTransitionViewModel
+@Inject
+constructor(
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+ private val transitionAnimation =
+ animationFlow.setup(
+ duration = FromDreamingTransitionInteractor.TO_AOD_DURATION,
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.AOD,
+ )
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+ ->
+ if (udfpsEnrolledAndEnabled) {
+ transitionAnimation.sharedFlow(
+ duration = FromDreamingTransitionInteractor.TO_AOD_DURATION,
+ onStep = { it },
+ onFinish = { 1f },
+ )
+ } else {
+ emptyFlow()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt
index e0b1c50..a2ce408 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt
@@ -43,9 +43,11 @@
transitionAnimation.sharedFlow(
duration = 250.milliseconds,
onStep = { it },
- onCancel = { 0f },
+ onCancel = { 1f },
)
+ val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+
val deviceEntryBackgroundViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(1f)
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 b6622e5..1c1c33a 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
@@ -26,7 +26,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.ComposeLockscreen
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.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -54,8 +53,6 @@
val useLargeClock: Boolean
get() = clockSize.value == LARGE
- var clock: ClockController? by keyguardClockInteractor::clock
-
val clockSize =
combine(keyguardClockInteractor.selectedClockSize, keyguardClockInteractor.clockSize) {
selectedSize,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
index e35e065..8409f15 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
@@ -16,10 +16,10 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.doze.util.BurnInHelperWrapper
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -52,7 +52,7 @@
/** An observable for whether the indication area should be padded. */
val isIndicationAreaPadded: Flow<Boolean> =
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled) {
combine(shortcutsCombinedViewModel.startButton, shortcutsCombinedViewModel.endButton) {
startButtonModel,
endButtonModel ->
@@ -79,7 +79,7 @@
/** An observable for the x-offset by which the indication area should be translated. */
val indicationAreaTranslationX: Flow<Float> =
- if (migrateClocksToBlueprint() || keyguardBottomAreaRefactor()) {
+ if (MigrateClocksToBlueprint.isEnabled || KeyguardBottomAreaRefactor.isEnabled) {
burnIn.map { it.translationX.toFloat() }
} else {
bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
@@ -87,7 +87,7 @@
/** Returns an observable for the y-offset by which the indication area should be translated. */
fun indicationAreaTranslationY(defaultBurnInOffset: Int): Flow<Float> {
- return if (migrateClocksToBlueprint()) {
+ return if (MigrateClocksToBlueprint.isEnabled) {
burnIn.map { it.translationY.toFloat() }
} else {
keyguardInteractor.dozeAmount
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
index b9ff259..4f2c6f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
@@ -24,10 +24,8 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/** View model for the small clock view, large clock view. */
class KeyguardPreviewClockViewModel
@@ -45,15 +43,7 @@
val isSmallClockVisible: Flow<Boolean> =
interactor.selectedClockSize.map { it == SettingsClockSize.SMALL }
- var lastClockPair: Pair<ClockController, ClockController>? = null
+ val previewClock: Flow<ClockController> = interactor.previewClock
- val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
- interactor.previewClockPair
-
- val selectedClockSize: StateFlow<SettingsClockSize?> =
- interactor.selectedClockSize.stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = null
- )
+ val selectedClockSize: StateFlow<SettingsClockSize?> = interactor.selectedClockSize
}
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 301f00e..5337ca3 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
@@ -91,6 +91,7 @@
private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
+ private val goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
private val lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
private val lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
@@ -205,7 +206,7 @@
merge(
alphaOnShadeExpansion,
keyguardInteractor.dismissAlpha.filterNotNull(),
- alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ alternateBouncerToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
@@ -218,6 +219,7 @@
goneToAodTransitionViewModel.enterFromTopAnimationAlpha,
goneToDozingTransitionViewModel.lockscreenAlpha,
goneToDreamingTransitionViewModel.lockscreenAlpha,
+ goneToLockscreenTransitionViewModel.lockscreenAlpha,
lockscreenToAodTransitionViewModel.lockscreenAlpha(viewState),
lockscreenToDozingTransitionViewModel.lockscreenAlpha,
lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
index 34c9ac9..2575041 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
@@ -18,7 +18,6 @@
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
@@ -27,8 +26,6 @@
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.flatMapLatest
/**
* Breaks down PRIMARY BOUNCER->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -39,7 +36,6 @@
class PrimaryBouncerToLockscreenTransitionViewModel
@Inject
constructor(
- deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {
private val transitionAnimation =
@@ -49,15 +45,6 @@
to = KeyguardState.LOCKSCREEN,
)
- val deviceEntryBackgroundViewAlpha: Flow<Float> =
- deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfps ->
- if (isUdfps) {
- transitionAnimation.immediatelyTransitionTo(1f)
- } else {
- emptyFlow()
- }
- }
-
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
duration = 250.milliseconds,
@@ -67,6 +54,8 @@
val lockscreenAlpha: Flow<Float> = shortcutsAlpha
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(1f)
override val deviceEntryParentViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(1f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaDataRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaDataRepository.kt
new file mode 100644
index 0000000..b6fd287
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaDataRepository.kt
@@ -0,0 +1,123 @@
+/*
+ * 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.media.controls.data.repository
+
+import android.util.Log
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.media.controls.util.MediaFlags
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+private const val TAG = "MediaDataRepository"
+private const val DEBUG = true
+
+/** A repository that holds the state of all media controls in carousel. */
+@SysUISingleton
+class MediaDataRepository
+@Inject
+constructor(
+ private val mediaFlags: MediaFlags,
+ dumpManager: DumpManager,
+) : Dumpable {
+
+ private val _mediaEntries: MutableStateFlow<Map<String, MediaData>> =
+ MutableStateFlow(LinkedHashMap())
+ val mediaEntries: StateFlow<Map<String, MediaData>> = _mediaEntries.asStateFlow()
+
+ private val _smartspaceMediaData: MutableStateFlow<SmartspaceMediaData> =
+ MutableStateFlow(SmartspaceMediaData())
+ val smartspaceMediaData: StateFlow<SmartspaceMediaData> = _smartspaceMediaData.asStateFlow()
+
+ init {
+ dumpManager.registerNormalDumpable(TAG, this)
+ }
+
+ /** Updates the recommendation data with a new smartspace media data. */
+ fun setRecommendation(recommendation: SmartspaceMediaData) {
+ _smartspaceMediaData.value = recommendation
+ }
+
+ /**
+ * Marks the recommendation data as inactive.
+ *
+ * @return true if the recommendation was actually marked as inactive, false otherwise.
+ */
+ fun setRecommendationInactive(key: String): Boolean {
+ if (!mediaFlags.isPersistentSsCardEnabled()) {
+ Log.e(TAG, "Only persistent recommendation can be inactive!")
+ return false
+ }
+ if (DEBUG) Log.d(TAG, "Setting smartspace recommendation inactive")
+
+ if (smartspaceMediaData.value.targetId != key || !smartspaceMediaData.value.isValid()) {
+ // If this doesn't match, or we've already invalidated the data, no action needed
+ return false
+ }
+
+ setRecommendation(smartspaceMediaData.value.copy(isActive = false))
+ return true
+ }
+
+ /**
+ * Marks the recommendation data as dismissed.
+ *
+ * @return true if the recommendation was dismissed or already inactive, false otherwise.
+ */
+ fun dismissSmartspaceRecommendation(key: String): Boolean {
+ val data = smartspaceMediaData.value
+ if (data.targetId != key || !data.isValid()) {
+ // If this doesn't match, or we've already invalidated the data, no action needed
+ return false
+ }
+
+ if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
+ if (data.isActive) {
+ setRecommendation(
+ SmartspaceMediaData(
+ targetId = smartspaceMediaData.value.targetId,
+ instanceId = smartspaceMediaData.value.instanceId
+ )
+ )
+ }
+ return true
+ }
+
+ fun removeMediaEntry(key: String): MediaData? {
+ val entries = LinkedHashMap<String, MediaData>(_mediaEntries.value)
+ val mediaData = entries.remove(key)
+ _mediaEntries.value = entries
+ return mediaData
+ }
+
+ fun addMediaEntry(key: String, data: MediaData): MediaData? {
+ val entries = LinkedHashMap<String, MediaData>(_mediaEntries.value)
+ val mediaData = entries.put(key, data)
+ _mediaEntries.value = entries
+ return mediaData
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply { println("mediaEntries: ${mediaEntries.value}") }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
new file mode 100644
index 0000000..b94a4af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.media.controls.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** A repository that holds the state of filtered media data on the device. */
+@SysUISingleton
+class MediaFilterRepository @Inject constructor() {
+
+ /** Key of media control that recommendations card reactivated. */
+ private val _reactivatedKey: MutableStateFlow<String?> = MutableStateFlow(null)
+ val reactivatedKey: StateFlow<String?> = _reactivatedKey.asStateFlow()
+
+ private val _smartspaceMediaData: MutableStateFlow<SmartspaceMediaData> =
+ MutableStateFlow(SmartspaceMediaData())
+ val smartspaceMediaData: StateFlow<SmartspaceMediaData> = _smartspaceMediaData.asStateFlow()
+
+ private val _selectedUserEntries: MutableStateFlow<Map<String, MediaData>> =
+ MutableStateFlow(LinkedHashMap())
+ val selectedUserEntries: StateFlow<Map<String, MediaData>> = _selectedUserEntries.asStateFlow()
+
+ private val _allUserEntries: MutableStateFlow<Map<String, MediaData>> =
+ MutableStateFlow(LinkedHashMap())
+ val allUserEntries: StateFlow<Map<String, MediaData>> = _allUserEntries.asStateFlow()
+
+ fun addMediaEntry(key: String, data: MediaData) {
+ val entries = LinkedHashMap<String, MediaData>(_allUserEntries.value)
+ entries[key] = data
+ _allUserEntries.value = entries
+ }
+
+ /**
+ * Removes the media entry corresponding to the given [key].
+ *
+ * @return media data if an entry is actually removed, `null` otherwise.
+ */
+ fun removeMediaEntry(key: String): MediaData? {
+ val entries = LinkedHashMap<String, MediaData>(_allUserEntries.value)
+ val mediaData = entries.remove(key)
+ _allUserEntries.value = entries
+ return mediaData
+ }
+
+ fun addSelectedUserMediaEntry(key: String, data: MediaData) {
+ val entries = LinkedHashMap<String, MediaData>(_selectedUserEntries.value)
+ entries[key] = data
+ _selectedUserEntries.value = entries
+ }
+
+ /**
+ * Removes selected user media entry given the corresponding key.
+ *
+ * @return media data if an entry is actually removed, `null` otherwise.
+ */
+ fun removeSelectedUserMediaEntry(key: String): MediaData? {
+ val entries = LinkedHashMap<String, MediaData>(_selectedUserEntries.value)
+ val mediaData = entries.remove(key)
+ _selectedUserEntries.value = entries
+ return mediaData
+ }
+
+ /**
+ * Removes selected user media entry given a key and media data.
+ *
+ * @return true if media data is removed, false otherwise.
+ */
+ fun removeSelectedUserMediaEntry(key: String, data: MediaData): Boolean {
+ val entries = LinkedHashMap<String, MediaData>(_selectedUserEntries.value)
+ val succeed = entries.remove(key, data)
+ if (!succeed) {
+ return false
+ }
+ _selectedUserEntries.value = entries
+ return true
+ }
+
+ fun clearSelectedUserMedia() {
+ _selectedUserEntries.value = LinkedHashMap()
+ }
+
+ /** Updates recommendation data with a new smartspace media data. */
+ fun setRecommendation(smartspaceMediaData: SmartspaceMediaData) {
+ _smartspaceMediaData.value = smartspaceMediaData
+ }
+
+ /** Updates media control key that recommendations card reactivated. */
+ fun setReactivatedKey(key: String?) {
+ _reactivatedKey.value = key
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/MediaDomainModule.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/MediaDomainModule.kt
new file mode 100644
index 0000000..e0c5419
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/MediaDomainModule.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.media.controls.domain
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.controls.domain.pipeline.LegacyMediaDataManagerImpl
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
+import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor
+import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
+import com.android.systemui.media.controls.util.MediaFlags
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Provider
+
+/** Dagger module for injecting media controls domain interfaces. */
+@Module
+interface MediaDomainModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(MediaCarouselInteractor::class)
+ fun bindMediaCarouselInteractor(interactor: MediaCarouselInteractor): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(MediaDataProcessor::class)
+ fun bindMediaDataProcessor(interactor: MediaDataProcessor): CoreStartable
+ companion object {
+
+ @Provides
+ @SysUISingleton
+ fun providesMediaDataManager(
+ legacyProvider: Provider<LegacyMediaDataManagerImpl>,
+ newProvider: Provider<MediaCarouselInteractor>,
+ mediaFlags: MediaFlags,
+ ): MediaDataManager {
+ return if (mediaFlags.isMediaControlsRefactorEnabled()) {
+ newProvider.get()
+ } else {
+ legacyProvider.get()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt
rename to packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt
index bc539ef..c02478b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt
@@ -61,7 +61,7 @@
* This is added at the end of the pipeline since we may still need to handle callbacks from
* background users (e.g. timeouts).
*/
-class MediaDataFilter
+class LegacyMediaDataFilterImpl
@Inject
constructor(
private val context: Context,
@@ -74,9 +74,9 @@
private val mediaFlags: MediaFlags,
) : MediaDataManager.Listener {
private val _listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
- internal val listeners: Set<MediaDataManager.Listener>
+ val listeners: Set<MediaDataManager.Listener>
get() = _listeners.toSet()
- internal lateinit var mediaDataManager: MediaDataManager
+ lateinit var mediaDataManager: MediaDataManager
private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
// The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
@@ -279,7 +279,7 @@
val mediaKeys = userEntries.keys.toSet()
mediaKeys.forEach {
// Force updates to listeners, needed for re-activated card
- mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true)
+ mediaDataManager.setInactive(it, timedOut = true, forceUpdate = true)
}
if (smartspaceMediaData.isActive) {
val dismissIntent = smartspaceMediaData.dismissIntent
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
new file mode 100644
index 0000000..3a831156
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
@@ -0,0 +1,1693 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.controls.domain.pipeline
+
+import android.annotation.SuppressLint
+import android.app.ActivityOptions
+import android.app.BroadcastOptions
+import android.app.Notification
+import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
+import android.app.PendingIntent
+import android.app.StatusBarManager
+import android.app.UriGrantsManager
+import android.app.smartspace.SmartspaceAction
+import android.app.smartspace.SmartspaceConfig
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.BroadcastReceiver
+import android.content.ContentProvider
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.ImageDecoder
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.Icon
+import android.media.MediaDescription
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.net.Uri
+import android.os.Parcelable
+import android.os.Process
+import android.os.UserHandle
+import android.provider.Settings
+import android.service.notification.StatusBarNotification
+import android.support.v4.media.MediaMetadataCompat
+import android.text.TextUtils
+import android.util.Log
+import android.util.Pair as APair
+import androidx.media.utils.MediaConstants
+import com.android.app.tracing.traceSection
+import com.android.internal.annotations.Keep
+import com.android.internal.logging.InstanceId
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
+import com.android.systemui.media.controls.domain.resume.MediaResumeListener
+import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
+import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
+import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
+import com.android.systemui.media.controls.shared.model.MediaAction
+import com.android.systemui.media.controls.shared.model.MediaButton
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
+import com.android.systemui.media.controls.ui.view.MediaViewHolder
+import com.android.systemui.media.controls.util.MediaControllerFactory
+import com.android.systemui.media.controls.util.MediaDataUtils
+import com.android.systemui.media.controls.util.MediaFlags
+import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
+import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
+import com.android.systemui.statusbar.notification.row.HybridGroupManager
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.Assert
+import com.android.systemui.util.Utils
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.ThreadFactory
+import com.android.systemui.util.time.SystemClock
+import java.io.IOException
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+// URI fields to try loading album art from
+private val ART_URIS =
+ arrayOf(
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ MediaMetadata.METADATA_KEY_ART_URI,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
+ )
+
+private const val TAG = "MediaDataManager"
+private const val DEBUG = true
+private const val EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY = "dismiss_intent"
+
+private val LOADING =
+ MediaData(
+ userId = -1,
+ initialized = false,
+ app = null,
+ appIcon = null,
+ artist = null,
+ song = null,
+ artwork = null,
+ actions = emptyList(),
+ actionsToShowInCompact = emptyList(),
+ packageName = "INVALID",
+ token = null,
+ clickIntent = null,
+ device = null,
+ active = true,
+ resumeAction = null,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ appUid = Process.INVALID_UID
+ )
+
+internal val EMPTY_SMARTSPACE_MEDIA_DATA =
+ SmartspaceMediaData(
+ targetId = "INVALID",
+ isActive = false,
+ packageName = "INVALID",
+ cardAction = null,
+ recommendations = emptyList(),
+ dismissIntent = null,
+ headphoneConnectionTimeMillis = 0,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ expiryTimeMs = 0,
+ )
+
+const val MEDIA_TITLE_ERROR_MESSAGE = "Invalid media data: title is null or blank."
+
+/**
+ * Allow recommendations from smartspace to show in media controls. Requires
+ * [Utils.useQsMediaPlayer] to be enabled. On by default, but can be disabled by setting to 0
+ */
+private fun allowMediaRecommendations(context: Context): Boolean {
+ val flag =
+ Settings.Secure.getInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 1
+ )
+ return Utils.useQsMediaPlayer(context) && flag > 0
+}
+
+/** A class that facilitates management and loading of Media Data, ready for binding. */
+@SysUISingleton
+class LegacyMediaDataManagerImpl(
+ private val context: Context,
+ @Background private val backgroundExecutor: Executor,
+ @Main private val uiExecutor: Executor,
+ @Main private val foregroundExecutor: DelayableExecutor,
+ private val mediaControllerFactory: MediaControllerFactory,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ dumpManager: DumpManager,
+ mediaTimeoutListener: MediaTimeoutListener,
+ mediaResumeListener: MediaResumeListener,
+ mediaSessionBasedFilter: MediaSessionBasedFilter,
+ private val mediaDeviceManager: MediaDeviceManager,
+ mediaDataCombineLatest: MediaDataCombineLatest,
+ private val mediaDataFilter: LegacyMediaDataFilterImpl,
+ private val activityStarter: ActivityStarter,
+ private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
+ private var useMediaResumption: Boolean,
+ private val useQsMediaPlayer: Boolean,
+ private val systemClock: SystemClock,
+ private val tunerService: TunerService,
+ private val mediaFlags: MediaFlags,
+ private val logger: MediaUiEventLogger,
+ private val smartspaceManager: SmartspaceManager?,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener, MediaDataManager {
+
+ companion object {
+ // UI surface label for subscribing Smartspace updates.
+ @JvmField val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
+
+ // Smartspace package name's extra key.
+ @JvmField val EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"
+
+ // Maximum number of actions allowed in compact view
+ @JvmField val MAX_COMPACT_ACTIONS = 3
+
+ // Maximum number of actions allowed in expanded view
+ @JvmField val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
+ }
+
+ private val themeText =
+ com.android.settingslib.Utils.getColorAttr(
+ context,
+ com.android.internal.R.attr.textColorPrimary
+ )
+ .defaultColor
+
+ // Internal listeners are part of the internal pipeline. External listeners (those registered
+ // with [MediaDeviceManager.addListener]) receive events after they have propagated through
+ // the internal pipeline.
+ // Another way to think of the distinction between internal and external listeners is the
+ // following. Internal listeners are listeners that MediaDataManager depends on, and external
+ // listeners are listeners that depend on MediaDataManager.
+ // TODO(b/159539991#comment5): Move internal listeners to separate package.
+ private val internalListeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
+ private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
+ // There should ONLY be at most one Smartspace media recommendation.
+ var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
+ @Keep private var smartspaceSession: SmartspaceSession? = null
+ private var allowMediaRecommendations = allowMediaRecommendations(context)
+
+ private val artworkWidth =
+ context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize
+ )
+ private val artworkHeight =
+ context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
+
+ @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
+ private val statusBarManager =
+ context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager
+
+ /** Check whether this notification is an RCN */
+ private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
+ return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
+ }
+
+ @Inject
+ constructor(
+ context: Context,
+ threadFactory: ThreadFactory,
+ @Main uiExecutor: Executor,
+ @Main foregroundExecutor: DelayableExecutor,
+ mediaControllerFactory: MediaControllerFactory,
+ dumpManager: DumpManager,
+ broadcastDispatcher: BroadcastDispatcher,
+ mediaTimeoutListener: MediaTimeoutListener,
+ mediaResumeListener: MediaResumeListener,
+ mediaSessionBasedFilter: MediaSessionBasedFilter,
+ mediaDeviceManager: MediaDeviceManager,
+ mediaDataCombineLatest: MediaDataCombineLatest,
+ mediaDataFilter: LegacyMediaDataFilterImpl,
+ activityStarter: ActivityStarter,
+ smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
+ clock: SystemClock,
+ tunerService: TunerService,
+ mediaFlags: MediaFlags,
+ logger: MediaUiEventLogger,
+ smartspaceManager: SmartspaceManager?,
+ keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ ) : this(
+ context,
+ // Loading bitmap for UMO background can take longer time, so it cannot run on the default
+ // background thread. Use a custom thread for media.
+ threadFactory.buildExecutorOnNewThread(TAG),
+ uiExecutor,
+ foregroundExecutor,
+ mediaControllerFactory,
+ broadcastDispatcher,
+ dumpManager,
+ mediaTimeoutListener,
+ mediaResumeListener,
+ mediaSessionBasedFilter,
+ mediaDeviceManager,
+ mediaDataCombineLatest,
+ mediaDataFilter,
+ activityStarter,
+ smartspaceMediaDataProvider,
+ Utils.useMediaResumption(context),
+ Utils.useQsMediaPlayer(context),
+ clock,
+ tunerService,
+ mediaFlags,
+ logger,
+ smartspaceManager,
+ keyguardUpdateMonitor,
+ )
+
+ private val appChangeReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_PACKAGES_SUSPENDED -> {
+ val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ packages?.forEach { removeAllForPackage(it) }
+ }
+ Intent.ACTION_PACKAGE_REMOVED,
+ Intent.ACTION_PACKAGE_RESTARTED -> {
+ intent.data?.encodedSchemeSpecificPart?.let { removeAllForPackage(it) }
+ }
+ }
+ }
+ }
+
+ init {
+ dumpManager.registerDumpable(TAG, this)
+
+ // Initialize the internal processing pipeline. The listeners at the front of the pipeline
+ // are set as internal listeners so that they receive events. From there, events are
+ // propagated through the pipeline. The end of the pipeline is currently mediaDataFilter,
+ // so it is responsible for dispatching events to external listeners. To achieve this,
+ // external listeners that are registered with [MediaDataManager.addListener] are actually
+ // registered as listeners to mediaDataFilter.
+ addInternalListener(mediaTimeoutListener)
+ addInternalListener(mediaResumeListener)
+ addInternalListener(mediaSessionBasedFilter)
+ mediaSessionBasedFilter.addListener(mediaDeviceManager)
+ mediaSessionBasedFilter.addListener(mediaDataCombineLatest)
+ mediaDeviceManager.addListener(mediaDataCombineLatest)
+ mediaDataCombineLatest.addListener(mediaDataFilter)
+
+ // Set up links back into the pipeline for listeners that need to send events upstream.
+ mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean ->
+ setInactive(key, timedOut)
+ }
+ mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
+ updateState(key, state)
+ }
+ mediaTimeoutListener.sessionCallback = { key: String -> onSessionDestroyed(key) }
+ mediaResumeListener.setManager(this)
+ mediaDataFilter.mediaDataManager = this
+
+ val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
+ broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
+
+ val uninstallFilter =
+ IntentFilter().apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_RESTARTED)
+ addDataScheme("package")
+ }
+ // BroadcastDispatcher does not allow filters with data schemes
+ context.registerReceiver(appChangeReceiver, uninstallFilter)
+
+ // Register for Smartspace data updates.
+ smartspaceMediaDataProvider.registerListener(this)
+ smartspaceSession =
+ smartspaceManager?.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build()
+ )
+ smartspaceSession?.let {
+ it.addOnTargetsAvailableListener(
+ // Use a main uiExecutor thread listening to Smartspace updates instead of using
+ // the existing background executor.
+ // SmartspaceSession has scheduled routine updates which can be unpredictable on
+ // test simulators, using the backgroundExecutor makes it's hard to test the threads
+ // numbers.
+ uiExecutor,
+ SmartspaceSession.OnTargetsAvailableListener { targets ->
+ smartspaceMediaDataProvider.onTargetsAvailable(targets)
+ }
+ )
+ }
+ smartspaceSession?.let { it.requestSmartspaceUpdate() }
+ tunerService.addTunable(
+ object : TunerService.Tunable {
+ override fun onTuningChanged(key: String?, newValue: String?) {
+ allowMediaRecommendations = allowMediaRecommendations(context)
+ if (!allowMediaRecommendations) {
+ dismissSmartspaceRecommendation(
+ key = smartspaceMediaData.targetId,
+ delay = 0L
+ )
+ }
+ }
+ },
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION
+ )
+ }
+
+ override fun destroy() {
+ smartspaceMediaDataProvider.unregisterListener(this)
+ smartspaceSession?.close()
+ smartspaceSession = null
+ context.unregisterReceiver(appChangeReceiver)
+ }
+
+ override fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
+ if (useQsMediaPlayer && isMediaNotification(sbn)) {
+ var isNewlyActiveEntry = false
+ Assert.isMainThread()
+ val oldKey = findExistingEntry(key, sbn.packageName)
+ if (oldKey == null) {
+ val instanceId = logger.getNewInstanceId()
+ val temp =
+ LOADING.copy(
+ packageName = sbn.packageName,
+ instanceId = instanceId,
+ createdTimestampMillis = systemClock.currentTimeMillis(),
+ )
+ mediaEntries.put(key, temp)
+ isNewlyActiveEntry = true
+ } else if (oldKey != key) {
+ // Resume -> active conversion; move to new key
+ val oldData = mediaEntries.remove(oldKey)!!
+ isNewlyActiveEntry = true
+ mediaEntries.put(key, oldData)
+ }
+ loadMediaData(key, sbn, oldKey, isNewlyActiveEntry)
+ } else {
+ onNotificationRemoved(key)
+ }
+ }
+
+ private fun removeAllForPackage(packageName: String) {
+ Assert.isMainThread()
+ val toRemove = mediaEntries.filter { it.value.packageName == packageName }
+ toRemove.forEach { removeEntry(it.key) }
+ }
+
+ override fun setResumeAction(key: String, action: Runnable?) {
+ mediaEntries.get(key)?.let {
+ it.resumeAction = action
+ it.hasCheckedForResume = true
+ }
+ }
+
+ override fun addResumptionControls(
+ userId: Int,
+ desc: MediaDescription,
+ action: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ // Resume controls don't have a notification key, so store by package name instead
+ if (!mediaEntries.containsKey(packageName)) {
+ val instanceId = logger.getNewInstanceId()
+ val appUid =
+ try {
+ context.packageManager.getApplicationInfo(packageName, 0)?.uid!!
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app UID for $packageName", e)
+ Process.INVALID_UID
+ }
+
+ val resumeData =
+ LOADING.copy(
+ packageName = packageName,
+ resumeAction = action,
+ hasCheckedForResume = true,
+ instanceId = instanceId,
+ appUid = appUid,
+ createdTimestampMillis = systemClock.currentTimeMillis(),
+ )
+ mediaEntries.put(packageName, resumeData)
+ logSingleVsMultipleMediaAdded(appUid, packageName, instanceId)
+ logger.logResumeMediaAdded(appUid, packageName, instanceId)
+ }
+ backgroundExecutor.execute {
+ loadMediaDataInBgForResumption(
+ userId,
+ desc,
+ action,
+ token,
+ appName,
+ appIntent,
+ packageName
+ )
+ }
+ }
+
+ /**
+ * Check if there is an existing entry that matches the key or package name. Returns the key
+ * that matches, or null if not found.
+ */
+ private fun findExistingEntry(key: String, packageName: String): String? {
+ if (mediaEntries.containsKey(key)) {
+ return key
+ }
+ // Check if we already had a resume player
+ if (mediaEntries.containsKey(packageName)) {
+ return packageName
+ }
+ return null
+ }
+
+ private fun loadMediaData(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?,
+ isNewlyActiveEntry: Boolean = false,
+ ) {
+ backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, isNewlyActiveEntry) }
+ }
+
+ /** Add a listener for changes in this class */
+ override fun addListener(listener: MediaDataManager.Listener) {
+ // mediaDataFilter is the current end of the internal pipeline. Register external
+ // listeners as listeners to it.
+ mediaDataFilter.addListener(listener)
+ }
+
+ /** Remove a listener for changes in this class */
+ override fun removeListener(listener: MediaDataManager.Listener) {
+ // Since mediaDataFilter is the current end of the internal pipelie, external listeners
+ // have been registered to it. So, they need to be removed from it too.
+ mediaDataFilter.removeListener(listener)
+ }
+
+ /** Add a listener for internal events. */
+ private fun addInternalListener(listener: MediaDataManager.Listener) =
+ internalListeners.add(listener)
+
+ /**
+ * Notify internal listeners of media loaded event.
+ *
+ * External listeners registered with [addListener] will be notified after the event propagates
+ * through the internal listener pipeline.
+ */
+ private fun notifyMediaDataLoaded(key: String, oldKey: String?, info: MediaData) {
+ internalListeners.forEach { it.onMediaDataLoaded(key, oldKey, info) }
+ }
+
+ /**
+ * Notify internal listeners of Smartspace media loaded event.
+ *
+ * External listeners registered with [addListener] will be notified after the event propagates
+ * through the internal listener pipeline.
+ */
+ private fun notifySmartspaceMediaDataLoaded(key: String, info: SmartspaceMediaData) {
+ internalListeners.forEach { it.onSmartspaceMediaDataLoaded(key, info) }
+ }
+
+ /**
+ * Notify internal listeners of media removed event.
+ *
+ * External listeners registered with [addListener] will be notified after the event propagates
+ * through the internal listener pipeline.
+ */
+ private fun notifyMediaDataRemoved(key: String) {
+ internalListeners.forEach { it.onMediaDataRemoved(key) }
+ }
+
+ /**
+ * Notify internal listeners of Smartspace media removed event.
+ *
+ * External listeners registered with [addListener] will be notified after the event propagates
+ * through the internal listener pipeline.
+ *
+ * @param immediately indicates should apply the UI changes immediately, otherwise wait until
+ * the next refresh-round before UI becomes visible. Should only be true if the update is
+ * initiated by user's interaction.
+ */
+ private fun notifySmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
+ internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
+ }
+
+ /**
+ * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
+ * will make the player not active anymore, hiding it from QQS and Keyguard.
+ *
+ * @see MediaData.active
+ */
+ override fun setInactive(key: String, timedOut: Boolean, forceUpdate: Boolean) {
+ mediaEntries[key]?.let {
+ if (timedOut && !forceUpdate) {
+ // Only log this event when media expires on its own
+ logger.logMediaTimeout(it.appUid, it.packageName, it.instanceId)
+ }
+ if (it.active == !timedOut && !forceUpdate) {
+ if (it.resumption) {
+ if (DEBUG) Log.d(TAG, "timing out resume player $key")
+ dismissMediaData(key, 0L /* delay */)
+ }
+ return
+ }
+ // Update last active if media was still active.
+ if (it.active) {
+ it.lastActive = systemClock.elapsedRealtime()
+ }
+ it.active = !timedOut
+ if (DEBUG) Log.d(TAG, "Updating $key timedOut: $timedOut")
+ onMediaDataLoaded(key, key, it)
+ }
+
+ if (key == smartspaceMediaData.targetId) {
+ if (DEBUG) Log.d(TAG, "smartspace card expired")
+ dismissSmartspaceRecommendation(key, delay = 0L)
+ }
+ }
+
+ /** Called when the player's [PlaybackState] has been updated with new actions and/or state */
+ private fun updateState(key: String, state: PlaybackState) {
+ mediaEntries.get(key)?.let {
+ val token = it.token
+ if (token == null) {
+ if (DEBUG) Log.d(TAG, "State updated, but token was null")
+ return
+ }
+ val actions =
+ createActionsFromState(
+ it.packageName,
+ mediaControllerFactory.create(it.token),
+ UserHandle(it.userId)
+ )
+
+ // Control buttons
+ // If flag is enabled and controller has a PlaybackState,
+ // create actions from session info
+ // otherwise, no need to update semantic actions.
+ val data =
+ if (actions != null) {
+ it.copy(semanticActions = actions, isPlaying = isPlayingState(state.state))
+ } else {
+ it.copy(isPlaying = isPlayingState(state.state))
+ }
+ if (DEBUG) Log.d(TAG, "State updated outside of notification")
+ onMediaDataLoaded(key, key, data)
+ }
+ }
+
+ private fun removeEntry(key: String, logEvent: Boolean = true) {
+ mediaEntries.remove(key)?.let {
+ if (logEvent) {
+ logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
+ }
+ }
+ notifyMediaDataRemoved(key)
+ }
+
+ /** Dismiss a media entry. Returns false if the key was not found. */
+ override fun dismissMediaData(key: String, delay: Long): Boolean {
+ val existed = mediaEntries[key] != null
+ backgroundExecutor.execute {
+ mediaEntries[key]?.let { mediaData ->
+ if (mediaData.isLocalSession()) {
+ mediaData.token?.let {
+ val mediaController = mediaControllerFactory.create(it)
+ mediaController.transportControls.stop()
+ }
+ }
+ }
+ }
+ foregroundExecutor.executeDelayed({ removeEntry(key) }, delay)
+ return existed
+ }
+
+ /**
+ * Called whenever the recommendation has been expired or removed by the user. This will remove
+ * the recommendation card entirely from the carousel.
+ */
+ override fun dismissSmartspaceRecommendation(key: String, delay: Long) {
+ if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
+ // If this doesn't match, or we've already invalidated the data, no action needed
+ return
+ }
+
+ if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
+ if (smartspaceMediaData.isActive) {
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId
+ )
+ }
+ foregroundExecutor.executeDelayed(
+ { notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = true) },
+ delay
+ )
+ }
+
+ /** Called when the recommendation card should no longer be visible in QQS or lockscreen */
+ override fun setRecommendationInactive(key: String) {
+ if (!mediaFlags.isPersistentSsCardEnabled()) {
+ Log.e(TAG, "Only persistent recommendation can be inactive!")
+ return
+ }
+ if (DEBUG) Log.d(TAG, "Setting smartspace recommendation inactive")
+
+ if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
+ // If this doesn't match, or we've already invalidated the data, no action needed
+ return
+ }
+
+ smartspaceMediaData = smartspaceMediaData.copy(isActive = false)
+ notifySmartspaceMediaDataLoaded(smartspaceMediaData.targetId, smartspaceMediaData)
+ }
+
+ private fun loadMediaDataInBgForResumption(
+ userId: Int,
+ desc: MediaDescription,
+ resumeAction: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ if (desc.title.isNullOrBlank()) {
+ Log.e(TAG, "Description incomplete")
+ // Delete the placeholder entry
+ mediaEntries.remove(packageName)
+ return
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "adding track for $userId from browser: $desc")
+ }
+
+ val currentEntry = mediaEntries.get(packageName)
+ val appUid = currentEntry?.appUid ?: Process.INVALID_UID
+
+ // Album art
+ var artworkBitmap = desc.iconBitmap
+ if (artworkBitmap == null && desc.iconUri != null) {
+ artworkBitmap = loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName)
+ }
+ val artworkIcon =
+ if (artworkBitmap != null) {
+ Icon.createWithBitmap(artworkBitmap)
+ } else {
+ null
+ }
+
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val isExplicit =
+ desc.extras?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+
+ val progress =
+ if (mediaFlags.isResumeProgressEnabled()) {
+ MediaDataUtils.getDescriptionProgress(desc.extras)
+ } else null
+
+ val mediaAction = getResumeMediaAction(resumeAction)
+ val lastActive = systemClock.elapsedRealtime()
+ val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
+ foregroundExecutor.execute {
+ onMediaDataLoaded(
+ packageName,
+ null,
+ MediaData(
+ userId,
+ true,
+ appName,
+ null,
+ desc.subtitle,
+ desc.title,
+ artworkIcon,
+ listOf(mediaAction),
+ listOf(0),
+ MediaButton(playOrPause = mediaAction),
+ packageName,
+ token,
+ appIntent,
+ device = null,
+ active = false,
+ resumeAction = resumeAction,
+ resumption = true,
+ notificationKey = packageName,
+ hasCheckedForResume = true,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = appUid,
+ isExplicit = isExplicit,
+ resumeProgress = progress,
+ )
+ )
+ }
+ }
+
+ fun loadMediaDataInBg(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?,
+ isNewlyActiveEntry: Boolean = false,
+ ) {
+ val token =
+ sbn.notification.extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION,
+ MediaSession.Token::class.java
+ )
+ if (token == null) {
+ return
+ }
+ val mediaController = mediaControllerFactory.create(token)
+ val metadata = mediaController.metadata
+ val notif: Notification = sbn.notification
+
+ val appInfo =
+ notif.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ )
+ ?: getAppInfoFromPackage(sbn.packageName)
+
+ // App name
+ val appName = getAppName(sbn, appInfo)
+
+ // Song name
+ var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
+ if (song.isNullOrBlank()) {
+ song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
+ }
+ if (song.isNullOrBlank()) {
+ song = HybridGroupManager.resolveTitle(notif)
+ }
+ if (song.isNullOrBlank()) {
+ // For apps that don't include a title, log and add a placeholder
+ song = context.getString(R.string.controls_media_empty_title, appName)
+ try {
+ statusBarManager.logBlankMediaTitle(sbn.packageName, sbn.user.identifier)
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Error reporting blank media title for package ${sbn.packageName}")
+ }
+ }
+
+ // Album art
+ var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
+ if (artworkBitmap == null) {
+ artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
+ }
+ if (artworkBitmap == null) {
+ artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
+ }
+ val artWorkIcon =
+ if (artworkBitmap == null) {
+ notif.getLargeIcon()
+ } else {
+ Icon.createWithBitmap(artworkBitmap)
+ }
+
+ // App Icon
+ val smallIcon = sbn.notification.smallIcon
+
+ // Explicit Indicator
+ var isExplicit = false
+ val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
+ isExplicit =
+ mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+
+ // Artist name
+ var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
+ if (artist.isNullOrBlank()) {
+ artist = HybridGroupManager.resolveText(notif)
+ }
+
+ // Device name (used for remote cast notifications)
+ var device: MediaDeviceData? = null
+ if (isRemoteCastNotification(sbn)) {
+ val extras = sbn.notification.extras
+ val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
+ val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
+ val deviceIntent =
+ extras.getParcelable(
+ Notification.EXTRA_MEDIA_REMOTE_INTENT,
+ PendingIntent::class.java
+ )
+ Log.d(TAG, "$key is RCN for $deviceName")
+
+ if (deviceName != null && deviceIcon > -1) {
+ // Name and icon must be present, but intent may be null
+ val enabled = deviceIntent != null && deviceIntent.isActivity
+ val deviceDrawable =
+ Icon.createWithResource(sbn.packageName, deviceIcon)
+ .loadDrawable(sbn.getPackageContext(context))
+ device =
+ MediaDeviceData(
+ enabled,
+ deviceDrawable,
+ deviceName,
+ deviceIntent,
+ showBroadcastButton = false
+ )
+ }
+ }
+
+ // Control buttons
+ // If flag is enabled and controller has a PlaybackState, create actions from session info
+ // Otherwise, use the notification actions
+ var actionIcons: List<MediaAction> = emptyList()
+ var actionsToShowCollapsed: List<Int> = emptyList()
+ val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
+ if (semanticActions == null) {
+ val actions = createActionsFromNotification(sbn)
+ actionIcons = actions.first
+ actionsToShowCollapsed = actions.second
+ }
+
+ val playbackLocation =
+ if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
+ else if (
+ mediaController.playbackInfo?.playbackType ==
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
+ )
+ MediaData.PLAYBACK_LOCAL
+ else MediaData.PLAYBACK_CAST_LOCAL
+ val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
+
+ val currentEntry = mediaEntries.get(key)
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val appUid = appInfo?.uid ?: Process.INVALID_UID
+
+ if (isNewlyActiveEntry) {
+ logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId)
+ logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
+ } else if (playbackLocation != currentEntry?.playbackLocation) {
+ logger.logPlaybackLocationChange(appUid, sbn.packageName, instanceId, playbackLocation)
+ }
+
+ val lastActive = systemClock.elapsedRealtime()
+ val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
+ foregroundExecutor.execute {
+ val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
+ val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
+ val active = mediaEntries[key]?.active ?: true
+ onMediaDataLoaded(
+ key,
+ oldKey,
+ MediaData(
+ sbn.normalizedUserId,
+ true,
+ appName,
+ smallIcon,
+ artist,
+ song,
+ artWorkIcon,
+ actionIcons,
+ actionsToShowCollapsed,
+ semanticActions,
+ sbn.packageName,
+ token,
+ notif.contentIntent,
+ device,
+ active,
+ resumeAction = resumeAction,
+ playbackLocation = playbackLocation,
+ notificationKey = key,
+ hasCheckedForResume = hasCheckedForResume,
+ isPlaying = isPlaying,
+ isClearable = !sbn.isOngoing,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = appUid,
+ isExplicit = isExplicit,
+ )
+ )
+ }
+ }
+
+ private fun logSingleVsMultipleMediaAdded(
+ appUid: Int,
+ packageName: String,
+ instanceId: InstanceId
+ ) {
+ if (mediaEntries.size == 1) {
+ logger.logSingleMediaPlayerInCarousel(appUid, packageName, instanceId)
+ } else if (mediaEntries.size == 2) {
+ // Since this method is only called when there is a new media session added.
+ // logging needed once there is more than one media session in carousel.
+ logger.logMultipleMediaPlayersInCarousel(appUid, packageName, instanceId)
+ }
+ }
+
+ private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
+ try {
+ return context.packageManager.getApplicationInfo(packageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app info for $packageName", e)
+ }
+ return null
+ }
+
+ private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
+ val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
+ if (name != null) {
+ return name
+ }
+
+ return if (appInfo != null) {
+ context.packageManager.getApplicationLabel(appInfo).toString()
+ } else {
+ sbn.packageName
+ }
+ }
+
+ /** Generate action buttons based on notification actions */
+ private fun createActionsFromNotification(
+ sbn: StatusBarNotification
+ ): Pair<List<MediaAction>, List<Int>> {
+ val notif = sbn.notification
+ val actionIcons: MutableList<MediaAction> = ArrayList()
+ val actions = notif.actions
+ var actionsToShowCollapsed =
+ notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList()
+ ?: mutableListOf()
+ if (actionsToShowCollapsed.size > MAX_COMPACT_ACTIONS) {
+ Log.e(
+ TAG,
+ "Too many compact actions for ${sbn.key}," +
+ "limiting to first $MAX_COMPACT_ACTIONS"
+ )
+ actionsToShowCollapsed = actionsToShowCollapsed.subList(0, MAX_COMPACT_ACTIONS)
+ }
+
+ if (actions != null) {
+ for ((index, action) in actions.withIndex()) {
+ if (index == MAX_NOTIFICATION_ACTIONS) {
+ Log.w(
+ TAG,
+ "Too many notification actions for ${sbn.key}," +
+ " limiting to first $MAX_NOTIFICATION_ACTIONS"
+ )
+ break
+ }
+ if (action.getIcon() == null) {
+ if (DEBUG) Log.i(TAG, "No icon for action $index ${action.title}")
+ actionsToShowCollapsed.remove(index)
+ continue
+ }
+ val runnable =
+ if (action.actionIntent != null) {
+ Runnable {
+ if (action.actionIntent.isActivity) {
+ activityStarter.startPendingIntentDismissingKeyguard(
+ action.actionIntent
+ )
+ } else if (action.isAuthenticationRequired()) {
+ activityStarter.dismissKeyguardThenExecute(
+ {
+ var result = sendPendingIntent(action.actionIntent)
+ result
+ },
+ {},
+ true
+ )
+ } else {
+ sendPendingIntent(action.actionIntent)
+ }
+ }
+ } else {
+ null
+ }
+ val mediaActionIcon =
+ if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
+ Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
+ } else {
+ action.getIcon()
+ }
+ .setTint(themeText)
+ .loadDrawable(context)
+ val mediaAction = MediaAction(mediaActionIcon, runnable, action.title, null)
+ actionIcons.add(mediaAction)
+ }
+ }
+ return Pair(actionIcons, actionsToShowCollapsed)
+ }
+
+ /**
+ * Generates action button info for this media session based on the PlaybackState
+ *
+ * @param packageName Package name for the media app
+ * @param controller MediaController for the current session
+ * @return a Pair consisting of a list of media actions, and a list of ints representing which
+ *
+ * ```
+ * of those actions should be shown in the compact player
+ * ```
+ */
+ private fun createActionsFromState(
+ packageName: String,
+ controller: MediaController,
+ user: UserHandle
+ ): MediaButton? {
+ val state = controller.playbackState
+ if (state == null || !mediaFlags.areMediaSessionActionsEnabled(packageName, user)) {
+ return null
+ }
+
+ // First, check for standard actions
+ val playOrPause =
+ if (isConnectingState(state.state)) {
+ // Spinner needs to be animating to render anything. Start it here.
+ val drawable =
+ context.getDrawable(com.android.internal.R.drawable.progress_small_material)
+ (drawable as Animatable).start()
+ MediaAction(
+ drawable,
+ null, // no action to perform when clicked
+ context.getString(R.string.controls_media_button_connecting),
+ context.getDrawable(R.drawable.ic_media_connecting_container),
+ // Specify a rebind id to prevent the spinner from restarting on later binds.
+ com.android.internal.R.drawable.progress_small_material
+ )
+ } else if (isPlayingState(state.state)) {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
+ } else {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
+ }
+ val prevButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_PREVIOUS)
+ val nextButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_NEXT)
+
+ // Then, create a way to build any custom actions that will be needed
+ val customActions =
+ state.customActions
+ .asSequence()
+ .filterNotNull()
+ .map { getCustomAction(state, packageName, controller, it) }
+ .iterator()
+ fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
+
+ // Finally, assign the remaining button slots: play/pause A B C D
+ // A = previous, else custom action (if not reserved)
+ // B = next, else custom action (if not reserved)
+ // C and D are always custom actions
+ val reservePrev =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ ) == true
+ val reserveNext =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ ) == true
+
+ val prevOrCustom =
+ if (prevButton != null) {
+ prevButton
+ } else if (!reservePrev) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ val nextOrCustom =
+ if (nextButton != null) {
+ nextButton
+ } else if (!reserveNext) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ return MediaButton(
+ playOrPause,
+ nextOrCustom,
+ prevOrCustom,
+ nextCustomAction(),
+ nextCustomAction(),
+ reserveNext,
+ reservePrev
+ )
+ }
+
+ /**
+ * Create a [MediaAction] for a given action and media session
+ *
+ * @param controller MediaController for the session
+ * @param stateActions The actions included with the session's [PlaybackState]
+ * @param action A [PlaybackState.Actions] value representing what action to generate. One of:
+ * ```
+ * [PlaybackState.ACTION_PLAY]
+ * [PlaybackState.ACTION_PAUSE]
+ * [PlaybackState.ACTION_SKIP_TO_PREVIOUS]
+ * [PlaybackState.ACTION_SKIP_TO_NEXT]
+ * @return
+ * ```
+ *
+ * A [MediaAction] with correct values set, or null if the state doesn't support it
+ */
+ private fun getStandardAction(
+ controller: MediaController,
+ stateActions: Long,
+ @PlaybackState.Actions action: Long
+ ): MediaAction? {
+ if (!includesAction(stateActions, action)) {
+ return null
+ }
+
+ return when (action) {
+ PlaybackState.ACTION_PLAY -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_play),
+ { controller.transportControls.play() },
+ context.getString(R.string.controls_media_button_play),
+ context.getDrawable(R.drawable.ic_media_play_container)
+ )
+ }
+ PlaybackState.ACTION_PAUSE -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_pause),
+ { controller.transportControls.pause() },
+ context.getString(R.string.controls_media_button_pause),
+ context.getDrawable(R.drawable.ic_media_pause_container)
+ )
+ }
+ PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_prev),
+ { controller.transportControls.skipToPrevious() },
+ context.getString(R.string.controls_media_button_prev),
+ null
+ )
+ }
+ PlaybackState.ACTION_SKIP_TO_NEXT -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_next),
+ { controller.transportControls.skipToNext() },
+ context.getString(R.string.controls_media_button_next),
+ null
+ )
+ }
+ else -> null
+ }
+ }
+
+ /** Check whether the actions from a [PlaybackState] include a specific action */
+ private fun includesAction(stateActions: Long, @PlaybackState.Actions action: Long): Boolean {
+ if (
+ (action == PlaybackState.ACTION_PLAY || action == PlaybackState.ACTION_PAUSE) &&
+ (stateActions and PlaybackState.ACTION_PLAY_PAUSE > 0L)
+ ) {
+ return true
+ }
+ return (stateActions and action != 0L)
+ }
+
+ /** Get a [MediaAction] representing a [PlaybackState.CustomAction] */
+ private fun getCustomAction(
+ state: PlaybackState,
+ packageName: String,
+ controller: MediaController,
+ customAction: PlaybackState.CustomAction
+ ): MediaAction {
+ return MediaAction(
+ Icon.createWithResource(packageName, customAction.icon).loadDrawable(context),
+ { controller.transportControls.sendCustomAction(customAction, customAction.extras) },
+ customAction.name,
+ null
+ )
+ }
+
+ /** Load a bitmap from the various Art metadata URIs */
+ private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
+ for (uri in ART_URIS) {
+ val uriString = metadata.getString(uri)
+ if (!TextUtils.isEmpty(uriString)) {
+ val albumArt = loadBitmapFromUri(Uri.parse(uriString))
+ if (albumArt != null) {
+ if (DEBUG) Log.d(TAG, "loaded art from $uri")
+ return albumArt
+ }
+ }
+ }
+ return null
+ }
+
+ private fun sendPendingIntent(intent: PendingIntent): Boolean {
+ return try {
+ val options = BroadcastOptions.makeBasic()
+ options.setInteractive(true)
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
+ intent.send(options.toBundle())
+ true
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ false
+ }
+ }
+
+ /** Returns a bitmap if the user can access the given URI, else null */
+ private fun loadBitmapFromUriForUser(
+ uri: Uri,
+ userId: Int,
+ appUid: Int,
+ packageName: String,
+ ): Bitmap? {
+ try {
+ val ugm = UriGrantsManager.getService()
+ ugm.checkGrantUriPermission_ignoreNonSystem(
+ appUid,
+ packageName,
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ ContentProvider.getUserIdFromUri(uri, userId)
+ )
+ return loadBitmapFromUri(uri)
+ } catch (e: SecurityException) {
+ Log.e(TAG, "Failed to get URI permission: $e")
+ }
+ return null
+ }
+
+ /**
+ * Load a bitmap from a URI
+ *
+ * @param uri the uri to load
+ * @return bitmap, or null if couldn't be loaded
+ */
+ private fun loadBitmapFromUri(uri: Uri): Bitmap? {
+ // ImageDecoder requires a scheme of the following types
+ if (uri.scheme == null) {
+ return null
+ }
+
+ if (
+ !uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_FILE)
+ ) {
+ return null
+ }
+
+ val source = ImageDecoder.createSource(context.contentResolver, uri)
+ return try {
+ ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
+ val width = info.size.width
+ val height = info.size.height
+ val scale =
+ MediaDataUtils.getScaleFactor(
+ APair(width, height),
+ APair(artworkWidth, artworkHeight)
+ )
+
+ // Downscale if needed
+ if (scale != 0f && scale < 1) {
+ decoder.setTargetSize((scale * width).toInt(), (scale * height).toInt())
+ }
+ decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
+ }
+ } catch (e: IOException) {
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ }
+ }
+
+ private fun getResumeMediaAction(action: Runnable): MediaAction {
+ return MediaAction(
+ Icon.createWithResource(context, R.drawable.ic_media_play)
+ .setTint(themeText)
+ .loadDrawable(context),
+ action,
+ context.getString(R.string.controls_media_resume),
+ context.getDrawable(R.drawable.ic_media_play_container)
+ )
+ }
+
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) =
+ traceSection("MediaDataManager#onMediaDataLoaded") {
+ Assert.isMainThread()
+ if (mediaEntries.containsKey(key)) {
+ // Otherwise this was removed already
+ mediaEntries.put(key, data)
+ notifyMediaDataLoaded(key, oldKey, data)
+ }
+ }
+
+ override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
+ if (!allowMediaRecommendations) {
+ if (DEBUG) Log.d(TAG, "Smartspace recommendation is disabled in Settings.")
+ return
+ }
+
+ val mediaTargets = targets.filterIsInstance<SmartspaceTarget>()
+ when (mediaTargets.size) {
+ 0 -> {
+ if (!smartspaceMediaData.isActive) {
+ return
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Set Smartspace media to be inactive for the data update")
+ }
+ if (mediaFlags.isPersistentSsCardEnabled()) {
+ // Smartspace uses this signal to hide the card (e.g. when it expires or user
+ // disconnects headphones), so treat as setting inactive when flag is on
+ smartspaceMediaData = smartspaceMediaData.copy(isActive = false)
+ notifySmartspaceMediaDataLoaded(
+ smartspaceMediaData.targetId,
+ smartspaceMediaData,
+ )
+ } else {
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId,
+ )
+ notifySmartspaceMediaDataRemoved(
+ smartspaceMediaData.targetId,
+ immediately = false,
+ )
+ }
+ }
+ 1 -> {
+ val newMediaTarget = mediaTargets.get(0)
+ if (smartspaceMediaData.targetId == newMediaTarget.smartspaceTargetId) {
+ // The same Smartspace updates can be received. Skip the duplicate updates.
+ return
+ }
+ if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.")
+ smartspaceMediaData = toSmartspaceMediaData(newMediaTarget)
+ notifySmartspaceMediaDataLoaded(smartspaceMediaData.targetId, smartspaceMediaData)
+ }
+ else -> {
+ // There should NOT be more than 1 Smartspace media update. When it happens, it
+ // indicates a bad state or an error. Reset the status accordingly.
+ Log.wtf(TAG, "More than 1 Smartspace Media Update. Resetting the status...")
+ notifySmartspaceMediaDataRemoved(
+ smartspaceMediaData.targetId,
+ immediately = false,
+ )
+ smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
+ }
+ }
+ }
+
+ override fun onNotificationRemoved(key: String) {
+ Assert.isMainThread()
+ val removed = mediaEntries.remove(key) ?: return
+ if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ } else if (isAbleToResume(removed)) {
+ convertToResumePlayer(key, removed)
+ } else if (mediaFlags.isRetainingPlayersEnabled()) {
+ handlePossibleRemoval(key, removed, notificationRemoved = true)
+ } else {
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ }
+ }
+
+ private fun onSessionDestroyed(key: String) {
+ if (DEBUG) Log.d(TAG, "session destroyed for $key")
+ val entry = mediaEntries.remove(key) ?: return
+ // Clear token since the session is no longer valid
+ val updated = entry.copy(token = null)
+ handlePossibleRemoval(key, updated)
+ }
+
+ private fun isAbleToResume(data: MediaData): Boolean {
+ val isEligibleForResume =
+ data.isLocalSession() ||
+ (mediaFlags.isRemoteResumeAllowed() &&
+ data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
+ return useMediaResumption && data.resumeAction != null && isEligibleForResume
+ }
+
+ /**
+ * Convert to resume state if the player is no longer valid and active, then notify listeners
+ * that the data was updated. Does not convert to resume state if the player is still valid, or
+ * if it was removed before becoming inactive. (Assumes that [removed] was removed from
+ * [mediaEntries] before this function was called)
+ */
+ private fun handlePossibleRemoval(
+ key: String,
+ removed: MediaData,
+ notificationRemoved: Boolean = false
+ ) {
+ val hasSession = removed.token != null
+ if (hasSession && removed.semanticActions != null) {
+ // The app was using session actions, and the session is still valid: keep player
+ if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
+ mediaEntries.put(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (!notificationRemoved && removed.semanticActions == null) {
+ // The app was using notification actions, and notif wasn't removed yet: keep player
+ if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
+ mediaEntries.put(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (removed.active && !isAbleToResume(removed)) {
+ // This player was still active - it didn't last long enough to time out,
+ // and its app doesn't normally support resume: remove
+ if (DEBUG) Log.d(TAG, "Removing still-active player $key")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
+ // Convert to resume
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Notification ($notificationRemoved) and/or session " +
+ "($hasSession) gone for inactive player $key"
+ )
+ }
+ convertToResumePlayer(key, removed)
+ } else {
+ // Retaining players flag is off and app doesn't support resume: remove player.
+ if (DEBUG) Log.d(TAG, "Removing player $key")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ }
+ }
+
+ /** Set the given [MediaData] as a resume state player and notify listeners */
+ private fun convertToResumePlayer(key: String, data: MediaData) {
+ if (DEBUG) Log.d(TAG, "Converting $key to resume")
+ // Resumption controls must have a title.
+ if (data.song.isNullOrBlank()) {
+ Log.e(TAG, "Description incomplete")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
+ return
+ }
+ // Move to resume key (aka package name) if that key doesn't already exist.
+ val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) }
+ val actions = resumeAction?.let { listOf(resumeAction) } ?: emptyList()
+ val launcherIntent =
+ context.packageManager.getLaunchIntentForPackage(data.packageName)?.let {
+ PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE)
+ }
+ val lastActive =
+ if (data.active) {
+ systemClock.elapsedRealtime()
+ } else {
+ data.lastActive
+ }
+ val updated =
+ data.copy(
+ token = null,
+ actions = actions,
+ semanticActions = MediaButton(playOrPause = resumeAction),
+ actionsToShowInCompact = listOf(0),
+ active = false,
+ resumption = true,
+ isPlaying = false,
+ isClearable = true,
+ clickIntent = launcherIntent,
+ lastActive = lastActive,
+ )
+ val pkg = data.packageName
+ val migrate = mediaEntries.put(pkg, updated) == null
+ // Notify listeners of "new" controls when migrating or removed and update when not
+ Log.d(TAG, "migrating? $migrate from $key -> $pkg")
+ if (migrate) {
+ notifyMediaDataLoaded(key = pkg, oldKey = key, info = updated)
+ } else {
+ // Since packageName is used for the key of the resumption controls, it is
+ // possible that another notification has already been reused for the resumption
+ // controls of this package. In this case, rather than renaming this player as
+ // packageName, just remove it and then send a update to the existing resumption
+ // controls.
+ notifyMediaDataRemoved(key)
+ notifyMediaDataLoaded(key = pkg, oldKey = pkg, info = updated)
+ }
+ logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
+
+ // Limit total number of resume controls
+ val resumeEntries = mediaEntries.filter { (key, data) -> data.resumption }
+ val numResume = resumeEntries.size
+ if (numResume > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) {
+ resumeEntries
+ .toList()
+ .sortedBy { (key, data) -> data.lastActive }
+ .subList(0, numResume - ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS)
+ .forEach { (key, data) ->
+ Log.d(TAG, "Removing excess control $key")
+ mediaEntries.remove(key)
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
+ }
+ }
+ }
+
+ override fun setMediaResumptionEnabled(isEnabled: Boolean) {
+ if (useMediaResumption == isEnabled) {
+ return
+ }
+
+ useMediaResumption = isEnabled
+
+ if (!useMediaResumption) {
+ // Remove any existing resume controls
+ val filtered = mediaEntries.filter { !it.value.active }
+ filtered.forEach {
+ mediaEntries.remove(it.key)
+ notifyMediaDataRemoved(it.key)
+ logger.logMediaRemoved(it.value.appUid, it.value.packageName, it.value.instanceId)
+ }
+ }
+ }
+
+ /** Invoked when the user has dismissed the media carousel */
+ override fun onSwipeToDismiss() = mediaDataFilter.onSwipeToDismiss()
+
+ /** Are there any media notifications active, including the recommendations? */
+ override fun hasActiveMediaOrRecommendation() = mediaDataFilter.hasActiveMediaOrRecommendation()
+
+ /**
+ * Are there any media entries we should display, including the recommendations?
+ * - If resumption is enabled, this will include inactive players
+ * - If resumption is disabled, we only want to show active players
+ */
+ override fun hasAnyMediaOrRecommendation() = mediaDataFilter.hasAnyMediaOrRecommendation()
+
+ /** Are there any resume media notifications active, excluding the recommendations? */
+ override fun hasActiveMedia() = mediaDataFilter.hasActiveMedia()
+
+ /**
+ * Are there any resume media notifications active, excluding the recommendations?
+ * - If resumption is enabled, this will include inactive players
+ * - If resumption is disabled, we only want to show active players
+ */
+ override fun hasAnyMedia() = mediaDataFilter.hasAnyMedia()
+ override fun isRecommendationActive() = smartspaceMediaData.isActive
+
+ /**
+ * Converts the pass-in SmartspaceTarget to SmartspaceMediaData
+ *
+ * @return An empty SmartspaceMediaData with the valid target Id is returned if the
+ * SmartspaceTarget's data is invalid.
+ */
+ private fun toSmartspaceMediaData(target: SmartspaceTarget): SmartspaceMediaData {
+ val baseAction: SmartspaceAction? = target.baseAction
+ val dismissIntent =
+ baseAction?.extras?.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent?
+
+ val isActive =
+ when {
+ !mediaFlags.isPersistentSsCardEnabled() -> true
+ baseAction == null -> true
+ else -> {
+ val triggerSource = baseAction.extras?.getString(EXTRA_KEY_TRIGGER_SOURCE)
+ triggerSource != EXTRA_VALUE_TRIGGER_PERIODIC
+ }
+ }
+
+ packageName(target)?.let {
+ return SmartspaceMediaData(
+ targetId = target.smartspaceTargetId,
+ isActive = isActive,
+ packageName = it,
+ cardAction = target.baseAction,
+ recommendations = target.iconGrid,
+ dismissIntent = dismissIntent,
+ headphoneConnectionTimeMillis = target.creationTimeMillis,
+ instanceId = logger.getNewInstanceId(),
+ expiryTimeMs = target.expiryTimeMillis,
+ )
+ }
+ return EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = target.smartspaceTargetId,
+ isActive = isActive,
+ dismissIntent = dismissIntent,
+ headphoneConnectionTimeMillis = target.creationTimeMillis,
+ instanceId = logger.getNewInstanceId(),
+ expiryTimeMs = target.expiryTimeMillis,
+ )
+ }
+
+ private fun packageName(target: SmartspaceTarget): String? {
+ val recommendationList = target.iconGrid
+ if (recommendationList == null || recommendationList.isEmpty()) {
+ Log.w(TAG, "Empty or null media recommendation list.")
+ return null
+ }
+ for (recommendation in recommendationList) {
+ val extras = recommendation.extras
+ extras?.let {
+ it.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME)?.let { packageName ->
+ return packageName
+ }
+ }
+ }
+ Log.w(TAG, "No valid package name is provided.")
+ return null
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("internalListeners: $internalListeners")
+ println("externalListeners: ${mediaDataFilter.listeners}")
+ println("mediaEntries: $mediaEntries")
+ println("useMediaResumption: $useMediaResumption")
+ println("allowMediaRecommendations: $allowMediaRecommendations")
+ }
+ mediaDeviceManager.dump(pw)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
similarity index 76%
copy from packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt
copy to packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
index bc539ef..a65db35 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -24,6 +24,7 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
@@ -36,7 +37,6 @@
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import javax.inject.Inject
-import kotlin.collections.LinkedHashMap
private const val TAG = "MediaDataFilter"
private const val DEBUG = true
@@ -46,14 +46,6 @@
private const val RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY = "resumable_media_max_age_seconds"
/**
- * Maximum age of a media control to re-activate on smartspace signal. If there is no media control
- * available within this time window, smartspace recommendations will be shown instead.
- */
-@VisibleForTesting
-internal val SMARTSPACE_MAX_AGE =
- SystemProperties.getLong("debug.sysui.smartspace_max_age", TimeUnit.MINUTES.toMillis(30))
-
-/**
* Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user
* switches (removing entries for the previous user, adding back entries for the current user). Also
* filters out smartspace updates in favor of local recent media, when avaialble.
@@ -61,28 +53,23 @@
* This is added at the end of the pipeline since we may still need to handle callbacks from
* background users (e.g. timeouts).
*/
-class MediaDataFilter
+class MediaDataFilterImpl
@Inject
constructor(
private val context: Context,
- private val userTracker: UserTracker,
+ userTracker: UserTracker,
private val broadcastSender: BroadcastSender,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor,
private val systemClock: SystemClock,
private val logger: MediaUiEventLogger,
private val mediaFlags: MediaFlags,
+ private val mediaFilterRepository: MediaFilterRepository,
) : MediaDataManager.Listener {
private val _listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
- internal val listeners: Set<MediaDataManager.Listener>
+ val listeners: Set<MediaDataManager.Listener>
get() = _listeners.toSet()
- internal lateinit var mediaDataManager: MediaDataManager
-
- private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
- // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
- private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
- private var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
- private var reactivatedKey: String? = null
+ lateinit var mediaDataManager: MediaDataManager
// Ensure the field (and associated reference) isn't removed during optimization.
@KeepForWeakReference
@@ -110,9 +97,9 @@
isSsReactivated: Boolean
) {
if (oldKey != null && oldKey != key) {
- allEntries.remove(oldKey)
+ mediaFilterRepository.removeMediaEntry(oldKey)
}
- allEntries.put(key, data)
+ mediaFilterRepository.addMediaEntry(key, data)
if (
!lockscreenUserManager.isCurrentProfile(data.userId) ||
@@ -122,9 +109,9 @@
}
if (oldKey != null && oldKey != key) {
- userEntries.remove(oldKey)
+ mediaFilterRepository.removeSelectedUserMediaEntry(oldKey)
}
- userEntries.put(key, data)
+ mediaFilterRepository.addSelectedUserMediaEntry(key, data)
// Notify listeners
listeners.forEach { it.onMediaDataLoaded(key, oldKey, data) }
@@ -144,10 +131,12 @@
// Override the pass-in value here, as the order of Smartspace card is only determined here.
var shouldPrioritizeMutable = false
- smartspaceMediaData = data
+ mediaFilterRepository.setRecommendation(data)
// Before forwarding the smartspace target, first check if we have recently inactive media
- val sorted = userEntries.toSortedMap(compareBy { userEntries.get(it)?.lastActive ?: -1 })
+ val selectedUserEntries = mediaFilterRepository.selectedUserEntries.value
+ val sorted =
+ selectedUserEntries.toSortedMap(compareBy { selectedUserEntries[it]?.lastActive ?: -1 })
val timeSinceActive = timeSinceActiveForMostRecentMedia(sorted)
var smartspaceMaxAgeMillis = SMARTSPACE_MAX_AGE
data.cardAction?.extras?.let {
@@ -162,7 +151,10 @@
val shouldTriggerResume =
data.cardAction?.extras?.getBoolean(EXTRA_KEY_TRIGGER_RESUME, true) ?: true
val shouldReactivate =
- shouldTriggerResume && !hasActiveMedia() && hasAnyMedia() && data.isActive
+ shouldTriggerResume &&
+ !selectedUserEntries.any { it.value.active } &&
+ selectedUserEntries.isNotEmpty() &&
+ data.isActive
if (timeSinceActive < smartspaceMaxAgeMillis) {
// It could happen there are existing active media resume cards, then we don't need to
@@ -171,8 +163,8 @@
val lastActiveKey = sorted.lastKey() // most recently active
// Notify listeners to consider this media active
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
- reactivatedKey = lastActiveKey
- val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
+ mediaFilterRepository.setReactivatedKey(lastActiveKey)
+ val mediaData = sorted[lastActiveKey]!!.copy(active = true)
logger.logRecommendationActivated(
mediaData.appUid,
mediaData.packageName,
@@ -199,6 +191,7 @@
Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
return
}
+ val smartspaceMediaData = mediaFilterRepository.smartspaceMediaData.value
logger.logRecommendationAdded(
smartspaceMediaData.packageName,
smartspaceMediaData.instanceId
@@ -207,8 +200,8 @@
}
override fun onMediaDataRemoved(key: String) {
- allEntries.remove(key)
- userEntries.remove(key)?.let {
+ mediaFilterRepository.removeMediaEntry(key)
+ mediaFilterRepository.removeSelectedUserMediaEntry(key)?.let {
// Only notify listeners if something actually changed
listeners.forEach { it.onMediaDataRemoved(key) }
}
@@ -216,24 +209,26 @@
override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
// First check if we had reactivated media instead of forwarding smartspace
- reactivatedKey?.let {
+ mediaFilterRepository.reactivatedKey.value?.let {
val lastActiveKey = it
- reactivatedKey = null
+ mediaFilterRepository.setReactivatedKey(null)
Log.d(TAG, "expiring reactivated key $lastActiveKey")
// Notify listeners to update with actual active value
- userEntries.get(lastActiveKey)?.let { mediaData ->
- listeners.forEach {
- it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData, immediately)
+ mediaFilterRepository.selectedUserEntries.value[lastActiveKey]?.let { mediaData ->
+ listeners.forEach { listener ->
+ listener.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData, immediately)
}
}
}
+ val smartspaceMediaData = mediaFilterRepository.smartspaceMediaData.value
if (smartspaceMediaData.isActive) {
- smartspaceMediaData =
+ mediaFilterRepository.setRecommendation(
EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId,
instanceId = smartspaceMediaData.instanceId
)
+ )
}
listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
}
@@ -241,11 +236,11 @@
@VisibleForTesting
internal fun handleProfileChanged() {
// TODO(b/317221348) re-add media removed when profile is available.
- allEntries.forEach { (key, data) ->
+ mediaFilterRepository.allUserEntries.value.forEach { (key, data) ->
if (!lockscreenUserManager.isProfileAvailable(data.userId)) {
// Only remove media when the profile is unavailable.
if (DEBUG) Log.d(TAG, "Removing $key after profile change")
- userEntries.remove(key, data)
+ mediaFilterRepository.removeSelectedUserMediaEntry(key, data)
listeners.forEach { listener -> listener.onMediaDataRemoved(key) }
}
}
@@ -255,19 +250,19 @@
internal fun handleUserSwitched() {
// If the user changes, remove all current MediaData objects and inform listeners
val listenersCopy = listeners
- val keyCopy = userEntries.keys.toMutableList()
+ val keyCopy = mediaFilterRepository.selectedUserEntries.value.keys.toMutableList()
// Clear the list first, to make sure callbacks from listeners if we have any entries
// are up to date
- userEntries.clear()
+ mediaFilterRepository.clearSelectedUserMedia()
keyCopy.forEach {
if (DEBUG) Log.d(TAG, "Removing $it after user change")
listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it) }
}
- allEntries.forEach { (key, data) ->
+ mediaFilterRepository.allUserEntries.value.forEach { (key, data) ->
if (lockscreenUserManager.isCurrentProfile(data.userId)) {
if (DEBUG) Log.d(TAG, "Re-adding $key after user change")
- userEntries.put(key, data)
+ mediaFilterRepository.addSelectedUserMediaEntry(key, data)
listenersCopy.forEach { listener -> listener.onMediaDataLoaded(key, null, data) }
}
}
@@ -276,11 +271,12 @@
/** Invoked when the user has dismissed the media carousel */
fun onSwipeToDismiss() {
if (DEBUG) Log.d(TAG, "Media carousel swiped away")
- val mediaKeys = userEntries.keys.toSet()
+ val mediaKeys = mediaFilterRepository.selectedUserEntries.value.keys.toSet()
mediaKeys.forEach {
// Force updates to listeners, needed for re-activated card
- mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true)
+ mediaDataManager.setInactive(it, timedOut = true, forceUpdate = true)
}
+ val smartspaceMediaData = mediaFilterRepository.smartspaceMediaData.value
if (smartspaceMediaData.isActive) {
val dismissIntent = smartspaceMediaData.dismissIntent
if (dismissIntent == null) {
@@ -298,14 +294,15 @@
}
if (mediaFlags.isPersistentSsCardEnabled()) {
- smartspaceMediaData = smartspaceMediaData.copy(isActive = false)
+ mediaFilterRepository.setRecommendation(smartspaceMediaData.copy(isActive = false))
mediaDataManager.setRecommendationInactive(smartspaceMediaData.targetId)
} else {
- smartspaceMediaData =
+ mediaFilterRepository.setRecommendation(
EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId,
instanceId = smartspaceMediaData.instanceId,
)
+ )
mediaDataManager.dismissSmartspaceRecommendation(
smartspaceMediaData.targetId,
delay = 0L,
@@ -314,29 +311,6 @@
}
}
- /** Are there any active media entries, including the recommendation? */
- fun hasActiveMediaOrRecommendation() =
- userEntries.any { it.value.active } ||
- (smartspaceMediaData.isActive &&
- (smartspaceMediaData.isValid() || reactivatedKey != null))
-
- /** Are there any media entries we should display? */
- fun hasAnyMediaOrRecommendation(): Boolean {
- val hasSmartspace =
- if (mediaFlags.isPersistentSsCardEnabled()) {
- smartspaceMediaData.isValid()
- } else {
- smartspaceMediaData.isActive && smartspaceMediaData.isValid()
- }
- return userEntries.isNotEmpty() || hasSmartspace
- }
-
- /** Are there any media notifications active (excluding the recommendation)? */
- fun hasActiveMedia() = userEntries.any { it.value.active }
-
- /** Are there any media entries we should display (excluding the recommendation)? */
- fun hasAnyMedia() = userEntries.isNotEmpty()
-
/** Add a listener for filtered [MediaData] changes */
fun addListener(listener: MediaDataManager.Listener) = _listeners.add(listener)
@@ -346,7 +320,7 @@
/**
* Return the time since last active for the most-recent media.
*
- * @param sortedEntries userEntries sorted from the earliest to the most-recent.
+ * @param sortedEntries selectedUserEntries sorted from the earliest to the most-recent.
* @return The duration in milliseconds from the most-recent media's last active timestamp to
* the present. MAX_VALUE will be returned if there is no media.
*/
@@ -359,6 +333,21 @@
val now = systemClock.elapsedRealtime()
val lastActiveKey = sortedEntries.lastKey() // most recently active
- return sortedEntries.get(lastActiveKey)?.let { now - it.lastActive } ?: Long.MAX_VALUE
+ return sortedEntries[lastActiveKey]?.let { now - it.lastActive } ?: Long.MAX_VALUE
+ }
+
+ companion object {
+ /**
+ * Maximum age of a media control to re-activate on smartspace signal. If there is no media
+ * control available within this time window, smartspace recommendations will be shown
+ * instead.
+ */
+ @VisibleForTesting
+ internal val SMARTSPACE_MAX_AGE: Long
+ get() =
+ SystemProperties.getLong(
+ "debug.sysui.smartspace_max_age",
+ TimeUnit.MINUTES.toMillis(30)
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
index 865c49e..2b1070c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -16,424 +16,39 @@
package com.android.systemui.media.controls.domain.pipeline
-import android.annotation.SuppressLint
-import android.app.ActivityOptions
-import android.app.BroadcastOptions
-import android.app.Notification
-import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
-import android.app.StatusBarManager
-import android.app.UriGrantsManager
-import android.app.smartspace.SmartspaceAction
-import android.app.smartspace.SmartspaceConfig
-import android.app.smartspace.SmartspaceManager
-import android.app.smartspace.SmartspaceSession
-import android.app.smartspace.SmartspaceTarget
-import android.content.BroadcastReceiver
-import android.content.ContentProvider
-import android.content.ContentResolver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
-import android.graphics.Bitmap
-import android.graphics.ImageDecoder
-import android.graphics.drawable.Animatable
-import android.graphics.drawable.Icon
import android.media.MediaDescription
-import android.media.MediaMetadata
-import android.media.session.MediaController
import android.media.session.MediaSession
-import android.media.session.PlaybackState
-import android.net.Uri
-import android.os.Parcelable
-import android.os.Process
-import android.os.UserHandle
-import android.provider.Settings
import android.service.notification.StatusBarNotification
-import android.support.v4.media.MediaMetadataCompat
-import android.text.TextUtils
-import android.util.Log
-import android.util.Pair as APair
-import androidx.media.utils.MediaConstants
-import com.android.app.tracing.traceSection
-import com.android.internal.annotations.Keep
-import com.android.internal.logging.InstanceId
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.Dumpable
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.controls.domain.resume.MediaResumeListener
-import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
-import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
-import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
-import com.android.systemui.media.controls.shared.model.MediaAction
-import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
-import com.android.systemui.media.controls.shared.model.MediaDeviceData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
-import com.android.systemui.media.controls.ui.view.MediaViewHolder
-import com.android.systemui.media.controls.util.MediaControllerFactory
-import com.android.systemui.media.controls.util.MediaDataUtils
-import com.android.systemui.media.controls.util.MediaFlags
-import com.android.systemui.media.controls.util.MediaUiEventLogger
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
-import com.android.systemui.statusbar.notification.row.HybridGroupManager
-import com.android.systemui.tuner.TunerService
-import com.android.systemui.util.Assert
-import com.android.systemui.util.Utils
-import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.concurrency.ThreadFactory
-import com.android.systemui.util.time.SystemClock
-import java.io.IOException
-import java.io.PrintWriter
-import java.util.concurrent.Executor
-import javax.inject.Inject
-// URI fields to try loading album art from
-private val ART_URIS =
- arrayOf(
- MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
- MediaMetadata.METADATA_KEY_ART_URI,
- MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
- )
+/** Facilitates management and loading of Media Data, ready for binding. */
+interface MediaDataManager {
-private const val TAG = "MediaDataManager"
-private const val DEBUG = true
-private const val EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY = "dismiss_intent"
+ /** Add a listener for changes in this class */
+ fun addListener(listener: Listener)
-private val LOADING =
- MediaData(
- userId = -1,
- initialized = false,
- app = null,
- appIcon = null,
- artist = null,
- song = null,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
- packageName = "INVALID",
- token = null,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null,
- instanceId = InstanceId.fakeInstanceId(-1),
- appUid = Process.INVALID_UID
- )
+ /** Remove a listener for changes in this class */
+ fun removeListener(listener: Listener)
-internal val EMPTY_SMARTSPACE_MEDIA_DATA =
- SmartspaceMediaData(
- targetId = "INVALID",
- isActive = false,
- packageName = "INVALID",
- cardAction = null,
- recommendations = emptyList(),
- dismissIntent = null,
- headphoneConnectionTimeMillis = 0,
- instanceId = InstanceId.fakeInstanceId(-1),
- expiryTimeMs = 0,
- )
+ /**
+ * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
+ * will make the player not active anymore, hiding it from QQS and Keyguard.
+ *
+ * @see MediaData.active
+ */
+ fun setInactive(key: String, timedOut: Boolean, forceUpdate: Boolean = false)
-const val MEDIA_TITLE_ERROR_MESSAGE = "Invalid media data: title is null or blank."
+ /** Invoked when media notification is added. */
+ fun onNotificationAdded(key: String, sbn: StatusBarNotification)
-fun isMediaNotification(sbn: StatusBarNotification): Boolean {
- return sbn.notification.isMediaNotification()
-}
+ fun destroy()
-/**
- * Allow recommendations from smartspace to show in media controls. Requires
- * [Utils.useQsMediaPlayer] to be enabled. On by default, but can be disabled by setting to 0
- */
-private fun allowMediaRecommendations(context: Context): Boolean {
- val flag =
- Settings.Secure.getInt(
- context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 1
- )
- return Utils.useQsMediaPlayer(context) && flag > 0
-}
+ /** Sets resume action. */
+ fun setResumeAction(key: String, action: Runnable?)
-/** A class that facilitates management and loading of Media Data, ready for binding. */
-@SysUISingleton
-class MediaDataManager(
- private val context: Context,
- @Background private val backgroundExecutor: Executor,
- @Main private val uiExecutor: Executor,
- @Main private val foregroundExecutor: DelayableExecutor,
- private val mediaControllerFactory: MediaControllerFactory,
- private val broadcastDispatcher: BroadcastDispatcher,
- dumpManager: DumpManager,
- mediaTimeoutListener: MediaTimeoutListener,
- mediaResumeListener: MediaResumeListener,
- mediaSessionBasedFilter: MediaSessionBasedFilter,
- mediaDeviceManager: MediaDeviceManager,
- mediaDataCombineLatest: MediaDataCombineLatest,
- private val mediaDataFilter: MediaDataFilter,
- private val activityStarter: ActivityStarter,
- private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
- private var useMediaResumption: Boolean,
- private val useQsMediaPlayer: Boolean,
- private val systemClock: SystemClock,
- private val tunerService: TunerService,
- private val mediaFlags: MediaFlags,
- private val logger: MediaUiEventLogger,
- private val smartspaceManager: SmartspaceManager?,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
-
- companion object {
- // UI surface label for subscribing Smartspace updates.
- @JvmField val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
-
- // Smartspace package name's extra key.
- @JvmField val EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"
-
- // Maximum number of actions allowed in compact view
- @JvmField val MAX_COMPACT_ACTIONS = 3
-
- // Maximum number of actions allowed in expanded view
- @JvmField val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
- }
-
- private val themeText =
- com.android.settingslib.Utils.getColorAttr(
- context,
- com.android.internal.R.attr.textColorPrimary
- )
- .defaultColor
-
- // Internal listeners are part of the internal pipeline. External listeners (those registered
- // with [MediaDeviceManager.addListener]) receive events after they have propagated through
- // the internal pipeline.
- // Another way to think of the distinction between internal and external listeners is the
- // following. Internal listeners are listeners that MediaDataManager depends on, and external
- // listeners are listeners that depend on MediaDataManager.
- // TODO(b/159539991#comment5): Move internal listeners to separate package.
- private val internalListeners: MutableSet<Listener> = mutableSetOf()
- private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
- // There should ONLY be at most one Smartspace media recommendation.
- var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
- @Keep private var smartspaceSession: SmartspaceSession? = null
- private var allowMediaRecommendations = allowMediaRecommendations(context)
-
- private val artworkWidth =
- context.resources.getDimensionPixelSize(
- com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize
- )
- private val artworkHeight =
- context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
-
- @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
- private val statusBarManager =
- context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager
-
- /** Check whether this notification is an RCN */
- private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
- return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
- }
-
- @Inject
- constructor(
- context: Context,
- threadFactory: ThreadFactory,
- @Main uiExecutor: Executor,
- @Main foregroundExecutor: DelayableExecutor,
- mediaControllerFactory: MediaControllerFactory,
- dumpManager: DumpManager,
- broadcastDispatcher: BroadcastDispatcher,
- mediaTimeoutListener: MediaTimeoutListener,
- mediaResumeListener: MediaResumeListener,
- mediaSessionBasedFilter: MediaSessionBasedFilter,
- mediaDeviceManager: MediaDeviceManager,
- mediaDataCombineLatest: MediaDataCombineLatest,
- mediaDataFilter: MediaDataFilter,
- activityStarter: ActivityStarter,
- smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
- clock: SystemClock,
- tunerService: TunerService,
- mediaFlags: MediaFlags,
- logger: MediaUiEventLogger,
- smartspaceManager: SmartspaceManager?,
- keyguardUpdateMonitor: KeyguardUpdateMonitor,
- ) : this(
- context,
- // Loading bitmap for UMO background can take longer time, so it cannot run on the default
- // background thread. Use a custom thread for media.
- threadFactory.buildExecutorOnNewThread(TAG),
- uiExecutor,
- foregroundExecutor,
- mediaControllerFactory,
- broadcastDispatcher,
- dumpManager,
- mediaTimeoutListener,
- mediaResumeListener,
- mediaSessionBasedFilter,
- mediaDeviceManager,
- mediaDataCombineLatest,
- mediaDataFilter,
- activityStarter,
- smartspaceMediaDataProvider,
- Utils.useMediaResumption(context),
- Utils.useQsMediaPlayer(context),
- clock,
- tunerService,
- mediaFlags,
- logger,
- smartspaceManager,
- keyguardUpdateMonitor,
- )
-
- private val appChangeReceiver =
- object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_PACKAGES_SUSPENDED -> {
- val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
- packages?.forEach { removeAllForPackage(it) }
- }
- Intent.ACTION_PACKAGE_REMOVED,
- Intent.ACTION_PACKAGE_RESTARTED -> {
- intent.data?.encodedSchemeSpecificPart?.let { removeAllForPackage(it) }
- }
- }
- }
- }
-
- init {
- dumpManager.registerDumpable(TAG, this)
-
- // Initialize the internal processing pipeline. The listeners at the front of the pipeline
- // are set as internal listeners so that they receive events. From there, events are
- // propagated through the pipeline. The end of the pipeline is currently mediaDataFilter,
- // so it is responsible for dispatching events to external listeners. To achieve this,
- // external listeners that are registered with [MediaDataManager.addListener] are actually
- // registered as listeners to mediaDataFilter.
- addInternalListener(mediaTimeoutListener)
- addInternalListener(mediaResumeListener)
- addInternalListener(mediaSessionBasedFilter)
- mediaSessionBasedFilter.addListener(mediaDeviceManager)
- mediaSessionBasedFilter.addListener(mediaDataCombineLatest)
- mediaDeviceManager.addListener(mediaDataCombineLatest)
- mediaDataCombineLatest.addListener(mediaDataFilter)
-
- // Set up links back into the pipeline for listeners that need to send events upstream.
- mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean ->
- setTimedOut(key, timedOut)
- }
- mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
- updateState(key, state)
- }
- mediaTimeoutListener.sessionCallback = { key: String -> onSessionDestroyed(key) }
- mediaResumeListener.setManager(this)
- mediaDataFilter.mediaDataManager = this
-
- val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
- broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
-
- val uninstallFilter =
- IntentFilter().apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_RESTARTED)
- addDataScheme("package")
- }
- // BroadcastDispatcher does not allow filters with data schemes
- context.registerReceiver(appChangeReceiver, uninstallFilter)
-
- // Register for Smartspace data updates.
- smartspaceMediaDataProvider.registerListener(this)
- smartspaceSession =
- smartspaceManager?.createSmartspaceSession(
- SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build()
- )
- smartspaceSession?.let {
- it.addOnTargetsAvailableListener(
- // Use a main uiExecutor thread listening to Smartspace updates instead of using
- // the existing background executor.
- // SmartspaceSession has scheduled routine updates which can be unpredictable on
- // test simulators, using the backgroundExecutor makes it's hard to test the threads
- // numbers.
- uiExecutor,
- SmartspaceSession.OnTargetsAvailableListener { targets ->
- smartspaceMediaDataProvider.onTargetsAvailable(targets)
- }
- )
- }
- smartspaceSession?.let { it.requestSmartspaceUpdate() }
- tunerService.addTunable(
- object : TunerService.Tunable {
- override fun onTuningChanged(key: String?, newValue: String?) {
- allowMediaRecommendations = allowMediaRecommendations(context)
- if (!allowMediaRecommendations) {
- dismissSmartspaceRecommendation(
- key = smartspaceMediaData.targetId,
- delay = 0L
- )
- }
- }
- },
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION
- )
- }
-
- fun destroy() {
- smartspaceMediaDataProvider.unregisterListener(this)
- smartspaceSession?.close()
- smartspaceSession = null
- context.unregisterReceiver(appChangeReceiver)
- }
-
- fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
- if (useQsMediaPlayer && isMediaNotification(sbn)) {
- var isNewlyActiveEntry = false
- Assert.isMainThread()
- val oldKey = findExistingEntry(key, sbn.packageName)
- if (oldKey == null) {
- val instanceId = logger.getNewInstanceId()
- val temp =
- LOADING.copy(
- packageName = sbn.packageName,
- instanceId = instanceId,
- createdTimestampMillis = systemClock.currentTimeMillis(),
- )
- mediaEntries.put(key, temp)
- isNewlyActiveEntry = true
- } else if (oldKey != key) {
- // Resume -> active conversion; move to new key
- val oldData = mediaEntries.remove(oldKey)!!
- isNewlyActiveEntry = true
- mediaEntries.put(key, oldData)
- }
- loadMediaData(key, sbn, oldKey, isNewlyActiveEntry)
- } else {
- onNotificationRemoved(key)
- }
- }
-
- private fun removeAllForPackage(packageName: String) {
- Assert.isMainThread()
- val toRemove = mediaEntries.filter { it.value.packageName == packageName }
- toRemove.forEach { removeEntry(it.key) }
- }
-
- fun setResumeAction(key: String, action: Runnable?) {
- mediaEntries.get(key)?.let {
- it.resumeAction = action
- it.hasCheckedForResume = true
- }
- }
-
+ /** Adds resume media data. */
fun addResumptionControls(
userId: Int,
desc: MediaDescription,
@@ -442,1184 +57,45 @@
appName: String,
appIntent: PendingIntent,
packageName: String
- ) {
- // Resume controls don't have a notification key, so store by package name instead
- if (!mediaEntries.containsKey(packageName)) {
- val instanceId = logger.getNewInstanceId()
- val appUid =
- try {
- context.packageManager.getApplicationInfo(packageName, 0)?.uid!!
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Could not get app UID for $packageName", e)
- Process.INVALID_UID
- }
-
- val resumeData =
- LOADING.copy(
- packageName = packageName,
- resumeAction = action,
- hasCheckedForResume = true,
- instanceId = instanceId,
- appUid = appUid,
- createdTimestampMillis = systemClock.currentTimeMillis(),
- )
- mediaEntries.put(packageName, resumeData)
- logSingleVsMultipleMediaAdded(appUid, packageName, instanceId)
- logger.logResumeMediaAdded(appUid, packageName, instanceId)
- }
- backgroundExecutor.execute {
- loadMediaDataInBgForResumption(
- userId,
- desc,
- action,
- token,
- appName,
- appIntent,
- packageName
- )
- }
- }
-
- /**
- * Check if there is an existing entry that matches the key or package name. Returns the key
- * that matches, or null if not found.
- */
- private fun findExistingEntry(key: String, packageName: String): String? {
- if (mediaEntries.containsKey(key)) {
- return key
- }
- // Check if we already had a resume player
- if (mediaEntries.containsKey(packageName)) {
- return packageName
- }
- return null
- }
-
- private fun loadMediaData(
- key: String,
- sbn: StatusBarNotification,
- oldKey: String?,
- isNewlyActiveEntry: Boolean = false,
- ) {
- backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, isNewlyActiveEntry) }
- }
-
- /** Add a listener for changes in this class */
- fun addListener(listener: Listener) {
- // mediaDataFilter is the current end of the internal pipeline. Register external
- // listeners as listeners to it.
- mediaDataFilter.addListener(listener)
- }
-
- /** Remove a listener for changes in this class */
- fun removeListener(listener: Listener) {
- // Since mediaDataFilter is the current end of the internal pipelie, external listeners
- // have been registered to it. So, they need to be removed from it too.
- mediaDataFilter.removeListener(listener)
- }
-
- /** Add a listener for internal events. */
- private fun addInternalListener(listener: Listener) = internalListeners.add(listener)
-
- /**
- * Notify internal listeners of media loaded event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- */
- private fun notifyMediaDataLoaded(key: String, oldKey: String?, info: MediaData) {
- internalListeners.forEach { it.onMediaDataLoaded(key, oldKey, info) }
- }
-
- /**
- * Notify internal listeners of Smartspace media loaded event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- */
- private fun notifySmartspaceMediaDataLoaded(key: String, info: SmartspaceMediaData) {
- internalListeners.forEach { it.onSmartspaceMediaDataLoaded(key, info) }
- }
-
- /**
- * Notify internal listeners of media removed event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- */
- private fun notifyMediaDataRemoved(key: String) {
- internalListeners.forEach { it.onMediaDataRemoved(key) }
- }
-
- /**
- * Notify internal listeners of Smartspace media removed event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- *
- * @param immediately indicates should apply the UI changes immediately, otherwise wait until
- * the next refresh-round before UI becomes visible. Should only be true if the update is
- * initiated by user's interaction.
- */
- private fun notifySmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
- internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
- }
-
- /**
- * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
- * will make the player not active anymore, hiding it from QQS and Keyguard.
- *
- * @see MediaData.active
- */
- internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) {
- mediaEntries[key]?.let {
- if (timedOut && !forceUpdate) {
- // Only log this event when media expires on its own
- logger.logMediaTimeout(it.appUid, it.packageName, it.instanceId)
- }
- if (it.active == !timedOut && !forceUpdate) {
- if (it.resumption) {
- if (DEBUG) Log.d(TAG, "timing out resume player $key")
- dismissMediaData(key, 0L /* delay */)
- }
- return
- }
- // Update last active if media was still active.
- if (it.active) {
- it.lastActive = systemClock.elapsedRealtime()
- }
- it.active = !timedOut
- if (DEBUG) Log.d(TAG, "Updating $key timedOut: $timedOut")
- onMediaDataLoaded(key, key, it)
- }
-
- if (key == smartspaceMediaData.targetId) {
- if (DEBUG) Log.d(TAG, "smartspace card expired")
- dismissSmartspaceRecommendation(key, delay = 0L)
- }
- }
-
- /** Called when the player's [PlaybackState] has been updated with new actions and/or state */
- private fun updateState(key: String, state: PlaybackState) {
- mediaEntries.get(key)?.let {
- val token = it.token
- if (token == null) {
- if (DEBUG) Log.d(TAG, "State updated, but token was null")
- return
- }
- val actions =
- createActionsFromState(
- it.packageName,
- mediaControllerFactory.create(it.token),
- UserHandle(it.userId)
- )
-
- // Control buttons
- // If flag is enabled and controller has a PlaybackState,
- // create actions from session info
- // otherwise, no need to update semantic actions.
- val data =
- if (actions != null) {
- it.copy(semanticActions = actions, isPlaying = isPlayingState(state.state))
- } else {
- it.copy(isPlaying = isPlayingState(state.state))
- }
- if (DEBUG) Log.d(TAG, "State updated outside of notification")
- onMediaDataLoaded(key, key, data)
- }
- }
-
- private fun removeEntry(key: String, logEvent: Boolean = true) {
- mediaEntries.remove(key)?.let {
- if (logEvent) {
- logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
- }
- }
- notifyMediaDataRemoved(key)
- }
+ )
/** Dismiss a media entry. Returns false if the key was not found. */
- fun dismissMediaData(key: String, delay: Long): Boolean {
- val existed = mediaEntries[key] != null
- backgroundExecutor.execute {
- mediaEntries[key]?.let { mediaData ->
- if (mediaData.isLocalSession()) {
- mediaData.token?.let {
- val mediaController = mediaControllerFactory.create(it)
- mediaController.transportControls.stop()
- }
- }
- }
- }
- foregroundExecutor.executeDelayed({ removeEntry(key) }, delay)
- return existed
- }
+ fun dismissMediaData(key: String, delay: Long): Boolean
/**
* Called whenever the recommendation has been expired or removed by the user. This will remove
* the recommendation card entirely from the carousel.
*/
- fun dismissSmartspaceRecommendation(key: String, delay: Long) {
- if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
- // If this doesn't match, or we've already invalidated the data, no action needed
- return
- }
-
- if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
- if (smartspaceMediaData.isActive) {
- smartspaceMediaData =
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId
- )
- }
- foregroundExecutor.executeDelayed(
- { notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = true) },
- delay
- )
- }
+ fun dismissSmartspaceRecommendation(key: String, delay: Long)
/** Called when the recommendation card should no longer be visible in QQS or lockscreen */
- fun setRecommendationInactive(key: String) {
- if (!mediaFlags.isPersistentSsCardEnabled()) {
- Log.e(TAG, "Only persistent recommendation can be inactive!")
- return
- }
- if (DEBUG) Log.d(TAG, "Setting smartspace recommendation inactive")
+ fun setRecommendationInactive(key: String)
- if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
- // If this doesn't match, or we've already invalidated the data, no action needed
- return
- }
+ /** Invoked when notification is removed. */
+ fun onNotificationRemoved(key: String)
- smartspaceMediaData = smartspaceMediaData.copy(isActive = false)
- notifySmartspaceMediaDataLoaded(smartspaceMediaData.targetId, smartspaceMediaData)
- }
-
- private fun loadMediaDataInBgForResumption(
- userId: Int,
- desc: MediaDescription,
- resumeAction: Runnable,
- token: MediaSession.Token,
- appName: String,
- appIntent: PendingIntent,
- packageName: String
- ) {
- if (desc.title.isNullOrBlank()) {
- Log.e(TAG, "Description incomplete")
- // Delete the placeholder entry
- mediaEntries.remove(packageName)
- return
- }
-
- if (DEBUG) {
- Log.d(TAG, "adding track for $userId from browser: $desc")
- }
-
- val currentEntry = mediaEntries.get(packageName)
- val appUid = currentEntry?.appUid ?: Process.INVALID_UID
-
- // Album art
- var artworkBitmap = desc.iconBitmap
- if (artworkBitmap == null && desc.iconUri != null) {
- artworkBitmap = loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName)
- }
- val artworkIcon =
- if (artworkBitmap != null) {
- Icon.createWithBitmap(artworkBitmap)
- } else {
- null
- }
-
- val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
- val isExplicit =
- desc.extras?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
-
- val progress =
- if (mediaFlags.isResumeProgressEnabled()) {
- MediaDataUtils.getDescriptionProgress(desc.extras)
- } else null
-
- val mediaAction = getResumeMediaAction(resumeAction)
- val lastActive = systemClock.elapsedRealtime()
- val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
- foregroundExecutor.execute {
- onMediaDataLoaded(
- packageName,
- null,
- MediaData(
- userId,
- true,
- appName,
- null,
- desc.subtitle,
- desc.title,
- artworkIcon,
- listOf(mediaAction),
- listOf(0),
- MediaButton(playOrPause = mediaAction),
- packageName,
- token,
- appIntent,
- device = null,
- active = false,
- resumeAction = resumeAction,
- resumption = true,
- notificationKey = packageName,
- hasCheckedForResume = true,
- lastActive = lastActive,
- createdTimestampMillis = createdTimestampMillis,
- instanceId = instanceId,
- appUid = appUid,
- isExplicit = isExplicit,
- resumeProgress = progress,
- )
- )
- }
- }
-
- fun loadMediaDataInBg(
- key: String,
- sbn: StatusBarNotification,
- oldKey: String?,
- isNewlyActiveEntry: Boolean = false,
- ) {
- val token =
- sbn.notification.extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION,
- MediaSession.Token::class.java
- )
- if (token == null) {
- return
- }
- val mediaController = mediaControllerFactory.create(token)
- val metadata = mediaController.metadata
- val notif: Notification = sbn.notification
-
- val appInfo =
- notif.extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO,
- ApplicationInfo::class.java
- )
- ?: getAppInfoFromPackage(sbn.packageName)
-
- // App name
- val appName = getAppName(sbn, appInfo)
-
- // Song name
- var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
- if (song.isNullOrBlank()) {
- song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
- }
- if (song.isNullOrBlank()) {
- song = HybridGroupManager.resolveTitle(notif)
- }
- if (song.isNullOrBlank()) {
- // For apps that don't include a title, log and add a placeholder
- song = context.getString(R.string.controls_media_empty_title, appName)
- try {
- statusBarManager.logBlankMediaTitle(sbn.packageName, sbn.user.identifier)
- } catch (e: RuntimeException) {
- Log.e(TAG, "Error reporting blank media title for package ${sbn.packageName}")
- }
- }
-
- // Album art
- var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
- if (artworkBitmap == null) {
- artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
- }
- if (artworkBitmap == null) {
- artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
- }
- val artWorkIcon =
- if (artworkBitmap == null) {
- notif.getLargeIcon()
- } else {
- Icon.createWithBitmap(artworkBitmap)
- }
-
- // App Icon
- val smallIcon = sbn.notification.smallIcon
-
- // Explicit Indicator
- var isExplicit = false
- val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
- isExplicit =
- mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
-
- // Artist name
- var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
- if (artist.isNullOrBlank()) {
- artist = HybridGroupManager.resolveText(notif)
- }
-
- // Device name (used for remote cast notifications)
- var device: MediaDeviceData? = null
- if (isRemoteCastNotification(sbn)) {
- val extras = sbn.notification.extras
- val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
- val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
- val deviceIntent =
- extras.getParcelable(
- Notification.EXTRA_MEDIA_REMOTE_INTENT,
- PendingIntent::class.java
- )
- Log.d(TAG, "$key is RCN for $deviceName")
-
- if (deviceName != null && deviceIcon > -1) {
- // Name and icon must be present, but intent may be null
- val enabled = deviceIntent != null && deviceIntent.isActivity
- val deviceDrawable =
- Icon.createWithResource(sbn.packageName, deviceIcon)
- .loadDrawable(sbn.getPackageContext(context))
- device =
- MediaDeviceData(
- enabled,
- deviceDrawable,
- deviceName,
- deviceIntent,
- showBroadcastButton = false
- )
- }
- }
-
- // Control buttons
- // If flag is enabled and controller has a PlaybackState, create actions from session info
- // Otherwise, use the notification actions
- var actionIcons: List<MediaAction> = emptyList()
- var actionsToShowCollapsed: List<Int> = emptyList()
- val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
- if (semanticActions == null) {
- val actions = createActionsFromNotification(sbn)
- actionIcons = actions.first
- actionsToShowCollapsed = actions.second
- }
-
- val playbackLocation =
- if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
- else if (
- mediaController.playbackInfo?.playbackType ==
- MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
- )
- MediaData.PLAYBACK_LOCAL
- else MediaData.PLAYBACK_CAST_LOCAL
- val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
-
- val currentEntry = mediaEntries.get(key)
- val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
- val appUid = appInfo?.uid ?: Process.INVALID_UID
-
- if (isNewlyActiveEntry) {
- logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId)
- logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
- } else if (playbackLocation != currentEntry?.playbackLocation) {
- logger.logPlaybackLocationChange(appUid, sbn.packageName, instanceId, playbackLocation)
- }
-
- val lastActive = systemClock.elapsedRealtime()
- val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
- foregroundExecutor.execute {
- val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
- val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
- val active = mediaEntries[key]?.active ?: true
- onMediaDataLoaded(
- key,
- oldKey,
- MediaData(
- sbn.normalizedUserId,
- true,
- appName,
- smallIcon,
- artist,
- song,
- artWorkIcon,
- actionIcons,
- actionsToShowCollapsed,
- semanticActions,
- sbn.packageName,
- token,
- notif.contentIntent,
- device,
- active,
- resumeAction = resumeAction,
- playbackLocation = playbackLocation,
- notificationKey = key,
- hasCheckedForResume = hasCheckedForResume,
- isPlaying = isPlaying,
- isClearable = !sbn.isOngoing,
- lastActive = lastActive,
- createdTimestampMillis = createdTimestampMillis,
- instanceId = instanceId,
- appUid = appUid,
- isExplicit = isExplicit,
- )
- )
- }
- }
-
- private fun logSingleVsMultipleMediaAdded(
- appUid: Int,
- packageName: String,
- instanceId: InstanceId
- ) {
- if (mediaEntries.size == 1) {
- logger.logSingleMediaPlayerInCarousel(appUid, packageName, instanceId)
- } else if (mediaEntries.size == 2) {
- // Since this method is only called when there is a new media session added.
- // logging needed once there is more than one media session in carousel.
- logger.logMultipleMediaPlayersInCarousel(appUid, packageName, instanceId)
- }
- }
-
- private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
- try {
- return context.packageManager.getApplicationInfo(packageName, 0)
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Could not get app info for $packageName", e)
- }
- return null
- }
-
- private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
- val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
- if (name != null) {
- return name
- }
-
- return if (appInfo != null) {
- context.packageManager.getApplicationLabel(appInfo).toString()
- } else {
- sbn.packageName
- }
- }
-
- /** Generate action buttons based on notification actions */
- private fun createActionsFromNotification(
- sbn: StatusBarNotification
- ): Pair<List<MediaAction>, List<Int>> {
- val notif = sbn.notification
- val actionIcons: MutableList<MediaAction> = ArrayList()
- val actions = notif.actions
- var actionsToShowCollapsed =
- notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList()
- ?: mutableListOf()
- if (actionsToShowCollapsed.size > MAX_COMPACT_ACTIONS) {
- Log.e(
- TAG,
- "Too many compact actions for ${sbn.key}," +
- "limiting to first $MAX_COMPACT_ACTIONS"
- )
- actionsToShowCollapsed = actionsToShowCollapsed.subList(0, MAX_COMPACT_ACTIONS)
- }
-
- if (actions != null) {
- for ((index, action) in actions.withIndex()) {
- if (index == MAX_NOTIFICATION_ACTIONS) {
- Log.w(
- TAG,
- "Too many notification actions for ${sbn.key}," +
- " limiting to first $MAX_NOTIFICATION_ACTIONS"
- )
- break
- }
- if (action.getIcon() == null) {
- if (DEBUG) Log.i(TAG, "No icon for action $index ${action.title}")
- actionsToShowCollapsed.remove(index)
- continue
- }
- val runnable =
- if (action.actionIntent != null) {
- Runnable {
- if (action.actionIntent.isActivity) {
- activityStarter.startPendingIntentDismissingKeyguard(
- action.actionIntent
- )
- } else if (action.isAuthenticationRequired()) {
- activityStarter.dismissKeyguardThenExecute(
- {
- var result = sendPendingIntent(action.actionIntent)
- result
- },
- {},
- true
- )
- } else {
- sendPendingIntent(action.actionIntent)
- }
- }
- } else {
- null
- }
- val mediaActionIcon =
- if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
- Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
- } else {
- action.getIcon()
- }
- .setTint(themeText)
- .loadDrawable(context)
- val mediaAction = MediaAction(mediaActionIcon, runnable, action.title, null)
- actionIcons.add(mediaAction)
- }
- }
- return Pair(actionIcons, actionsToShowCollapsed)
- }
-
- /**
- * Generates action button info for this media session based on the PlaybackState
- *
- * @param packageName Package name for the media app
- * @param controller MediaController for the current session
- * @return a Pair consisting of a list of media actions, and a list of ints representing which
- *
- * ```
- * of those actions should be shown in the compact player
- * ```
- */
- private fun createActionsFromState(
- packageName: String,
- controller: MediaController,
- user: UserHandle
- ): MediaButton? {
- val state = controller.playbackState
- if (state == null || !mediaFlags.areMediaSessionActionsEnabled(packageName, user)) {
- return null
- }
-
- // First, check for standard actions
- val playOrPause =
- if (isConnectingState(state.state)) {
- // Spinner needs to be animating to render anything. Start it here.
- val drawable =
- context.getDrawable(com.android.internal.R.drawable.progress_small_material)
- (drawable as Animatable).start()
- MediaAction(
- drawable,
- null, // no action to perform when clicked
- context.getString(R.string.controls_media_button_connecting),
- context.getDrawable(R.drawable.ic_media_connecting_container),
- // Specify a rebind id to prevent the spinner from restarting on later binds.
- com.android.internal.R.drawable.progress_small_material
- )
- } else if (isPlayingState(state.state)) {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
- } else {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
- }
- val prevButton =
- getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_PREVIOUS)
- val nextButton =
- getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_NEXT)
-
- // Then, create a way to build any custom actions that will be needed
- val customActions =
- state.customActions
- .asSequence()
- .filterNotNull()
- .map { getCustomAction(state, packageName, controller, it) }
- .iterator()
- fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
-
- // Finally, assign the remaining button slots: play/pause A B C D
- // A = previous, else custom action (if not reserved)
- // B = next, else custom action (if not reserved)
- // C and D are always custom actions
- val reservePrev =
- controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
- ) == true
- val reserveNext =
- controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
- ) == true
-
- val prevOrCustom =
- if (prevButton != null) {
- prevButton
- } else if (!reservePrev) {
- nextCustomAction()
- } else {
- null
- }
-
- val nextOrCustom =
- if (nextButton != null) {
- nextButton
- } else if (!reserveNext) {
- nextCustomAction()
- } else {
- null
- }
-
- return MediaButton(
- playOrPause,
- nextOrCustom,
- prevOrCustom,
- nextCustomAction(),
- nextCustomAction(),
- reserveNext,
- reservePrev
- )
- }
-
- /**
- * Create a [MediaAction] for a given action and media session
- *
- * @param controller MediaController for the session
- * @param stateActions The actions included with the session's [PlaybackState]
- * @param action A [PlaybackState.Actions] value representing what action to generate. One of:
- * ```
- * [PlaybackState.ACTION_PLAY]
- * [PlaybackState.ACTION_PAUSE]
- * [PlaybackState.ACTION_SKIP_TO_PREVIOUS]
- * [PlaybackState.ACTION_SKIP_TO_NEXT]
- * @return
- * ```
- *
- * A [MediaAction] with correct values set, or null if the state doesn't support it
- */
- private fun getStandardAction(
- controller: MediaController,
- stateActions: Long,
- @PlaybackState.Actions action: Long
- ): MediaAction? {
- if (!includesAction(stateActions, action)) {
- return null
- }
-
- return when (action) {
- PlaybackState.ACTION_PLAY -> {
- MediaAction(
- context.getDrawable(R.drawable.ic_media_play),
- { controller.transportControls.play() },
- context.getString(R.string.controls_media_button_play),
- context.getDrawable(R.drawable.ic_media_play_container)
- )
- }
- PlaybackState.ACTION_PAUSE -> {
- MediaAction(
- context.getDrawable(R.drawable.ic_media_pause),
- { controller.transportControls.pause() },
- context.getString(R.string.controls_media_button_pause),
- context.getDrawable(R.drawable.ic_media_pause_container)
- )
- }
- PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
- MediaAction(
- context.getDrawable(R.drawable.ic_media_prev),
- { controller.transportControls.skipToPrevious() },
- context.getString(R.string.controls_media_button_prev),
- null
- )
- }
- PlaybackState.ACTION_SKIP_TO_NEXT -> {
- MediaAction(
- context.getDrawable(R.drawable.ic_media_next),
- { controller.transportControls.skipToNext() },
- context.getString(R.string.controls_media_button_next),
- null
- )
- }
- else -> null
- }
- }
-
- /** Check whether the actions from a [PlaybackState] include a specific action */
- private fun includesAction(stateActions: Long, @PlaybackState.Actions action: Long): Boolean {
- if (
- (action == PlaybackState.ACTION_PLAY || action == PlaybackState.ACTION_PAUSE) &&
- (stateActions and PlaybackState.ACTION_PLAY_PAUSE > 0L)
- ) {
- return true
- }
- return (stateActions and action != 0L)
- }
-
- /** Get a [MediaAction] representing a [PlaybackState.CustomAction] */
- private fun getCustomAction(
- state: PlaybackState,
- packageName: String,
- controller: MediaController,
- customAction: PlaybackState.CustomAction
- ): MediaAction {
- return MediaAction(
- Icon.createWithResource(packageName, customAction.icon).loadDrawable(context),
- { controller.transportControls.sendCustomAction(customAction, customAction.extras) },
- customAction.name,
- null
- )
- }
-
- /** Load a bitmap from the various Art metadata URIs */
- private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
- for (uri in ART_URIS) {
- val uriString = metadata.getString(uri)
- if (!TextUtils.isEmpty(uriString)) {
- val albumArt = loadBitmapFromUri(Uri.parse(uriString))
- if (albumArt != null) {
- if (DEBUG) Log.d(TAG, "loaded art from $uri")
- return albumArt
- }
- }
- }
- return null
- }
-
- private fun sendPendingIntent(intent: PendingIntent): Boolean {
- return try {
- val options = BroadcastOptions.makeBasic()
- options.setInteractive(true)
- options.setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
- )
- intent.send(options.toBundle())
- true
- } catch (e: PendingIntent.CanceledException) {
- Log.d(TAG, "Intent canceled", e)
- false
- }
- }
-
- /** Returns a bitmap if the user can access the given URI, else null */
- private fun loadBitmapFromUriForUser(
- uri: Uri,
- userId: Int,
- appUid: Int,
- packageName: String,
- ): Bitmap? {
- try {
- val ugm = UriGrantsManager.getService()
- ugm.checkGrantUriPermission_ignoreNonSystem(
- appUid,
- packageName,
- ContentProvider.getUriWithoutUserId(uri),
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- ContentProvider.getUserIdFromUri(uri, userId)
- )
- return loadBitmapFromUri(uri)
- } catch (e: SecurityException) {
- Log.e(TAG, "Failed to get URI permission: $e")
- }
- return null
- }
-
- /**
- * Load a bitmap from a URI
- *
- * @param uri the uri to load
- * @return bitmap, or null if couldn't be loaded
- */
- private fun loadBitmapFromUri(uri: Uri): Bitmap? {
- // ImageDecoder requires a scheme of the following types
- if (uri.scheme == null) {
- return null
- }
-
- if (
- !uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
- !uri.scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE) &&
- !uri.scheme.equals(ContentResolver.SCHEME_FILE)
- ) {
- return null
- }
-
- val source = ImageDecoder.createSource(context.contentResolver, uri)
- return try {
- ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
- val width = info.size.width
- val height = info.size.height
- val scale =
- MediaDataUtils.getScaleFactor(
- APair(width, height),
- APair(artworkWidth, artworkHeight)
- )
-
- // Downscale if needed
- if (scale != 0f && scale < 1) {
- decoder.setTargetSize((scale * width).toInt(), (scale * height).toInt())
- }
- decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
- }
- } catch (e: IOException) {
- Log.e(TAG, "Unable to load bitmap", e)
- null
- } catch (e: RuntimeException) {
- Log.e(TAG, "Unable to load bitmap", e)
- null
- }
- }
-
- private fun getResumeMediaAction(action: Runnable): MediaAction {
- return MediaAction(
- Icon.createWithResource(context, R.drawable.ic_media_play)
- .setTint(themeText)
- .loadDrawable(context),
- action,
- context.getString(R.string.controls_media_resume),
- context.getDrawable(R.drawable.ic_media_play_container)
- )
- }
-
- fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) =
- traceSection("MediaDataManager#onMediaDataLoaded") {
- Assert.isMainThread()
- if (mediaEntries.containsKey(key)) {
- // Otherwise this was removed already
- mediaEntries.put(key, data)
- notifyMediaDataLoaded(key, oldKey, data)
- }
- }
-
- override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
- if (!allowMediaRecommendations) {
- if (DEBUG) Log.d(TAG, "Smartspace recommendation is disabled in Settings.")
- return
- }
-
- val mediaTargets = targets.filterIsInstance<SmartspaceTarget>()
- when (mediaTargets.size) {
- 0 -> {
- if (!smartspaceMediaData.isActive) {
- return
- }
- if (DEBUG) {
- Log.d(TAG, "Set Smartspace media to be inactive for the data update")
- }
- if (mediaFlags.isPersistentSsCardEnabled()) {
- // Smartspace uses this signal to hide the card (e.g. when it expires or user
- // disconnects headphones), so treat as setting inactive when flag is on
- smartspaceMediaData = smartspaceMediaData.copy(isActive = false)
- notifySmartspaceMediaDataLoaded(
- smartspaceMediaData.targetId,
- smartspaceMediaData,
- )
- } else {
- smartspaceMediaData =
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId,
- )
- notifySmartspaceMediaDataRemoved(
- smartspaceMediaData.targetId,
- immediately = false,
- )
- }
- }
- 1 -> {
- val newMediaTarget = mediaTargets.get(0)
- if (smartspaceMediaData.targetId == newMediaTarget.smartspaceTargetId) {
- // The same Smartspace updates can be received. Skip the duplicate updates.
- return
- }
- if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.")
- smartspaceMediaData = toSmartspaceMediaData(newMediaTarget)
- notifySmartspaceMediaDataLoaded(smartspaceMediaData.targetId, smartspaceMediaData)
- }
- else -> {
- // There should NOT be more than 1 Smartspace media update. When it happens, it
- // indicates a bad state or an error. Reset the status accordingly.
- Log.wtf(TAG, "More than 1 Smartspace Media Update. Resetting the status...")
- notifySmartspaceMediaDataRemoved(
- smartspaceMediaData.targetId,
- immediately = false,
- )
- smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
- }
- }
- }
-
- fun onNotificationRemoved(key: String) {
- Assert.isMainThread()
- val removed = mediaEntries.remove(key) ?: return
- if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
- logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
- } else if (isAbleToResume(removed)) {
- convertToResumePlayer(key, removed)
- } else if (mediaFlags.isRetainingPlayersEnabled()) {
- handlePossibleRemoval(key, removed, notificationRemoved = true)
- } else {
- notifyMediaDataRemoved(key)
- logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
- }
- }
-
- private fun onSessionDestroyed(key: String) {
- if (DEBUG) Log.d(TAG, "session destroyed for $key")
- val entry = mediaEntries.remove(key) ?: return
- // Clear token since the session is no longer valid
- val updated = entry.copy(token = null)
- handlePossibleRemoval(key, updated)
- }
-
- private fun isAbleToResume(data: MediaData): Boolean {
- val isEligibleForResume =
- data.isLocalSession() ||
- (mediaFlags.isRemoteResumeAllowed() &&
- data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
- return useMediaResumption && data.resumeAction != null && isEligibleForResume
- }
-
- /**
- * Convert to resume state if the player is no longer valid and active, then notify listeners
- * that the data was updated. Does not convert to resume state if the player is still valid, or
- * if it was removed before becoming inactive. (Assumes that [removed] was removed from
- * [mediaEntries] before this function was called)
- */
- private fun handlePossibleRemoval(
- key: String,
- removed: MediaData,
- notificationRemoved: Boolean = false
- ) {
- val hasSession = removed.token != null
- if (hasSession && removed.semanticActions != null) {
- // The app was using session actions, and the session is still valid: keep player
- if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
- mediaEntries.put(key, removed)
- notifyMediaDataLoaded(key, key, removed)
- } else if (!notificationRemoved && removed.semanticActions == null) {
- // The app was using notification actions, and notif wasn't removed yet: keep player
- if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
- mediaEntries.put(key, removed)
- notifyMediaDataLoaded(key, key, removed)
- } else if (removed.active && !isAbleToResume(removed)) {
- // This player was still active - it didn't last long enough to time out,
- // and its app doesn't normally support resume: remove
- if (DEBUG) Log.d(TAG, "Removing still-active player $key")
- notifyMediaDataRemoved(key)
- logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
- } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
- // Convert to resume
- if (DEBUG) {
- Log.d(
- TAG,
- "Notification ($notificationRemoved) and/or session " +
- "($hasSession) gone for inactive player $key"
- )
- }
- convertToResumePlayer(key, removed)
- } else {
- // Retaining players flag is off and app doesn't support resume: remove player.
- if (DEBUG) Log.d(TAG, "Removing player $key")
- notifyMediaDataRemoved(key)
- logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
- }
- }
-
- /** Set the given [MediaData] as a resume state player and notify listeners */
- private fun convertToResumePlayer(key: String, data: MediaData) {
- if (DEBUG) Log.d(TAG, "Converting $key to resume")
- // Resumption controls must have a title.
- if (data.song.isNullOrBlank()) {
- Log.e(TAG, "Description incomplete")
- notifyMediaDataRemoved(key)
- logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
- return
- }
- // Move to resume key (aka package name) if that key doesn't already exist.
- val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) }
- val actions = resumeAction?.let { listOf(resumeAction) } ?: emptyList()
- val launcherIntent =
- context.packageManager.getLaunchIntentForPackage(data.packageName)?.let {
- PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE)
- }
- val lastActive =
- if (data.active) {
- systemClock.elapsedRealtime()
- } else {
- data.lastActive
- }
- val updated =
- data.copy(
- token = null,
- actions = actions,
- semanticActions = MediaButton(playOrPause = resumeAction),
- actionsToShowInCompact = listOf(0),
- active = false,
- resumption = true,
- isPlaying = false,
- isClearable = true,
- clickIntent = launcherIntent,
- lastActive = lastActive,
- )
- val pkg = data.packageName
- val migrate = mediaEntries.put(pkg, updated) == null
- // Notify listeners of "new" controls when migrating or removed and update when not
- Log.d(TAG, "migrating? $migrate from $key -> $pkg")
- if (migrate) {
- notifyMediaDataLoaded(key = pkg, oldKey = key, info = updated)
- } else {
- // Since packageName is used for the key of the resumption controls, it is
- // possible that another notification has already been reused for the resumption
- // controls of this package. In this case, rather than renaming this player as
- // packageName, just remove it and then send a update to the existing resumption
- // controls.
- notifyMediaDataRemoved(key)
- notifyMediaDataLoaded(key = pkg, oldKey = pkg, info = updated)
- }
- logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
-
- // Limit total number of resume controls
- val resumeEntries = mediaEntries.filter { (key, data) -> data.resumption }
- val numResume = resumeEntries.size
- if (numResume > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) {
- resumeEntries
- .toList()
- .sortedBy { (key, data) -> data.lastActive }
- .subList(0, numResume - ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS)
- .forEach { (key, data) ->
- Log.d(TAG, "Removing excess control $key")
- mediaEntries.remove(key)
- notifyMediaDataRemoved(key)
- logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
- }
- }
- }
-
- fun setMediaResumptionEnabled(isEnabled: Boolean) {
- if (useMediaResumption == isEnabled) {
- return
- }
-
- useMediaResumption = isEnabled
-
- if (!useMediaResumption) {
- // Remove any existing resume controls
- val filtered = mediaEntries.filter { !it.value.active }
- filtered.forEach {
- mediaEntries.remove(it.key)
- notifyMediaDataRemoved(it.key)
- logger.logMediaRemoved(it.value.appUid, it.value.packageName, it.value.instanceId)
- }
- }
- }
+ fun setMediaResumptionEnabled(isEnabled: Boolean)
/** Invoked when the user has dismissed the media carousel */
- fun onSwipeToDismiss() = mediaDataFilter.onSwipeToDismiss()
+ fun onSwipeToDismiss()
/** Are there any media notifications active, including the recommendations? */
- fun hasActiveMediaOrRecommendation() = mediaDataFilter.hasActiveMediaOrRecommendation()
+ fun hasActiveMediaOrRecommendation(): Boolean
- /**
- * Are there any media entries we should display, including the recommendations?
- * - If resumption is enabled, this will include inactive players
- * - If resumption is disabled, we only want to show active players
- */
- fun hasAnyMediaOrRecommendation() = mediaDataFilter.hasAnyMediaOrRecommendation()
+ /** Are there any media entries we should display, including the recommendations? */
+ fun hasAnyMediaOrRecommendation(): Boolean
/** Are there any resume media notifications active, excluding the recommendations? */
- fun hasActiveMedia() = mediaDataFilter.hasActiveMedia()
+ fun hasActiveMedia(): Boolean
- /**
- * Are there any resume media notifications active, excluding the recommendations?
- * - If resumption is enabled, this will include inactive players
- * - If resumption is disabled, we only want to show active players
- */
- fun hasAnyMedia() = mediaDataFilter.hasAnyMedia()
+ /** Are there any resume media notifications active, excluding the recommendations? */
+ fun hasAnyMedia(): Boolean
- interface Listener {
+ /** Is recommendation card active? */
+ fun isRecommendationActive(): Boolean
+
+ // Uses [MediaDataProcessor.Listener] in order to link the new logic code with UI layer.
+ interface Listener : MediaDataProcessor.Listener {
/**
* Called whenever there's new MediaData Loaded for the consumption in views.
@@ -1637,13 +113,13 @@
* @param isSsReactivated indicates resume media card is reactivated by Smartspace
* recommendation signal
*/
- fun onMediaDataLoaded(
+ override fun onMediaDataLoaded(
key: String,
oldKey: String?,
data: MediaData,
- immediately: Boolean = true,
- receivedSmartspaceCardLatency: Int = 0,
- isSsReactivated: Boolean = false
+ immediately: Boolean,
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean,
) {}
/**
@@ -1653,14 +129,14 @@
* it will be prioritized as the first card. Otherwise, it will show up as the last card
* as default.
*/
- fun onSmartspaceMediaDataLoaded(
+ override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean = false
+ shouldPrioritize: Boolean,
) {}
/** Called whenever a previously existing Media notification was removed. */
- fun onMediaDataRemoved(key: String) {}
+ override fun onMediaDataRemoved(key: String) {}
/**
* Called whenever a previously existing Smartspace media data was removed.
@@ -1669,78 +145,14 @@
* until the next refresh-round before UI becomes visible. True by default to take in
* place immediately.
*/
- fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) {}
+ override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {}
}
- /**
- * Converts the pass-in SmartspaceTarget to SmartspaceMediaData
- *
- * @return An empty SmartspaceMediaData with the valid target Id is returned if the
- * SmartspaceTarget's data is invalid.
- */
- private fun toSmartspaceMediaData(target: SmartspaceTarget): SmartspaceMediaData {
- val baseAction: SmartspaceAction? = target.baseAction
- val dismissIntent =
- baseAction?.extras?.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent?
+ companion object {
- val isActive =
- when {
- !mediaFlags.isPersistentSsCardEnabled() -> true
- baseAction == null -> true
- else -> {
- val triggerSource = baseAction.extras?.getString(EXTRA_KEY_TRIGGER_SOURCE)
- triggerSource != EXTRA_VALUE_TRIGGER_PERIODIC
- }
- }
-
- packageName(target)?.let {
- return SmartspaceMediaData(
- targetId = target.smartspaceTargetId,
- isActive = isActive,
- packageName = it,
- cardAction = target.baseAction,
- recommendations = target.iconGrid,
- dismissIntent = dismissIntent,
- headphoneConnectionTimeMillis = target.creationTimeMillis,
- instanceId = logger.getNewInstanceId(),
- expiryTimeMs = target.expiryTimeMillis,
- )
- }
- return EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = target.smartspaceTargetId,
- isActive = isActive,
- dismissIntent = dismissIntent,
- headphoneConnectionTimeMillis = target.creationTimeMillis,
- instanceId = logger.getNewInstanceId(),
- expiryTimeMs = target.expiryTimeMillis,
- )
- }
-
- private fun packageName(target: SmartspaceTarget): String? {
- val recommendationList = target.iconGrid
- if (recommendationList == null || recommendationList.isEmpty()) {
- Log.w(TAG, "Empty or null media recommendation list.")
- return null
- }
- for (recommendation in recommendationList) {
- val extras = recommendation.extras
- extras?.let {
- it.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME)?.let { packageName ->
- return packageName
- }
- }
- }
- Log.w(TAG, "No valid package name is provided.")
- return null
- }
-
- override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("internalListeners: $internalListeners")
- println("externalListeners: ${mediaDataFilter.listeners}")
- println("mediaEntries: $mediaEntries")
- println("useMediaResumption: $useMediaResumption")
- println("allowMediaRecommendations: $allowMediaRecommendations")
+ @JvmStatic
+ fun isMediaNotification(sbn: StatusBarNotification): Boolean {
+ return sbn.notification.isMediaNotification()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
new file mode 100644
index 0000000..7412290
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -0,0 +1,1654 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.annotation.SuppressLint
+import android.app.ActivityOptions
+import android.app.BroadcastOptions
+import android.app.Notification
+import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
+import android.app.PendingIntent
+import android.app.StatusBarManager
+import android.app.UriGrantsManager
+import android.app.smartspace.SmartspaceAction
+import android.app.smartspace.SmartspaceConfig
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.BroadcastReceiver
+import android.content.ContentProvider
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.ImageDecoder
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.Icon
+import android.media.MediaDescription
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.net.Uri
+import android.os.Handler
+import android.os.Parcelable
+import android.os.Process
+import android.os.UserHandle
+import android.provider.Settings
+import android.service.notification.StatusBarNotification
+import android.support.v4.media.MediaMetadataCompat
+import android.text.TextUtils
+import android.util.Log
+import android.util.Pair as APair
+import androidx.media.utils.MediaConstants
+import com.android.app.tracing.traceSection
+import com.android.internal.annotations.Keep
+import com.android.internal.logging.InstanceId
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.CoreStartable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.controls.data.repository.MediaDataRepository
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
+import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
+import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
+import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
+import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
+import com.android.systemui.media.controls.shared.model.MediaAction
+import com.android.systemui.media.controls.shared.model.MediaButton
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
+import com.android.systemui.media.controls.ui.view.MediaViewHolder
+import com.android.systemui.media.controls.util.MediaControllerFactory
+import com.android.systemui.media.controls.util.MediaDataUtils
+import com.android.systemui.media.controls.util.MediaFlags
+import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
+import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
+import com.android.systemui.statusbar.notification.row.HybridGroupManager
+import com.android.systemui.util.Assert
+import com.android.systemui.util.Utils
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.ThreadFactory
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import com.android.systemui.util.time.SystemClock
+import java.io.IOException
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+// URI fields to try loading album art from
+private val ART_URIS =
+ arrayOf(
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ MediaMetadata.METADATA_KEY_ART_URI,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
+ )
+
+private const val TAG = "MediaDataProcessor"
+private const val DEBUG = true
+private const val EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY = "dismiss_intent"
+
+/** Processes all media data fields and encapsulates logic for managing media data entries. */
+@SysUISingleton
+class MediaDataProcessor(
+ private val context: Context,
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Background private val backgroundExecutor: Executor,
+ @Main private val uiExecutor: Executor,
+ @Main private val foregroundExecutor: DelayableExecutor,
+ @Main private val handler: Handler,
+ private val mediaControllerFactory: MediaControllerFactory,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val dumpManager: DumpManager,
+ private val activityStarter: ActivityStarter,
+ private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
+ private var useMediaResumption: Boolean,
+ private val useQsMediaPlayer: Boolean,
+ private val systemClock: SystemClock,
+ private val secureSettings: SecureSettings,
+ private val mediaFlags: MediaFlags,
+ private val logger: MediaUiEventLogger,
+ private val smartspaceManager: SmartspaceManager?,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val mediaDataRepository: MediaDataRepository,
+) : CoreStartable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
+
+ companion object {
+ /**
+ * UI surface label for subscribing Smartspace updates. String must match with
+ * [BcSmartspaceDataPlugin.UI_SURFACE_MEDIA]
+ */
+ @JvmField val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
+
+ // Smartspace package name's extra key.
+ @JvmField val EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"
+
+ // Maximum number of actions allowed in compact view
+ @JvmField val MAX_COMPACT_ACTIONS = 3
+
+ /**
+ * Maximum number of actions allowed in expanded view. Number must match with the size of
+ * [MediaViewHolder.genericButtonIds]
+ */
+ @JvmField val MAX_NOTIFICATION_ACTIONS = 5
+ }
+
+ private val themeText =
+ com.android.settingslib.Utils.getColorAttr(
+ context,
+ com.android.internal.R.attr.textColorPrimary
+ )
+ .defaultColor
+
+ // Internal listeners are part of the internal pipeline. External listeners (those registered
+ // with [MediaDeviceManager.addListener]) receive events after they have propagated through
+ // the internal pipeline.
+ // Another way to think of the distinction between internal and external listeners is the
+ // following. Internal listeners are listeners that MediaDataProcessor depends on, and external
+ // listeners are listeners that depend on MediaDataProcessor.
+ private val internalListeners: MutableSet<Listener> = mutableSetOf()
+
+ // There should ONLY be at most one Smartspace media recommendation.
+ @Keep private var smartspaceSession: SmartspaceSession? = null
+ private var allowMediaRecommendations = false
+
+ private val artworkWidth =
+ context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize
+ )
+ private val artworkHeight =
+ context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
+
+ @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
+ private val statusBarManager =
+ context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager
+
+ /** Check whether this notification is an RCN */
+ private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
+ return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
+ }
+
+ @Inject
+ constructor(
+ context: Context,
+ @Application applicationScope: CoroutineScope,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ threadFactory: ThreadFactory,
+ @Main uiExecutor: Executor,
+ @Main foregroundExecutor: DelayableExecutor,
+ @Main handler: Handler,
+ mediaControllerFactory: MediaControllerFactory,
+ dumpManager: DumpManager,
+ broadcastDispatcher: BroadcastDispatcher,
+ activityStarter: ActivityStarter,
+ smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
+ clock: SystemClock,
+ secureSettings: SecureSettings,
+ mediaFlags: MediaFlags,
+ logger: MediaUiEventLogger,
+ smartspaceManager: SmartspaceManager?,
+ keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ mediaDataRepository: MediaDataRepository,
+ ) : this(
+ context,
+ applicationScope,
+ backgroundDispatcher,
+ // Loading bitmap for UMO background can take longer time, so it cannot run on the default
+ // background thread. Use a custom thread for media.
+ threadFactory.buildExecutorOnNewThread(TAG),
+ uiExecutor,
+ foregroundExecutor,
+ handler,
+ mediaControllerFactory,
+ broadcastDispatcher,
+ dumpManager,
+ activityStarter,
+ smartspaceMediaDataProvider,
+ Utils.useMediaResumption(context),
+ Utils.useQsMediaPlayer(context),
+ clock,
+ secureSettings,
+ mediaFlags,
+ logger,
+ smartspaceManager,
+ keyguardUpdateMonitor,
+ mediaDataRepository,
+ )
+
+ private val appChangeReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_PACKAGES_SUSPENDED -> {
+ val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ packages?.forEach { removeAllForPackage(it) }
+ }
+ Intent.ACTION_PACKAGE_REMOVED,
+ Intent.ACTION_PACKAGE_RESTARTED -> {
+ intent.data?.encodedSchemeSpecificPart?.let { removeAllForPackage(it) }
+ }
+ }
+ }
+ }
+
+ override fun start() {
+ if (!mediaFlags.isMediaControlsRefactorEnabled()) {
+ return
+ }
+
+ dumpManager.registerNormalDumpable(TAG, this)
+
+ val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
+ broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
+
+ val uninstallFilter =
+ IntentFilter().apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_RESTARTED)
+ addDataScheme("package")
+ }
+ // BroadcastDispatcher does not allow filters with data schemes
+ context.registerReceiver(appChangeReceiver, uninstallFilter)
+
+ // Register for Smartspace data updates.
+ smartspaceMediaDataProvider.registerListener(this)
+ smartspaceSession =
+ smartspaceManager?.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build()
+ )
+ smartspaceSession?.let {
+ it.addOnTargetsAvailableListener(
+ // Use a main uiExecutor thread listening to Smartspace updates instead of using
+ // the existing background executor.
+ // SmartspaceSession has scheduled routine updates which can be unpredictable on
+ // test simulators, using the backgroundExecutor makes it's hard to test the threads
+ // numbers.
+ uiExecutor
+ ) { targets ->
+ smartspaceMediaDataProvider.onTargetsAvailable(targets)
+ }
+ }
+ smartspaceSession?.requestSmartspaceUpdate()
+
+ // Track media controls recommendation setting.
+ applicationScope.launch { trackMediaControlsRecommendationSetting() }
+ }
+
+ fun destroy() {
+ smartspaceMediaDataProvider.unregisterListener(this)
+ smartspaceSession?.close()
+ smartspaceSession = null
+ context.unregisterReceiver(appChangeReceiver)
+ internalListeners.clear()
+ }
+
+ fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
+ if (useQsMediaPlayer && isMediaNotification(sbn)) {
+ var isNewlyActiveEntry = false
+ Assert.isMainThread()
+ val oldKey = findExistingEntry(key, sbn.packageName)
+ if (oldKey == null) {
+ val instanceId = logger.getNewInstanceId()
+ val temp =
+ MediaData()
+ .copy(
+ packageName = sbn.packageName,
+ instanceId = instanceId,
+ createdTimestampMillis = systemClock.currentTimeMillis(),
+ )
+ mediaDataRepository.addMediaEntry(key, temp)
+ isNewlyActiveEntry = true
+ } else if (oldKey != key) {
+ // Resume -> active conversion; move to new key
+ val oldData = mediaDataRepository.removeMediaEntry(oldKey)!!
+ isNewlyActiveEntry = true
+ mediaDataRepository.addMediaEntry(key, oldData)
+ }
+ loadMediaData(key, sbn, oldKey, isNewlyActiveEntry)
+ } else {
+ onNotificationRemoved(key)
+ }
+ }
+
+ /**
+ * Allow recommendations from smartspace to show in media controls. Requires
+ * [Utils.useQsMediaPlayer] to be enabled. On by default, but can be disabled by setting to 0
+ */
+ private suspend fun allowMediaRecommendations(): Boolean {
+ return withContext(backgroundDispatcher) {
+ val flag =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ true,
+ UserHandle.USER_CURRENT
+ )
+
+ useQsMediaPlayer && flag
+ }
+ }
+
+ private suspend fun trackMediaControlsRecommendationSetting() {
+ secureSettings
+ .observerFlow(UserHandle.USER_ALL, Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION)
+ // perform a query at the beginning.
+ .onStart { emit(Unit) }
+ .map { allowMediaRecommendations() }
+ .distinctUntilChanged()
+ // only track the most recent emission
+ .collectLatest {
+ allowMediaRecommendations = it
+ if (!allowMediaRecommendations) {
+ dismissSmartspaceRecommendation(
+ key = mediaDataRepository.smartspaceMediaData.value.targetId,
+ delay = 0L
+ )
+ }
+ }
+ }
+
+ private fun removeAllForPackage(packageName: String) {
+ Assert.isMainThread()
+ val toRemove =
+ mediaDataRepository.mediaEntries.value.filter { it.value.packageName == packageName }
+ toRemove.forEach { removeEntry(it.key) }
+ }
+
+ fun setResumeAction(key: String, action: Runnable?) {
+ mediaDataRepository.mediaEntries.value.get(key)?.let {
+ it.resumeAction = action
+ it.hasCheckedForResume = true
+ }
+ }
+
+ fun addResumptionControls(
+ userId: Int,
+ desc: MediaDescription,
+ action: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ // Resume controls don't have a notification key, so store by package name instead
+ if (!mediaDataRepository.mediaEntries.value.containsKey(packageName)) {
+ val instanceId = logger.getNewInstanceId()
+ val appUid =
+ try {
+ context.packageManager.getApplicationInfo(packageName, 0).uid
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app UID for $packageName", e)
+ Process.INVALID_UID
+ }
+
+ val resumeData =
+ MediaData()
+ .copy(
+ packageName = packageName,
+ resumeAction = action,
+ hasCheckedForResume = true,
+ instanceId = instanceId,
+ appUid = appUid,
+ createdTimestampMillis = systemClock.currentTimeMillis(),
+ )
+ mediaDataRepository.addMediaEntry(packageName, resumeData)
+ logSingleVsMultipleMediaAdded(appUid, packageName, instanceId)
+ logger.logResumeMediaAdded(appUid, packageName, instanceId)
+ }
+ backgroundExecutor.execute {
+ loadMediaDataInBgForResumption(
+ userId,
+ desc,
+ action,
+ token,
+ appName,
+ appIntent,
+ packageName
+ )
+ }
+ }
+
+ /**
+ * Check if there is an existing entry that matches the key or package name. Returns the key
+ * that matches, or null if not found.
+ */
+ private fun findExistingEntry(key: String, packageName: String): String? {
+ val mediaEntries = mediaDataRepository.mediaEntries.value
+ if (mediaEntries.containsKey(key)) {
+ return key
+ }
+ // Check if we already had a resume player
+ if (mediaEntries.containsKey(packageName)) {
+ return packageName
+ }
+ return null
+ }
+
+ private fun loadMediaData(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?,
+ isNewlyActiveEntry: Boolean = false,
+ ) {
+ backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, isNewlyActiveEntry) }
+ }
+
+ /** Add a listener for internal events. */
+ fun addInternalListener(listener: Listener) = internalListeners.add(listener)
+
+ /**
+ * Notify internal listeners of media loaded event.
+ *
+ * External listeners registered with [MediaCarouselInteractor.addListener] will be notified
+ * after the event propagates through the internal listener pipeline.
+ */
+ private fun notifyMediaDataLoaded(key: String, oldKey: String?, info: MediaData) {
+ internalListeners.forEach { it.onMediaDataLoaded(key, oldKey, info) }
+ }
+
+ /**
+ * Notify internal listeners of Smartspace media loaded event.
+ *
+ * External listeners registered with [MediaCarouselInteractor.addListener] will be notified
+ * after the event propagates through the internal listener pipeline.
+ */
+ private fun notifySmartspaceMediaDataLoaded(key: String, info: SmartspaceMediaData) {
+ internalListeners.forEach { it.onSmartspaceMediaDataLoaded(key, info) }
+ }
+
+ /**
+ * Notify internal listeners of media removed event.
+ *
+ * External listeners registered with [MediaCarouselInteractor.addListener] will be notified
+ * after the event propagates through the internal listener pipeline.
+ */
+ private fun notifyMediaDataRemoved(key: String) {
+ internalListeners.forEach { it.onMediaDataRemoved(key) }
+ }
+
+ /**
+ * Notify internal listeners of Smartspace media removed event.
+ *
+ * External listeners registered with [MediaCarouselInteractor.addListener] will be notified
+ * after the event propagates through the internal listener pipeline.
+ *
+ * @param immediately indicates should apply the UI changes immediately, otherwise wait until
+ * the next refresh-round before UI becomes visible. Should only be true if the update is
+ * initiated by user's interaction.
+ */
+ private fun notifySmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
+ internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
+ }
+
+ /**
+ * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
+ * will make the player not active anymore, hiding it from QQS and Keyguard.
+ *
+ * @see MediaData.active
+ */
+ fun setInactive(key: String, timedOut: Boolean, forceUpdate: Boolean = false) {
+ mediaDataRepository.mediaEntries.value[key]?.let {
+ if (timedOut && !forceUpdate) {
+ // Only log this event when media expires on its own
+ logger.logMediaTimeout(it.appUid, it.packageName, it.instanceId)
+ }
+ if (it.active == !timedOut && !forceUpdate) {
+ if (it.resumption) {
+ if (DEBUG) Log.d(TAG, "timing out resume player $key")
+ dismissMediaData(key, 0L /* delay */)
+ }
+ return
+ }
+ // Update last active if media was still active.
+ if (it.active) {
+ it.lastActive = systemClock.elapsedRealtime()
+ }
+ it.active = !timedOut
+ if (DEBUG) Log.d(TAG, "Updating $key timedOut: $timedOut")
+ onMediaDataLoaded(key, key, it)
+ }
+
+ if (key == mediaDataRepository.smartspaceMediaData.value.targetId) {
+ if (DEBUG) Log.d(TAG, "smartspace card expired")
+ dismissSmartspaceRecommendation(key, delay = 0L)
+ }
+ }
+
+ /** Called when the player's [PlaybackState] has been updated with new actions and/or state */
+ internal fun updateState(key: String, state: PlaybackState) {
+ mediaDataRepository.mediaEntries.value.get(key)?.let {
+ val token = it.token
+ if (token == null) {
+ if (DEBUG) Log.d(TAG, "State updated, but token was null")
+ return
+ }
+ val actions =
+ createActionsFromState(
+ it.packageName,
+ mediaControllerFactory.create(it.token),
+ UserHandle(it.userId)
+ )
+
+ // Control buttons
+ // If flag is enabled and controller has a PlaybackState,
+ // create actions from session info
+ // otherwise, no need to update semantic actions.
+ val data =
+ if (actions != null) {
+ it.copy(semanticActions = actions, isPlaying = isPlayingState(state.state))
+ } else {
+ it.copy(isPlaying = isPlayingState(state.state))
+ }
+ if (DEBUG) Log.d(TAG, "State updated outside of notification")
+ onMediaDataLoaded(key, key, data)
+ }
+ }
+
+ private fun removeEntry(key: String, logEvent: Boolean = true) {
+ mediaDataRepository.removeMediaEntry(key)?.let {
+ if (logEvent) {
+ logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
+ }
+ }
+ notifyMediaDataRemoved(key)
+ }
+
+ /** Dismiss a media entry. Returns false if the key was not found. */
+ fun dismissMediaData(key: String, delay: Long): Boolean {
+ val existed = mediaDataRepository.mediaEntries.value[key] != null
+ backgroundExecutor.execute {
+ mediaDataRepository.mediaEntries.value[key]?.let { mediaData ->
+ if (mediaData.isLocalSession()) {
+ mediaData.token?.let {
+ val mediaController = mediaControllerFactory.create(it)
+ mediaController.transportControls.stop()
+ }
+ }
+ }
+ }
+ foregroundExecutor.executeDelayed({ removeEntry(key) }, delay)
+ return existed
+ }
+
+ /**
+ * Called whenever the recommendation has been expired or removed by the user. This will remove
+ * the recommendation card entirely from the carousel.
+ */
+ fun dismissSmartspaceRecommendation(key: String, delay: Long) {
+ if (mediaDataRepository.dismissSmartspaceRecommendation(key)) {
+ foregroundExecutor.executeDelayed(
+ { notifySmartspaceMediaDataRemoved(key, immediately = true) },
+ delay
+ )
+ }
+ }
+
+ /** Called when the recommendation card should no longer be visible in QQS or lockscreen */
+ fun setRecommendationInactive(key: String) {
+ if (mediaDataRepository.setRecommendationInactive(key)) {
+ val recommendation = mediaDataRepository.smartspaceMediaData.value
+ notifySmartspaceMediaDataLoaded(recommendation.targetId, recommendation)
+ }
+ }
+
+ private fun loadMediaDataInBgForResumption(
+ userId: Int,
+ desc: MediaDescription,
+ resumeAction: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ if (desc.title.isNullOrBlank()) {
+ Log.e(TAG, "Description incomplete")
+ // Delete the placeholder entry
+ mediaDataRepository.removeMediaEntry(packageName)
+ return
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "adding track for $userId from browser: $desc")
+ }
+
+ val currentEntry = mediaDataRepository.mediaEntries.value.get(packageName)
+ val appUid = currentEntry?.appUid ?: Process.INVALID_UID
+
+ // Album art
+ var artworkBitmap = desc.iconBitmap
+ if (artworkBitmap == null && desc.iconUri != null) {
+ artworkBitmap = loadBitmapFromUriForUser(desc.iconUri!!, userId, appUid, packageName)
+ }
+ val artworkIcon =
+ if (artworkBitmap != null) {
+ Icon.createWithBitmap(artworkBitmap)
+ } else {
+ null
+ }
+
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val isExplicit =
+ desc.extras?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+
+ val progress =
+ if (mediaFlags.isResumeProgressEnabled()) {
+ MediaDataUtils.getDescriptionProgress(desc.extras)
+ } else null
+
+ val mediaAction = getResumeMediaAction(resumeAction)
+ val lastActive = systemClock.elapsedRealtime()
+ val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
+ foregroundExecutor.execute {
+ onMediaDataLoaded(
+ packageName,
+ null,
+ MediaData(
+ userId,
+ true,
+ appName,
+ null,
+ desc.subtitle,
+ desc.title,
+ artworkIcon,
+ listOf(mediaAction),
+ listOf(0),
+ MediaButton(playOrPause = mediaAction),
+ packageName,
+ token,
+ appIntent,
+ device = null,
+ active = false,
+ resumeAction = resumeAction,
+ resumption = true,
+ notificationKey = packageName,
+ hasCheckedForResume = true,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = appUid,
+ isExplicit = isExplicit,
+ resumeProgress = progress,
+ )
+ )
+ }
+ }
+
+ fun loadMediaDataInBg(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?,
+ isNewlyActiveEntry: Boolean = false,
+ ) {
+ val token =
+ sbn.notification.extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION,
+ MediaSession.Token::class.java
+ )
+ if (token == null) {
+ return
+ }
+ val mediaController = mediaControllerFactory.create(token)
+ val metadata = mediaController.metadata
+ val notif: Notification = sbn.notification
+
+ val appInfo =
+ notif.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ )
+ ?: getAppInfoFromPackage(sbn.packageName)
+
+ // App name
+ val appName = getAppName(sbn, appInfo)
+
+ // Song name
+ var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
+ if (song.isNullOrBlank()) {
+ song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
+ }
+ if (song.isNullOrBlank()) {
+ song = HybridGroupManager.resolveTitle(notif)
+ }
+ if (song.isNullOrBlank()) {
+ // For apps that don't include a title, log and add a placeholder
+ song = context.getString(R.string.controls_media_empty_title, appName)
+ try {
+ statusBarManager.logBlankMediaTitle(sbn.packageName, sbn.user.identifier)
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Error reporting blank media title for package ${sbn.packageName}")
+ }
+ }
+
+ // Album art
+ var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
+ if (artworkBitmap == null) {
+ artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
+ }
+ if (artworkBitmap == null) {
+ artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
+ }
+ val artWorkIcon =
+ if (artworkBitmap == null) {
+ notif.getLargeIcon()
+ } else {
+ Icon.createWithBitmap(artworkBitmap)
+ }
+
+ // App Icon
+ val smallIcon = sbn.notification.smallIcon
+
+ // Explicit Indicator
+ val isExplicit: Boolean
+ val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
+ isExplicit =
+ mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+
+ // Artist name
+ var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
+ if (artist.isNullOrBlank()) {
+ artist = HybridGroupManager.resolveText(notif)
+ }
+
+ // Device name (used for remote cast notifications)
+ var device: MediaDeviceData? = null
+ if (isRemoteCastNotification(sbn)) {
+ val extras = sbn.notification.extras
+ val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
+ val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
+ val deviceIntent =
+ extras.getParcelable(
+ Notification.EXTRA_MEDIA_REMOTE_INTENT,
+ PendingIntent::class.java
+ )
+ Log.d(TAG, "$key is RCN for $deviceName")
+
+ if (deviceName != null && deviceIcon > -1) {
+ // Name and icon must be present, but intent may be null
+ val enabled = deviceIntent != null && deviceIntent.isActivity
+ val deviceDrawable =
+ Icon.createWithResource(sbn.packageName, deviceIcon)
+ .loadDrawable(sbn.getPackageContext(context))
+ device =
+ MediaDeviceData(
+ enabled,
+ deviceDrawable,
+ deviceName,
+ deviceIntent,
+ showBroadcastButton = false
+ )
+ }
+ }
+
+ // Control buttons
+ // If flag is enabled and controller has a PlaybackState, create actions from session info
+ // Otherwise, use the notification actions
+ var actionIcons: List<MediaAction> = emptyList()
+ var actionsToShowCollapsed: List<Int> = emptyList()
+ val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
+ if (semanticActions == null) {
+ val actions = createActionsFromNotification(sbn)
+ actionIcons = actions.first
+ actionsToShowCollapsed = actions.second
+ }
+
+ val playbackLocation =
+ if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
+ else if (
+ mediaController.playbackInfo?.playbackType ==
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
+ )
+ MediaData.PLAYBACK_LOCAL
+ else MediaData.PLAYBACK_CAST_LOCAL
+ val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) }
+
+ val currentEntry = mediaDataRepository.mediaEntries.value.get(key)
+ val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val appUid = appInfo?.uid ?: Process.INVALID_UID
+
+ if (isNewlyActiveEntry) {
+ logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId)
+ logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
+ } else if (playbackLocation != currentEntry?.playbackLocation) {
+ logger.logPlaybackLocationChange(appUid, sbn.packageName, instanceId, playbackLocation)
+ }
+
+ val lastActive = systemClock.elapsedRealtime()
+ val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
+ foregroundExecutor.execute {
+ val resumeAction: Runnable? = mediaDataRepository.mediaEntries.value[key]?.resumeAction
+ val hasCheckedForResume =
+ mediaDataRepository.mediaEntries.value[key]?.hasCheckedForResume == true
+ val active = mediaDataRepository.mediaEntries.value[key]?.active ?: true
+ onMediaDataLoaded(
+ key,
+ oldKey,
+ MediaData(
+ sbn.normalizedUserId,
+ true,
+ appName,
+ smallIcon,
+ artist,
+ song,
+ artWorkIcon,
+ actionIcons,
+ actionsToShowCollapsed,
+ semanticActions,
+ sbn.packageName,
+ token,
+ notif.contentIntent,
+ device,
+ active,
+ resumeAction = resumeAction,
+ playbackLocation = playbackLocation,
+ notificationKey = key,
+ hasCheckedForResume = hasCheckedForResume,
+ isPlaying = isPlaying,
+ isClearable = !sbn.isOngoing,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = appUid,
+ isExplicit = isExplicit,
+ )
+ )
+ }
+ }
+
+ private fun logSingleVsMultipleMediaAdded(
+ appUid: Int,
+ packageName: String,
+ instanceId: InstanceId
+ ) {
+ if (mediaDataRepository.mediaEntries.value.size == 1) {
+ logger.logSingleMediaPlayerInCarousel(appUid, packageName, instanceId)
+ } else if (mediaDataRepository.mediaEntries.value.size == 2) {
+ // Since this method is only called when there is a new media session added.
+ // logging needed once there is more than one media session in carousel.
+ logger.logMultipleMediaPlayersInCarousel(appUid, packageName, instanceId)
+ }
+ }
+
+ private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
+ try {
+ return context.packageManager.getApplicationInfo(packageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app info for $packageName", e)
+ }
+ return null
+ }
+
+ private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
+ val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
+ if (name != null) {
+ return name
+ }
+
+ return if (appInfo != null) {
+ context.packageManager.getApplicationLabel(appInfo).toString()
+ } else {
+ sbn.packageName
+ }
+ }
+
+ /** Generate action buttons based on notification actions */
+ private fun createActionsFromNotification(
+ sbn: StatusBarNotification
+ ): Pair<List<MediaAction>, List<Int>> {
+ val notif = sbn.notification
+ val actionIcons: MutableList<MediaAction> = ArrayList()
+ val actions = notif.actions
+ var actionsToShowCollapsed =
+ notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList()
+ ?: mutableListOf()
+ if (actionsToShowCollapsed.size > MAX_COMPACT_ACTIONS) {
+ Log.e(
+ TAG,
+ "Too many compact actions for ${sbn.key}," +
+ "limiting to first $MAX_COMPACT_ACTIONS"
+ )
+ actionsToShowCollapsed = actionsToShowCollapsed.subList(0, MAX_COMPACT_ACTIONS)
+ }
+
+ if (actions != null) {
+ for ((index, action) in actions.withIndex()) {
+ if (index == MAX_NOTIFICATION_ACTIONS) {
+ Log.w(
+ TAG,
+ "Too many notification actions for ${sbn.key}," +
+ " limiting to first $MAX_NOTIFICATION_ACTIONS"
+ )
+ break
+ }
+ if (action.getIcon() == null) {
+ if (DEBUG) Log.i(TAG, "No icon for action $index ${action.title}")
+ actionsToShowCollapsed.remove(index)
+ continue
+ }
+ val runnable =
+ if (action.actionIntent != null) {
+ Runnable {
+ if (action.actionIntent.isActivity) {
+ activityStarter.startPendingIntentDismissingKeyguard(
+ action.actionIntent
+ )
+ } else if (action.isAuthenticationRequired()) {
+ activityStarter.dismissKeyguardThenExecute(
+ {
+ var result = sendPendingIntent(action.actionIntent)
+ result
+ },
+ {},
+ true
+ )
+ } else {
+ sendPendingIntent(action.actionIntent)
+ }
+ }
+ } else {
+ null
+ }
+ val mediaActionIcon =
+ if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
+ Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
+ } else {
+ action.getIcon()
+ }
+ .setTint(themeText)
+ .loadDrawable(context)
+ val mediaAction = MediaAction(mediaActionIcon, runnable, action.title, null)
+ actionIcons.add(mediaAction)
+ }
+ }
+ return Pair(actionIcons, actionsToShowCollapsed)
+ }
+
+ /**
+ * Generates action button info for this media session based on the PlaybackState
+ *
+ * @param packageName Package name for the media app
+ * @param controller MediaController for the current session
+ * @return a Pair consisting of a list of media actions, and a list of ints representing which
+ *
+ * ```
+ * of those actions should be shown in the compact player
+ * ```
+ */
+ private fun createActionsFromState(
+ packageName: String,
+ controller: MediaController,
+ user: UserHandle
+ ): MediaButton? {
+ val state = controller.playbackState
+ if (state == null || !mediaFlags.areMediaSessionActionsEnabled(packageName, user)) {
+ return null
+ }
+
+ // First, check for standard actions
+ val playOrPause =
+ if (isConnectingState(state.state)) {
+ // Spinner needs to be animating to render anything. Start it here.
+ val drawable =
+ context.getDrawable(com.android.internal.R.drawable.progress_small_material)
+ (drawable as Animatable).start()
+ MediaAction(
+ drawable,
+ null, // no action to perform when clicked
+ context.getString(R.string.controls_media_button_connecting),
+ context.getDrawable(R.drawable.ic_media_connecting_container),
+ // Specify a rebind id to prevent the spinner from restarting on later binds.
+ com.android.internal.R.drawable.progress_small_material
+ )
+ } else if (isPlayingState(state.state)) {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
+ } else {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
+ }
+ val prevButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_PREVIOUS)
+ val nextButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_NEXT)
+
+ // Then, create a way to build any custom actions that will be needed
+ val customActions =
+ state.customActions
+ .asSequence()
+ .filterNotNull()
+ .map { getCustomAction(packageName, controller, it) }
+ .iterator()
+ fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
+
+ // Finally, assign the remaining button slots: play/pause A B C D
+ // A = previous, else custom action (if not reserved)
+ // B = next, else custom action (if not reserved)
+ // C and D are always custom actions
+ val reservePrev =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ ) == true
+ val reserveNext =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ ) == true
+
+ val prevOrCustom =
+ if (prevButton != null) {
+ prevButton
+ } else if (!reservePrev) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ val nextOrCustom =
+ if (nextButton != null) {
+ nextButton
+ } else if (!reserveNext) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ return MediaButton(
+ playOrPause,
+ nextOrCustom,
+ prevOrCustom,
+ nextCustomAction(),
+ nextCustomAction(),
+ reserveNext,
+ reservePrev
+ )
+ }
+
+ /**
+ * Create a [MediaAction] for a given action and media session
+ *
+ * @param controller MediaController for the session
+ * @param stateActions The actions included with the session's [PlaybackState]
+ * @param action A [PlaybackState.Actions] value representing what action to generate. One of:
+ * ```
+ * [PlaybackState.ACTION_PLAY]
+ * [PlaybackState.ACTION_PAUSE]
+ * [PlaybackState.ACTION_SKIP_TO_PREVIOUS]
+ * [PlaybackState.ACTION_SKIP_TO_NEXT]
+ * @return
+ * ```
+ *
+ * A [MediaAction] with correct values set, or null if the state doesn't support it
+ */
+ private fun getStandardAction(
+ controller: MediaController,
+ stateActions: Long,
+ @PlaybackState.Actions action: Long
+ ): MediaAction? {
+ if (!includesAction(stateActions, action)) {
+ return null
+ }
+
+ return when (action) {
+ PlaybackState.ACTION_PLAY -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_play),
+ { controller.transportControls.play() },
+ context.getString(R.string.controls_media_button_play),
+ context.getDrawable(R.drawable.ic_media_play_container)
+ )
+ }
+ PlaybackState.ACTION_PAUSE -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_pause),
+ { controller.transportControls.pause() },
+ context.getString(R.string.controls_media_button_pause),
+ context.getDrawable(R.drawable.ic_media_pause_container)
+ )
+ }
+ PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_prev),
+ { controller.transportControls.skipToPrevious() },
+ context.getString(R.string.controls_media_button_prev),
+ null
+ )
+ }
+ PlaybackState.ACTION_SKIP_TO_NEXT -> {
+ MediaAction(
+ context.getDrawable(R.drawable.ic_media_next),
+ { controller.transportControls.skipToNext() },
+ context.getString(R.string.controls_media_button_next),
+ null
+ )
+ }
+ else -> null
+ }
+ }
+
+ /** Check whether the actions from a [PlaybackState] include a specific action */
+ private fun includesAction(stateActions: Long, @PlaybackState.Actions action: Long): Boolean {
+ if (
+ (action == PlaybackState.ACTION_PLAY || action == PlaybackState.ACTION_PAUSE) &&
+ (stateActions and PlaybackState.ACTION_PLAY_PAUSE > 0L)
+ ) {
+ return true
+ }
+ return (stateActions and action != 0L)
+ }
+
+ /** Get a [MediaAction] representing a [PlaybackState.CustomAction] */
+ private fun getCustomAction(
+ packageName: String,
+ controller: MediaController,
+ customAction: PlaybackState.CustomAction
+ ): MediaAction {
+ return MediaAction(
+ Icon.createWithResource(packageName, customAction.icon).loadDrawable(context),
+ { controller.transportControls.sendCustomAction(customAction, customAction.extras) },
+ customAction.name,
+ null
+ )
+ }
+
+ /** Load a bitmap from the various Art metadata URIs */
+ private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
+ for (uri in ART_URIS) {
+ val uriString = metadata.getString(uri)
+ if (!TextUtils.isEmpty(uriString)) {
+ val albumArt = loadBitmapFromUri(Uri.parse(uriString))
+ if (albumArt != null) {
+ if (DEBUG) Log.d(TAG, "loaded art from $uri")
+ return albumArt
+ }
+ }
+ }
+ return null
+ }
+
+ private fun sendPendingIntent(intent: PendingIntent): Boolean {
+ return try {
+ val options = BroadcastOptions.makeBasic()
+ options.setInteractive(true)
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
+ intent.send(options.toBundle())
+ true
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ false
+ }
+ }
+
+ /** Returns a bitmap if the user can access the given URI, else null */
+ private fun loadBitmapFromUriForUser(
+ uri: Uri,
+ userId: Int,
+ appUid: Int,
+ packageName: String,
+ ): Bitmap? {
+ try {
+ val ugm = UriGrantsManager.getService()
+ ugm.checkGrantUriPermission_ignoreNonSystem(
+ appUid,
+ packageName,
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ ContentProvider.getUserIdFromUri(uri, userId)
+ )
+ return loadBitmapFromUri(uri)
+ } catch (e: SecurityException) {
+ Log.e(TAG, "Failed to get URI permission: $e")
+ }
+ return null
+ }
+
+ /**
+ * Load a bitmap from a URI
+ *
+ * @param uri the uri to load
+ * @return bitmap, or null if couldn't be loaded
+ */
+ private fun loadBitmapFromUri(uri: Uri): Bitmap? {
+ // ImageDecoder requires a scheme of the following types
+ if (uri.scheme == null) {
+ return null
+ }
+
+ if (
+ !uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE) &&
+ !uri.scheme.equals(ContentResolver.SCHEME_FILE)
+ ) {
+ return null
+ }
+
+ val source = ImageDecoder.createSource(context.contentResolver, uri)
+ return try {
+ ImageDecoder.decodeBitmap(source) { decoder, info, _ ->
+ val width = info.size.width
+ val height = info.size.height
+ val scale =
+ MediaDataUtils.getScaleFactor(
+ APair(width, height),
+ APair(artworkWidth, artworkHeight)
+ )
+
+ // Downscale if needed
+ if (scale != 0f && scale < 1) {
+ decoder.setTargetSize((scale * width).toInt(), (scale * height).toInt())
+ }
+ decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
+ }
+ } catch (e: IOException) {
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ }
+ }
+
+ private fun getResumeMediaAction(action: Runnable): MediaAction {
+ return MediaAction(
+ Icon.createWithResource(context, R.drawable.ic_media_play)
+ .setTint(themeText)
+ .loadDrawable(context),
+ action,
+ context.getString(R.string.controls_media_resume),
+ context.getDrawable(R.drawable.ic_media_play_container)
+ )
+ }
+
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) =
+ traceSection("MediaDataProcessor#onMediaDataLoaded") {
+ Assert.isMainThread()
+ if (mediaDataRepository.mediaEntries.value.containsKey(key)) {
+ // Otherwise this was removed already
+ mediaDataRepository.addMediaEntry(key, data)
+ notifyMediaDataLoaded(key, oldKey, data)
+ }
+ }
+
+ override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
+ if (!allowMediaRecommendations) {
+ if (DEBUG) Log.d(TAG, "Smartspace recommendation is disabled in Settings.")
+ return
+ }
+
+ val mediaTargets = targets.filterIsInstance<SmartspaceTarget>()
+ val smartspaceMediaData = mediaDataRepository.smartspaceMediaData.value
+ when (mediaTargets.size) {
+ 0 -> {
+ if (!smartspaceMediaData.isActive) {
+ return
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Set Smartspace media to be inactive for the data update")
+ }
+ if (mediaFlags.isPersistentSsCardEnabled()) {
+ // Smartspace uses this signal to hide the card (e.g. when it expires or user
+ // disconnects headphones), so treat as setting inactive when flag is on
+ val recommendation = smartspaceMediaData.copy(isActive = false)
+ mediaDataRepository.setRecommendation(recommendation)
+ notifySmartspaceMediaDataLoaded(recommendation.targetId, recommendation)
+ } else {
+ notifySmartspaceMediaDataRemoved(
+ smartspaceMediaData.targetId,
+ immediately = false
+ )
+ mediaDataRepository.setRecommendation(
+ SmartspaceMediaData(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId,
+ )
+ )
+ }
+ }
+ 1 -> {
+ val newMediaTarget = mediaTargets.get(0)
+ if (smartspaceMediaData.targetId == newMediaTarget.smartspaceTargetId) {
+ // The same Smartspace updates can be received. Skip the duplicate updates.
+ return
+ }
+ if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.")
+ val recommendation = toSmartspaceMediaData(newMediaTarget)
+ mediaDataRepository.setRecommendation(recommendation)
+ notifySmartspaceMediaDataLoaded(recommendation.targetId, recommendation)
+ }
+ else -> {
+ // There should NOT be more than 1 Smartspace media update. When it happens, it
+ // indicates a bad state or an error. Reset the status accordingly.
+ Log.wtf(TAG, "More than 1 Smartspace Media Update. Resetting the status...")
+ notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = false)
+ mediaDataRepository.setRecommendation(SmartspaceMediaData())
+ }
+ }
+ }
+
+ fun onNotificationRemoved(key: String) {
+ Assert.isMainThread()
+ val removed = mediaDataRepository.removeMediaEntry(key) ?: return
+ if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ } else if (isAbleToResume(removed)) {
+ convertToResumePlayer(key, removed)
+ } else if (mediaFlags.isRetainingPlayersEnabled()) {
+ handlePossibleRemoval(key, removed, notificationRemoved = true)
+ } else {
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ }
+ }
+
+ internal fun onSessionDestroyed(key: String) {
+ if (DEBUG) Log.d(TAG, "session destroyed for $key")
+ val entry = mediaDataRepository.removeMediaEntry(key) ?: return
+ // Clear token since the session is no longer valid
+ val updated = entry.copy(token = null)
+ handlePossibleRemoval(key, updated)
+ }
+
+ private fun isAbleToResume(data: MediaData): Boolean {
+ val isEligibleForResume =
+ data.isLocalSession() ||
+ (mediaFlags.isRemoteResumeAllowed() &&
+ data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
+ return useMediaResumption && data.resumeAction != null && isEligibleForResume
+ }
+
+ /**
+ * Convert to resume state if the player is no longer valid and active, then notify listeners
+ * that the data was updated. Does not convert to resume state if the player is still valid, or
+ * if it was removed before becoming inactive. (Assumes that [removed] was removed from
+ * [mediaDataRepository.mediaEntries] state before this function was called)
+ */
+ private fun handlePossibleRemoval(
+ key: String,
+ removed: MediaData,
+ notificationRemoved: Boolean = false
+ ) {
+ val hasSession = removed.token != null
+ if (hasSession && removed.semanticActions != null) {
+ // The app was using session actions, and the session is still valid: keep player
+ if (DEBUG) Log.d(TAG, "Notification removed but using session actions $key")
+ mediaDataRepository.addMediaEntry(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (!notificationRemoved && removed.semanticActions == null) {
+ // The app was using notification actions, and notif wasn't removed yet: keep player
+ if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
+ mediaDataRepository.addMediaEntry(key, removed)
+ notifyMediaDataLoaded(key, key, removed)
+ } else if (removed.active && !isAbleToResume(removed)) {
+ // This player was still active - it didn't last long enough to time out,
+ // and its app doesn't normally support resume: remove
+ if (DEBUG) Log.d(TAG, "Removing still-active player $key")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ } else if (mediaFlags.isRetainingPlayersEnabled() || isAbleToResume(removed)) {
+ // Convert to resume
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Notification ($notificationRemoved) and/or session " +
+ "($hasSession) gone for inactive player $key"
+ )
+ }
+ convertToResumePlayer(key, removed)
+ } else {
+ // Retaining players flag is off and app doesn't support resume: remove player.
+ if (DEBUG) Log.d(TAG, "Removing player $key")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
+ }
+ }
+
+ /** Set the given [MediaData] as a resume state player and notify listeners */
+ private fun convertToResumePlayer(key: String, data: MediaData) {
+ if (DEBUG) Log.d(TAG, "Converting $key to resume")
+ // Resumption controls must have a title.
+ if (data.song.isNullOrBlank()) {
+ Log.e(TAG, "Description incomplete")
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
+ return
+ }
+ // Move to resume key (aka package name) if that key doesn't already exist.
+ val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) }
+ val actions = resumeAction?.let { listOf(resumeAction) } ?: emptyList()
+ val launcherIntent =
+ context.packageManager.getLaunchIntentForPackage(data.packageName)?.let {
+ PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_IMMUTABLE)
+ }
+ val lastActive =
+ if (data.active) {
+ systemClock.elapsedRealtime()
+ } else {
+ data.lastActive
+ }
+ val updated =
+ data.copy(
+ token = null,
+ actions = actions,
+ semanticActions = MediaButton(playOrPause = resumeAction),
+ actionsToShowInCompact = listOf(0),
+ active = false,
+ resumption = true,
+ isPlaying = false,
+ isClearable = true,
+ clickIntent = launcherIntent,
+ lastActive = lastActive,
+ )
+ val pkg = data.packageName
+ val migrate = mediaDataRepository.addMediaEntry(pkg, updated) == null
+ // Notify listeners of "new" controls when migrating or removed and update when not
+ Log.d(TAG, "migrating? $migrate from $key -> $pkg")
+ if (migrate) {
+ notifyMediaDataLoaded(key = pkg, oldKey = key, info = updated)
+ } else {
+ // Since packageName is used for the key of the resumption controls, it is
+ // possible that another notification has already been reused for the resumption
+ // controls of this package. In this case, rather than renaming this player as
+ // packageName, just remove it and then send a update to the existing resumption
+ // controls.
+ notifyMediaDataRemoved(key)
+ notifyMediaDataLoaded(key = pkg, oldKey = pkg, info = updated)
+ }
+ logger.logActiveConvertedToResume(updated.appUid, pkg, updated.instanceId)
+
+ // Limit total number of resume controls
+ val resumeEntries =
+ mediaDataRepository.mediaEntries.value.filter { (_, data) -> data.resumption }
+ val numResume = resumeEntries.size
+ if (numResume > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) {
+ resumeEntries
+ .toList()
+ .sortedBy { (_, data) -> data.lastActive }
+ .subList(0, numResume - ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS)
+ .forEach { (key, data) ->
+ Log.d(TAG, "Removing excess control $key")
+ mediaDataRepository.removeMediaEntry(key)
+ notifyMediaDataRemoved(key)
+ logger.logMediaRemoved(data.appUid, data.packageName, data.instanceId)
+ }
+ }
+ }
+
+ fun setMediaResumptionEnabled(isEnabled: Boolean) {
+ if (useMediaResumption == isEnabled) {
+ return
+ }
+
+ useMediaResumption = isEnabled
+
+ if (!useMediaResumption) {
+ // Remove any existing resume controls
+ val filtered = mediaDataRepository.mediaEntries.value.filter { !it.value.active }
+ filtered.forEach {
+ mediaDataRepository.removeMediaEntry(it.key)
+ notifyMediaDataRemoved(it.key)
+ logger.logMediaRemoved(it.value.appUid, it.value.packageName, it.value.instanceId)
+ }
+ }
+ }
+
+ /** Listener to data changes. */
+ interface Listener {
+
+ /**
+ * Called whenever there's new MediaData Loaded for the consumption in views.
+ *
+ * oldKey is provided to check whether the view has changed keys, which can happen when a
+ * player has gone from resume state (key is package name) to active state (key is
+ * notification key) or vice versa.
+ *
+ * @param immediately indicates should apply the UI changes immediately, otherwise wait
+ * until the next refresh-round before UI becomes visible. True by default to take in
+ * place immediately.
+ * @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI
+ * displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace
+ * signal.
+ * @param isSsReactivated indicates resume media card is reactivated by Smartspace
+ * recommendation signal
+ */
+ fun onMediaDataLoaded(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ immediately: Boolean = true,
+ receivedSmartspaceCardLatency: Int = 0,
+ isSsReactivated: Boolean = false
+ ) {}
+
+ /**
+ * Called whenever there's new Smartspace media data loaded.
+ *
+ * @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true,
+ * it will be prioritized as the first card. Otherwise, it will show up as the last card
+ * as default.
+ */
+ fun onSmartspaceMediaDataLoaded(
+ key: String,
+ data: SmartspaceMediaData,
+ shouldPrioritize: Boolean = false
+ ) {}
+
+ /** Called whenever a previously existing Media notification was removed. */
+ fun onMediaDataRemoved(key: String) {}
+
+ /**
+ * Called whenever a previously existing Smartspace media data was removed.
+ *
+ * @param immediately indicates should apply the UI changes immediately, otherwise wait
+ * until the next refresh-round before UI becomes visible. True by default to take in
+ * place immediately.
+ */
+ fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) {}
+ }
+
+ /**
+ * Converts the pass-in SmartspaceTarget to SmartspaceMediaData
+ *
+ * @return An empty SmartspaceMediaData with the valid target Id is returned if the
+ * SmartspaceTarget's data is invalid.
+ */
+ private fun toSmartspaceMediaData(target: SmartspaceTarget): SmartspaceMediaData {
+ val baseAction: SmartspaceAction? = target.baseAction
+ val dismissIntent =
+ baseAction
+ ?.extras
+ ?.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY, Intent::class.java)
+
+ val isActive =
+ when {
+ !mediaFlags.isPersistentSsCardEnabled() -> true
+ baseAction == null -> true
+ else -> {
+ val triggerSource = baseAction.extras?.getString(EXTRA_KEY_TRIGGER_SOURCE)
+ triggerSource != EXTRA_VALUE_TRIGGER_PERIODIC
+ }
+ }
+
+ packageName(target)?.let {
+ return SmartspaceMediaData(
+ targetId = target.smartspaceTargetId,
+ isActive = isActive,
+ packageName = it,
+ cardAction = target.baseAction,
+ recommendations = target.iconGrid,
+ dismissIntent = dismissIntent,
+ headphoneConnectionTimeMillis = target.creationTimeMillis,
+ instanceId = logger.getNewInstanceId(),
+ expiryTimeMs = target.expiryTimeMillis,
+ )
+ }
+ return SmartspaceMediaData(
+ targetId = target.smartspaceTargetId,
+ isActive = isActive,
+ dismissIntent = dismissIntent,
+ headphoneConnectionTimeMillis = target.creationTimeMillis,
+ instanceId = logger.getNewInstanceId(),
+ expiryTimeMs = target.expiryTimeMillis,
+ )
+ }
+
+ private fun packageName(target: SmartspaceTarget): String? {
+ val recommendationList: MutableList<SmartspaceAction> = target.iconGrid
+ if (recommendationList.isEmpty()) {
+ Log.w(TAG, "Empty or null media recommendation list.")
+ return null
+ }
+ for (recommendation in recommendationList) {
+ val extras = recommendation.extras
+ extras?.let {
+ it.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME)?.let { packageName ->
+ return packageName
+ }
+ }
+ }
+ Log.w(TAG, "No valid package name is provided.")
+ return null
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("internalListeners: $internalListeners")
+ println("useMediaResumption: $useMediaResumption")
+ println("allowMediaRecommendations: $allowMediaRecommendations")
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
index f4d70a5..c7cfb0b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
@@ -35,10 +35,8 @@
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
import com.android.settingslib.media.PhoneMediaDevice
-import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
import com.android.systemui.media.controls.util.LocalMediaManagerFactory
@@ -70,16 +68,11 @@
private val localBluetoothManager: Lazy<LocalBluetoothManager?>,
@Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
- dumpManager: DumpManager,
-) : MediaDataManager.Listener, Dumpable {
+) : MediaDataManager.Listener {
private val listeners: MutableSet<Listener> = mutableSetOf()
private val entries: MutableMap<String, Entry> = mutableMapOf()
- init {
- dumpManager.registerDumpable(this)
- }
-
/** Add a listener for changes to the media route (ie. device). */
fun addListener(listener: Listener) = listeners.add(listener)
@@ -123,7 +116,7 @@
token?.let { listeners.forEach { it.onKeyRemoved(key) } }
}
- override fun dump(pw: PrintWriter, args: Array<String>) {
+ fun dump(pw: PrintWriter) {
with(pw) {
println("MediaDeviceManager state:")
entries.forEach { (key, entry) ->
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt
new file mode 100644
index 0000000..4a92b71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt
@@ -0,0 +1,234 @@
+/*
+ * 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.media.controls.domain.pipeline.interactor
+
+import android.app.PendingIntent
+import android.media.MediaDescription
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.service.notification.StatusBarNotification
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.media.controls.data.repository.MediaDataRepository
+import com.android.systemui.media.controls.data.repository.MediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.MediaDataCombineLatest
+import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
+import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor
+import com.android.systemui.media.controls.domain.pipeline.MediaDeviceManager
+import com.android.systemui.media.controls.domain.pipeline.MediaSessionBasedFilter
+import com.android.systemui.media.controls.domain.pipeline.MediaTimeoutListener
+import com.android.systemui.media.controls.domain.resume.MediaResumeListener
+import com.android.systemui.media.controls.util.MediaFlags
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/** Encapsulates business logic for media pipeline. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class MediaCarouselInteractor
+@Inject
+constructor(
+ @Application applicationScope: CoroutineScope,
+ private val mediaDataRepository: MediaDataRepository,
+ private val mediaDataProcessor: MediaDataProcessor,
+ private val mediaTimeoutListener: MediaTimeoutListener,
+ private val mediaResumeListener: MediaResumeListener,
+ private val mediaSessionBasedFilter: MediaSessionBasedFilter,
+ private val mediaDeviceManager: MediaDeviceManager,
+ private val mediaDataCombineLatest: MediaDataCombineLatest,
+ private val mediaDataFilter: MediaDataFilterImpl,
+ mediaFilterRepository: MediaFilterRepository,
+ private val mediaFlags: MediaFlags,
+) : MediaDataManager, CoreStartable {
+
+ /** Are there any media notifications active, including the recommendations? */
+ val hasActiveMediaOrRecommendation: StateFlow<Boolean> =
+ combine(
+ mediaFilterRepository.selectedUserEntries,
+ mediaFilterRepository.smartspaceMediaData,
+ mediaFilterRepository.reactivatedKey
+ ) { entries, smartspaceMediaData, reactivatedKey ->
+ entries.any { it.value.active } ||
+ (smartspaceMediaData.isActive &&
+ (smartspaceMediaData.isValid() || reactivatedKey != null))
+ }
+ .distinctUntilChanged()
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+ /** Are there any media entries we should display, including the recommendations? */
+ val hasAnyMediaOrRecommendation: StateFlow<Boolean> =
+ combine(
+ mediaFilterRepository.selectedUserEntries,
+ mediaFilterRepository.smartspaceMediaData
+ ) { entries, smartspaceMediaData ->
+ entries.isNotEmpty() ||
+ (if (mediaFlags.isPersistentSsCardEnabled()) {
+ smartspaceMediaData.isValid()
+ } else {
+ smartspaceMediaData.isActive && smartspaceMediaData.isValid()
+ })
+ }
+ .distinctUntilChanged()
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+ /** Are there any media notifications active, excluding the recommendations? */
+ val hasActiveMedia: StateFlow<Boolean> =
+ mediaFilterRepository.selectedUserEntries
+ .mapLatest { entries -> entries.any { it.value.active } }
+ .distinctUntilChanged()
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+ /** Are there any media notifications, excluding the recommendations? */
+ val hasAnyMedia: StateFlow<Boolean> =
+ mediaFilterRepository.selectedUserEntries
+ .mapLatest { entries -> entries.isNotEmpty() }
+ .distinctUntilChanged()
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+ override fun start() {
+ if (!mediaFlags.isMediaControlsRefactorEnabled()) {
+ return
+ }
+
+ // Initialize the internal processing pipeline. The listeners at the front of the pipeline
+ // are set as internal listeners so that they receive events. From there, events are
+ // propagated through the pipeline. The end of the pipeline is currently mediaDataFilter,
+ // so it is responsible for dispatching events to external listeners. To achieve this,
+ // external listeners that are registered with [MediaDataManager.addListener] are actually
+ // registered as listeners to mediaDataFilter.
+ addInternalListener(mediaTimeoutListener)
+ addInternalListener(mediaResumeListener)
+ addInternalListener(mediaSessionBasedFilter)
+ mediaSessionBasedFilter.addListener(mediaDeviceManager)
+ mediaSessionBasedFilter.addListener(mediaDataCombineLatest)
+ mediaDeviceManager.addListener(mediaDataCombineLatest)
+ mediaDataCombineLatest.addListener(mediaDataFilter)
+
+ // Set up links back into the pipeline for listeners that need to send events upstream.
+ mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean ->
+ setInactive(key, timedOut)
+ }
+ mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
+ mediaDataProcessor.updateState(key, state)
+ }
+ mediaTimeoutListener.sessionCallback = { key: String ->
+ mediaDataProcessor.onSessionDestroyed(key)
+ }
+ mediaResumeListener.setManager(this)
+ mediaDataFilter.mediaDataManager = this
+ }
+
+ override fun addListener(listener: MediaDataManager.Listener) {
+ mediaDataFilter.addListener(listener)
+ }
+
+ override fun removeListener(listener: MediaDataManager.Listener) {
+ mediaDataFilter.removeListener(listener)
+ }
+
+ override fun setInactive(key: String, timedOut: Boolean, forceUpdate: Boolean) {
+ mediaDataProcessor.setInactive(key, timedOut, forceUpdate)
+ }
+
+ override fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
+ mediaDataProcessor.onNotificationAdded(key, sbn)
+ }
+
+ override fun destroy() {
+ mediaSessionBasedFilter.removeListener(mediaDeviceManager)
+ mediaSessionBasedFilter.removeListener(mediaDataCombineLatest)
+ mediaDeviceManager.removeListener(mediaDataCombineLatest)
+ mediaDataCombineLatest.removeListener(mediaDataFilter)
+ mediaDataProcessor.destroy()
+ }
+
+ override fun setResumeAction(key: String, action: Runnable?) {
+ mediaDataProcessor.setResumeAction(key, action)
+ }
+
+ override fun addResumptionControls(
+ userId: Int,
+ desc: MediaDescription,
+ action: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ mediaDataProcessor.addResumptionControls(
+ userId,
+ desc,
+ action,
+ token,
+ appName,
+ appIntent,
+ packageName
+ )
+ }
+
+ override fun dismissMediaData(key: String, delay: Long): Boolean {
+ return mediaDataProcessor.dismissMediaData(key, delay)
+ }
+
+ override fun dismissSmartspaceRecommendation(key: String, delay: Long) {
+ return mediaDataProcessor.dismissSmartspaceRecommendation(key, delay)
+ }
+
+ override fun setRecommendationInactive(key: String) {
+ mediaDataProcessor.setRecommendationInactive(key)
+ }
+
+ override fun onNotificationRemoved(key: String) {
+ mediaDataProcessor.onNotificationRemoved(key)
+ }
+
+ override fun setMediaResumptionEnabled(isEnabled: Boolean) {
+ mediaDataProcessor.setMediaResumptionEnabled(isEnabled)
+ }
+
+ override fun onSwipeToDismiss() {
+ mediaDataFilter.onSwipeToDismiss()
+ }
+
+ override fun hasActiveMediaOrRecommendation() = hasActiveMediaOrRecommendation.value
+
+ override fun hasAnyMediaOrRecommendation() = hasAnyMediaOrRecommendation.value
+
+ override fun hasActiveMedia() = hasActiveMedia.value
+
+ override fun hasAnyMedia() = hasAnyMedia.value
+
+ override fun isRecommendationActive() = mediaDataRepository.smartspaceMediaData.value.isActive
+
+ /** Add a listener for internal events. */
+ private fun addInternalListener(listener: MediaDataManager.Listener) =
+ mediaDataProcessor.addInternalListener(listener)
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ mediaDeviceManager.dump(pw)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
index 4fa7cb5..11a5629 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
@@ -20,48 +20,49 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.media.session.MediaSession
+import android.os.Process
import com.android.internal.logging.InstanceId
import com.android.systemui.res.R
/** State of a media view. */
data class MediaData(
- val userId: Int,
+ val userId: Int = -1,
val initialized: Boolean = false,
/** App name that will be displayed on the player. */
- val app: String?,
+ val app: String? = null,
/** App icon shown on player. */
- val appIcon: Icon?,
+ val appIcon: Icon? = null,
/** Artist name. */
- val artist: CharSequence?,
+ val artist: CharSequence? = null,
/** Song name. */
- val song: CharSequence?,
+ val song: CharSequence? = null,
/** Album artwork. */
- val artwork: Icon?,
+ val artwork: Icon? = null,
/** List of generic action buttons for the media player, based on notification actions */
- val actions: List<MediaAction>,
+ val actions: List<MediaAction> = emptyList(),
/** Same as above, but shown on smaller versions of the player, like in QQS or keyguard. */
- val actionsToShowInCompact: List<Int>,
+ val actionsToShowInCompact: List<Int> = emptyList(),
/**
* Semantic actions buttons, based on the PlaybackState of the media session. If present, these
* actions will be preferred in the UI over [actions]
*/
val semanticActions: MediaButton? = null,
/** Package name of the app that's posting the media. */
- val packageName: String,
+ val packageName: String = "INVALID",
/** Unique media session identifier. */
- val token: MediaSession.Token?,
+ val token: MediaSession.Token? = null,
/** Action to perform when the player is tapped. This is unrelated to {@link #actions}. */
- val clickIntent: PendingIntent?,
+ val clickIntent: PendingIntent? = null,
/** Where the media is playing: phone, headphones, ear buds, remote session. */
- val device: MediaDeviceData?,
+ val device: MediaDeviceData? = null,
/**
* When active, a player will be displayed on keyguard and quick-quick settings. This is
* unrelated to the stream being playing or not, a player will not be active if timed out, or in
* resumption mode.
*/
- var active: Boolean,
+ var active: Boolean = true,
/** Action that should be performed to restart a non active session. */
- var resumeAction: Runnable?,
+ var resumeAction: Runnable? = null,
/** Playback location: one of PLAYBACK_LOCAL, PLAYBACK_CAST_LOCAL, or PLAYBACK_CAST_REMOTE */
var playbackLocation: Int = PLAYBACK_LOCAL,
/**
@@ -88,10 +89,10 @@
var createdTimestampMillis: Long = 0L,
/** Instance ID for logging purposes */
- val instanceId: InstanceId,
+ val instanceId: InstanceId = InstanceId.fakeInstanceId(-1),
/** The UID of the app, used for logging */
- val appUid: Int,
+ val appUid: Int = Process.INVALID_UID,
/** Whether explicit indicator exists */
val isExplicit: Boolean = false,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
index 52c605f..b446585 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
@@ -30,23 +30,23 @@
/** State of a Smartspace media recommendations view. */
data class SmartspaceMediaData(
/** Unique id of a Smartspace media target. */
- val targetId: String,
+ val targetId: String = "INVALID",
/** Indicates if the status is active. */
- val isActive: Boolean,
+ val isActive: Boolean = false,
/** Package name of the media recommendations' provider-app. */
- val packageName: String,
+ val packageName: String = "INVALID",
/** Action to perform when the card is tapped. Also contains the target's extra info. */
- val cardAction: SmartspaceAction?,
+ val cardAction: SmartspaceAction? = null,
/** List of media recommendations. */
- val recommendations: List<SmartspaceAction>,
+ val recommendations: List<SmartspaceAction> = emptyList(),
/** Intent for the user's initiated dismissal. */
- val dismissIntent: Intent?,
+ val dismissIntent: Intent? = null,
/** The timestamp in milliseconds that the card was generated */
- val headphoneConnectionTimeMillis: Long,
+ val headphoneConnectionTimeMillis: Long = 0L,
/** Instance ID for [MediaUiEventLogger] */
- val instanceId: InstanceId,
+ val instanceId: InstanceId? = null,
/** The timestamp in milliseconds indicating when the card should be removed */
- val expiryTimeMs: Long,
+ val expiryTimeMs: Long = 0L,
) {
/**
* Indicates if all the data is valid.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
index ba7d410..963c602 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
@@ -18,19 +18,13 @@
import android.content.Context
import android.content.res.Configuration
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.controls.ui.view.MediaHostState
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
@@ -43,7 +37,6 @@
import com.android.systemui.statusbar.policy.SplitShadeStateController
import com.android.systemui.util.asIndenting
import com.android.systemui.util.println
-import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.withIncreasedIndent
import java.io.PrintWriter
import javax.inject.Inject
@@ -61,8 +54,6 @@
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
private val context: Context,
- private val secureSettings: SecureSettings,
- @Main private val handler: Handler,
configurationController: ConfigurationController,
private val splitShadeStateController: SplitShadeStateController,
private val logger: KeyguardMediaControllerLogger,
@@ -91,26 +82,6 @@
}
)
- val settingsObserver: ContentObserver =
- object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- if (uri == lockScreenMediaPlayerUri) {
- allowMediaPlayerOnLockScreen =
- secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
- )
- refreshMediaPosition(reason = "allowMediaPlayerOnLockScreen changed")
- }
- }
- }
- secureSettings.registerContentObserverForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- settingsObserver,
- UserHandle.USER_ALL
- )
-
// First let's set the desired state that we want for this host
mediaHost.expansion = MediaHostState.EXPANDED
mediaHost.showsOnlyActiveMedia = true
@@ -156,16 +127,6 @@
private set
private var splitShadeContainer: ViewGroup? = null
- /** Track the media player setting status on lock screen. */
- private var allowMediaPlayerOnLockScreen: Boolean =
- secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
- )
- private val lockScreenMediaPlayerUri =
- secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
-
/**
* Attaches media container in single pane mode, situated at the top of the notifications list
*/
@@ -185,7 +146,7 @@
refreshMediaPosition(reason = "onMediaHostVisibilityChanged")
if (visible) {
- if (migrateClocksToBlueprint() && useSplitShade) {
+ if (MigrateClocksToBlueprint.isEnabled && useSplitShade) {
return
}
mediaHost.hostView.layoutParams.apply {
@@ -229,14 +190,12 @@
// mediaHost.visible required for proper animations handling
val isMediaHostVisible = mediaHost.visible
val isBypassNotEnabled = !bypassController.bypassEnabled
- val currentAllowMediaPlayerOnLockScreen = allowMediaPlayerOnLockScreen
val useSplitShade = useSplitShade
val shouldBeVisibleForSplitShade = shouldBeVisibleForSplitShade()
visible =
isMediaHostVisible &&
isBypassNotEnabled &&
keyguardOrUserSwitcher &&
- currentAllowMediaPlayerOnLockScreen &&
shouldBeVisibleForSplitShade
logger.logRefreshMediaPosition(
reason = reason,
@@ -246,7 +205,6 @@
keyguardOrUserSwitcher = keyguardOrUserSwitcher,
mediaHostVisible = isMediaHostVisible,
bypassNotEnabled = isBypassNotEnabled,
- currentAllowMediaPlayerOnLockScreen = currentAllowMediaPlayerOnLockScreen,
shouldBeVisibleForSplitShade = shouldBeVisibleForSplitShade,
)
val currActiveContainer = activeContainer
@@ -321,7 +279,6 @@
println("Self", this@KeyguardMediaController)
println("visible", visible)
println("useSplitShade", useSplitShade)
- println("allowMediaPlayerOnLockScreen", allowMediaPlayerOnLockScreen)
println("bypassController.bypassEnabled", bypassController.bypassEnabled)
println("isDozeWakeUpAnimationWaiting", isDozeWakeUpAnimationWaiting)
println("singlePaneContainer", singlePaneContainer)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerLogger.kt
index c0d9dc2..4d1827ef 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerLogger.kt
@@ -36,7 +36,6 @@
keyguardOrUserSwitcher: Boolean,
mediaHostVisible: Boolean,
bypassNotEnabled: Boolean,
- currentAllowMediaPlayerOnLockScreen: Boolean,
shouldBeVisibleForSplitShade: Boolean,
) {
logBuffer.log(
@@ -50,8 +49,7 @@
bool3 = keyguardOrUserSwitcher
bool4 = mediaHostVisible
int2 = if (bypassNotEnabled) 1 else 0
- str2 = currentAllowMediaPlayerOnLockScreen.toString()
- str3 = shouldBeVisibleForSplitShade.toString()
+ str2 = shouldBeVisibleForSplitShade.toString()
},
{
"refreshMediaPosition(reason=$str1, " +
@@ -60,8 +58,7 @@
"keyguardOrUserSwitcher=$bool3, " +
"mediaHostVisible=$bool4, " +
"bypassNotEnabled=${int2 == 1}, " +
- "currentAllowMediaPlayerOnLockScreen=$str2, " +
- "shouldBeVisibleForSplitShade=$str3)"
+ "shouldBeVisibleForSplitShade=$str2)"
}
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index b721236..c3c1e83 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -22,6 +22,7 @@
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.database.ContentObserver
+import android.os.UserHandle
import android.provider.Settings
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
@@ -44,6 +45,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
@@ -76,6 +78,8 @@
import com.android.systemui.util.animation.requiresRemeasuring
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.util.Locale
@@ -83,10 +87,16 @@
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Provider
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
@@ -108,6 +118,7 @@
private val systemClock: SystemClock,
@Main executor: DelayableExecutor,
@Background private val bgExecutor: Executor,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val mediaManager: MediaDataManager,
configurationController: ConfigurationController,
falsingManager: FalsingManager,
@@ -118,6 +129,7 @@
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val globalSettings: GlobalSettings,
+ private val secureSettings: SecureSettings,
) : Dumpable {
/** The current width of the carousel */
var currentCarouselWidth: Int = 0
@@ -191,6 +203,8 @@
}
}
+ private var allowMediaPlayerOnLockScreen = false
+
/** Whether the media card currently has the "expanded" layout */
@VisibleForTesting
var currentlyExpanded = true
@@ -532,8 +546,9 @@
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
mediaCarousel.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- // A backup to show media carousel (if available) once the keyguard is gone.
listenForAnyStateToGoneKeyguardTransition(this)
+ listenForAnyStateToLockscreenTransition(this)
+ listenForLockscreenSettingChanges(this)
}
}
@@ -587,7 +602,49 @@
return scope.launch {
keyguardTransitionInteractor.anyStateToGoneTransition
.filter { it.transitionState == TransitionState.FINISHED }
- .collect { showMediaCarousel() }
+ .collect {
+ showMediaCarousel()
+ updateHostVisibility()
+ }
+ }
+ }
+
+ @VisibleForTesting
+ internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job {
+ return scope.launch {
+ keyguardTransitionInteractor.anyStateToLockscreenTransition
+ .filter { it.transitionState == TransitionState.FINISHED }
+ .collect {
+ if (!allowMediaPlayerOnLockScreen) {
+ updateHostVisibility()
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ internal fun listenForLockscreenSettingChanges(scope: CoroutineScope): Job {
+ return scope.launch {
+ secureSettings
+ .observerFlow(UserHandle.USER_ALL, Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+ // query to get initial value
+ .onStart { emit(Unit) }
+ .map { getMediaLockScreenSetting() }
+ .distinctUntilChanged()
+ .collectLatest {
+ allowMediaPlayerOnLockScreen = it
+ updateHostVisibility()
+ }
+ }
+ }
+
+ private suspend fun getMediaLockScreenSetting(): Boolean {
+ return withContext(backgroundDispatcher) {
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
}
}
@@ -600,6 +657,13 @@
updatePlayers(recreateMedia = true)
}
+ /** Return true if the carousel should be hidden because lockscreen is currently visible */
+ fun isLockedAndHidden(): Boolean {
+ val keyguardState = keyguardTransitionInteractor.getFinishedState()
+ return !allowMediaPlayerOnLockScreen &&
+ KeyguardState.lockscreenVisibleInState(keyguardState)
+ }
+
private fun reorderAllPlayers(
previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
key: String? = null
@@ -1163,7 +1227,7 @@
// Only log media resume card when Smartspace data is available
if (
!mediaControlKey.isSsMediaRec &&
- !mediaManager.smartspaceMediaData.isActive &&
+ !mediaManager.isRecommendationActive() &&
MediaPlayerData.smartspaceMediaData == null
) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
index d92168b..eca76b6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt
@@ -23,6 +23,7 @@
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
import com.android.systemui.media.controls.ui.controller.MediaHostStatesManager
import com.android.systemui.media.controls.ui.controller.MediaLocation
@@ -33,12 +34,12 @@
import java.util.Objects
import javax.inject.Inject
-class MediaHost
-constructor(
+class MediaHost(
private val state: MediaHostStateHolder,
private val mediaHierarchyManager: MediaHierarchyManager,
private val mediaDataManager: MediaDataManager,
- private val mediaHostStatesManager: MediaHostStatesManager
+ private val mediaHostStatesManager: MediaHostStatesManager,
+ private val mediaCarouselController: MediaCarouselController,
) : MediaHostState by state {
lateinit var hostView: UniqueObjectHostView
var location: Int = -1
@@ -202,7 +203,9 @@
*/
fun updateViewVisibility() {
state.visible =
- if (showsOnlyActiveMedia) {
+ if (mediaCarouselController.isLockedAndHidden()) {
+ false
+ } else if (showsOnlyActiveMedia) {
mediaDataManager.hasActiveMediaOrRecommendation()
} else {
mediaDataManager.hasAnyMediaOrRecommendation()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
index f8c816c..2c25fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
@@ -161,7 +161,7 @@
logger.log(event)
}
- fun logRecommendationAdded(packageName: String, instanceId: InstanceId) {
+ fun logRecommendationAdded(packageName: String, instanceId: InstanceId?) {
logger.logWithInstanceId(
MediaUiEvent.MEDIA_RECOMMENDATION_ADDED,
0,
@@ -170,7 +170,7 @@
)
}
- fun logRecommendationRemoved(packageName: String, instanceId: InstanceId) {
+ fun logRecommendationRemoved(packageName: String, instanceId: InstanceId?) {
logger.logWithInstanceId(
MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED,
0,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index d84e5dd..59b98b2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -19,7 +19,9 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
+import com.android.systemui.media.controls.domain.MediaDomainModule;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController;
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
import com.android.systemui.media.controls.ui.controller.MediaHostStatesManager;
import com.android.systemui.media.controls.ui.view.MediaHost;
@@ -38,7 +40,11 @@
import javax.inject.Named;
/** Dagger module for the media package. */
-@Module(subcomponents = {
+@Module(
+ includes = {
+ MediaDomainModule.class
+ },
+ subcomponents = {
MediaComplicationComponent.class,
})
public interface MediaModule {
@@ -54,8 +60,9 @@
@Named(QS_PANEL)
static MediaHost providesQSMediaHost(MediaHost.MediaHostStateHolder stateHolder,
MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
- MediaHostStatesManager statesManager) {
- return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
+ MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+ return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
+ carouselController);
}
/** */
@@ -64,8 +71,9 @@
@Named(QUICK_QS_PANEL)
static MediaHost providesQuickQSMediaHost(MediaHost.MediaHostStateHolder stateHolder,
MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
- MediaHostStatesManager statesManager) {
- return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
+ MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+ return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
+ carouselController);
}
/** */
@@ -74,8 +82,9 @@
@Named(KEYGUARD)
static MediaHost providesKeyguardMediaHost(MediaHost.MediaHostStateHolder stateHolder,
MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
- MediaHostStatesManager statesManager) {
- return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
+ MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+ return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
+ carouselController);
}
/** */
@@ -84,8 +93,9 @@
@Named(DREAM)
static MediaHost providesDreamMediaHost(MediaHost.MediaHostStateHolder stateHolder,
MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
- MediaHostStatesManager statesManager) {
- return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
+ MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+ return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
+ carouselController);
}
/** */
@@ -94,8 +104,9 @@
@Named(COMMUNAL_HUB)
static MediaHost providesCommunalMediaHost(MediaHost.MediaHostStateHolder stateHolder,
MediaHierarchyManager hierarchyManager, MediaDataManager dataManager,
- MediaHostStatesManager statesManager) {
- return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
+ MediaHostStatesManager statesManager, MediaCarouselController carouselController) {
+ return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager,
+ carouselController);
}
/** Provides a logging buffer related to the media tap-to-transfer chip on the sender device. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index dfe41eb..d49a513 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -243,7 +243,7 @@
Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Secure.SEARCH_LONG_PRESS_HOME_ENABLED),
+ Settings.Secure.getUriFor(Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
@@ -443,10 +443,10 @@
boolean overrideLongPressHome = mAssistManagerLazy.get()
.shouldOverrideAssist(AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
boolean longPressDefault = mContext.getResources().getBoolean(overrideLongPressHome
- ? com.android.internal.R.bool.config_searchLongPressHomeEnabledDefault
+ ? com.android.internal.R.bool.config_searchAllEntrypointsEnabledDefault
: com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
- overrideLongPressHome ? Secure.SEARCH_LONG_PRESS_HOME_ENABLED
+ overrideLongPressHome ? Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED
: Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
mUserTracker.getUserId()) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 768bb8e..4fe3a11 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -934,48 +934,51 @@
private void orientSecondaryHomeHandle() {
if (!canShowSecondaryHandle()) {
- if (mStartingQuickSwitchRotation == -1) {
- resetSecondaryHandle();
- }
return;
}
- int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
- if (mStartingQuickSwitchRotation == -1 || deltaRotation == -1) {
- // Curious if starting quickswitch can change between the if check and our delta
- Log.d(TAG, "secondary nav delta rotation: " + deltaRotation
- + " current: " + mCurrentRotation
- + " starting: " + mStartingQuickSwitchRotation);
- }
- int height = 0;
- int width = 0;
- Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
- mOrientationHandle.setDeltaRotation(deltaRotation);
- switch (deltaRotation) {
- case Surface.ROTATION_90, Surface.ROTATION_270:
- height = dispSize.height();
- width = mView.getHeight();
- break;
- case Surface.ROTATION_180, Surface.ROTATION_0:
- // TODO(b/152683657): Need to determine best UX for this
- if (!mShowOrientedHandleForImmersiveMode) {
- resetSecondaryHandle();
- return;
- }
- width = dispSize.width();
- height = mView.getHeight();
- break;
- }
+ if (mStartingQuickSwitchRotation == -1) {
+ resetSecondaryHandle();
+ } else {
+ int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
+ if (mStartingQuickSwitchRotation == -1 || deltaRotation == -1) {
+ // Curious if starting quickswitch can change between the if check and our delta
+ Log.d(TAG, "secondary nav delta rotation: " + deltaRotation
+ + " current: " + mCurrentRotation
+ + " starting: " + mStartingQuickSwitchRotation);
+ }
+ int height = 0;
+ int width = 0;
+ Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mOrientationHandle.setDeltaRotation(deltaRotation);
+ switch (deltaRotation) {
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_270:
+ height = dispSize.height();
+ width = mView.getHeight();
+ break;
+ case Surface.ROTATION_180:
+ case Surface.ROTATION_0:
+ // TODO(b/152683657): Need to determine best UX for this
+ if (!mShowOrientedHandleForImmersiveMode) {
+ resetSecondaryHandle();
+ return;
+ }
+ width = dispSize.width();
+ height = mView.getHeight();
+ break;
+ }
- mOrientationParams.gravity =
- deltaRotation == Surface.ROTATION_0 ? Gravity.BOTTOM :
- (deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT);
- mOrientationParams.height = height;
- mOrientationParams.width = width;
- mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
- mView.setVisibility(View.GONE);
- mOrientationHandle.setVisibility(View.VISIBLE);
- logNavbarOrientation("orientSecondaryHomeHandle");
+ mOrientationParams.gravity =
+ deltaRotation == Surface.ROTATION_0 ? Gravity.BOTTOM :
+ (deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT);
+ mOrientationParams.height = height;
+ mOrientationParams.width = width;
+ mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
+ mView.setVisibility(View.GONE);
+ mOrientationHandle.setVisibility(View.VISIBLE);
+ logNavbarOrientation("orientSecondaryHomeHandle");
+ }
}
private void resetSecondaryHandle() {
@@ -1789,8 +1792,7 @@
}
private boolean canShowSecondaryHandle() {
- return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null
- && mStartingQuickSwitchRotation != -1;
+ return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
}
private final UserTracker.Callback mUserChangedCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 5d2aeef..b34b370 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -432,6 +432,9 @@
for (int i = 0; i < NP; i++) {
mPages.get(i).removeAllViews();
}
+ if (mPageIndicator != null) {
+ mPageIndicator.setNumPages(numPages);
+ }
if (NP == numPages) {
return;
}
@@ -443,7 +446,6 @@
mLogger.d("Removing page");
mPages.remove(mPages.size() - 1);
}
- mPageIndicator.setNumPages(mPages.size());
setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
if (mPageToRestore != NO_PAGE) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 18d2f30..b0707db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -111,7 +111,7 @@
@Override
protected void handleClick(@Nullable View view) {
if (mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG)) {
- mDialogViewModel.showDialog(mContext, view);
+ mDialogViewModel.showDialog(view);
} else {
// Secondary clicks are header clicks, just toggle.
final boolean isEnabled = mState.value;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index d82b175..b418a17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -44,6 +44,7 @@
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.recordissue.IssueRecordingService
+import com.android.systemui.recordissue.IssueRecordingState
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.res.R
import com.android.systemui.screenrecord.RecordingService
@@ -69,6 +70,7 @@
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val panelInteractor: PanelInteractor,
private val userContextProvider: UserContextProvider,
+ private val issueRecordingState: IssueRecordingState,
private val delegateFactory: RecordIssueDialogDelegate.Factory,
) :
QSTileImpl<QSTile.BooleanState>(
@@ -83,7 +85,16 @@
qsLogger
) {
- @VisibleForTesting var isRecording: Boolean = false
+ private val onRecordingChangeListener = Runnable { refreshState() }
+
+ override fun handleSetListening(listening: Boolean) {
+ super.handleSetListening(listening)
+ if (listening) {
+ issueRecordingState.addListener(onRecordingChangeListener)
+ } else {
+ issueRecordingState.removeListener(onRecordingChangeListener)
+ }
+ }
override fun getTileLabel(): CharSequence = mContext.getString(R.string.qs_record_issue_label)
@@ -103,13 +114,11 @@
@VisibleForTesting
public override fun handleClick(view: View?) {
- if (isRecording) {
- isRecording = false
+ if (issueRecordingState.isRecording) {
stopIssueRecordingService()
} else {
mUiHandler.post { showPrompt(view) }
}
- refreshState()
}
private fun startIssueRecordingService(screenRecord: Boolean, winscopeTracing: Boolean) =
@@ -138,11 +147,9 @@
val dialog: AlertDialog =
delegateFactory
.create {
- isRecording = true
startIssueRecordingService(it.screenRecord, it.winscopeTracing)
dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
panelInteractor.collapsePanels()
- refreshState()
}
.createDialog()
val dismissAction =
@@ -168,7 +175,7 @@
@VisibleForTesting
public override fun handleUpdateState(qsTileState: QSTile.BooleanState, arg: Any?) {
qsTileState.apply {
- if (isRecording) {
+ if (issueRecordingState.isRecording) {
value = true
state = Tile.STATE_ACTIVE
forceExpandIcon = false
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
index 1247854..59fc81c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
@@ -19,8 +19,6 @@
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
/** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */
@SysUISingleton
@@ -30,14 +28,10 @@
private val bluetoothAutoOnRepository: BluetoothAutoOnRepository,
) {
- val isEnabled = bluetoothAutoOnRepository.isAutoOn.map { it == ENABLED }.distinctUntilChanged()
+ val isEnabled = bluetoothAutoOnRepository.isAutoOn
- /**
- * Checks if the auto on value is present in the repository.
- *
- * @return `true` if a value is present (i.e, the feature is enabled by the Bluetooth server).
- */
- suspend fun isValuePresent(): Boolean = bluetoothAutoOnRepository.isValuePresent()
+ /** Checks if the auto on feature is supported. */
+ suspend fun isAutoOnSupported(): Boolean = bluetoothAutoOnRepository.isAutoOnSupported()
/**
* Sets enabled or disabled based on the provided value.
@@ -45,17 +39,14 @@
* @param value `true` to enable the feature, `false` to disable it.
*/
suspend fun setEnabled(value: Boolean) {
- if (!isValuePresent()) {
+ if (!isAutoOnSupported()) {
Log.e(TAG, "Trying to set toggle value while feature not available.")
} else {
- val newValue = if (value) ENABLED else DISABLED
- bluetoothAutoOnRepository.setAutoOn(newValue)
+ bluetoothAutoOnRepository.setAutoOn(value)
}
}
companion object {
private const val TAG = "BluetoothAutoOnInteractor"
- const val DISABLED = 0
- const val ENABLED = 1
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
index f97fc38..9ee582a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
@@ -16,22 +16,23 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
+import android.bluetooth.BluetoothAdapter
+import android.util.Log
+import com.android.settingslib.bluetooth.BluetoothCallback
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.user.data.repository.UserRepository
-import com.android.systemui.util.settings.SecureSettings
-import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -44,61 +45,87 @@
class BluetoothAutoOnRepository
@Inject
constructor(
- private val secureSettings: SecureSettings,
- private val userRepository: UserRepository,
+ localBluetoothManager: LocalBluetoothManager?,
+ private val bluetoothAdapter: BluetoothAdapter?,
@Application private val coroutineScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) {
- // Flow representing the auto on setting value for the current user
- @OptIn(ExperimentalCoroutinesApi::class)
- internal val isAutoOn: StateFlow<Int> =
- userRepository.selectedUserInfo
- .flatMapLatest { userInfo ->
- secureSettings
- .observerFlow(userInfo.id, SETTING_NAME)
- .onStart { emit(Unit) }
- .map { secureSettings.getIntForUser(SETTING_NAME, UNSET, userInfo.id) }
- }
- .distinctUntilChanged()
- .flowOn(backgroundDispatcher)
- .stateIn(
- coroutineScope,
- SharingStarted.WhileSubscribed(replayExpirationMillis = 0),
- UNSET
- )
+ // Flow representing the auto on state for the current user
+ internal val isAutoOn: Flow<Boolean> =
+ localBluetoothManager?.eventManager?.let { eventManager ->
+ conflatedCallbackFlow {
+ val listener =
+ object : BluetoothCallback {
+ override fun onAutoOnStateChanged(autoOnState: Int) {
+ super.onAutoOnStateChanged(autoOnState)
+ if (
+ autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED ||
+ autoOnState == BluetoothAdapter.AUTO_ON_STATE_DISABLED
+ ) {
+ trySendWithFailureLogging(
+ autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED,
+ TAG,
+ "onAutoOnStateChanged"
+ )
+ }
+ }
+ }
+ eventManager.registerCallback(listener)
+ awaitClose { eventManager.unregisterCallback(listener) }
+ }
+ .onStart { emit(isAutoOnEnabled()) }
+ .flowOn(backgroundDispatcher)
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(replayExpirationMillis = 0),
+ initialValue = false
+ )
+ }
+ ?: flowOf(false)
/**
- * Checks if the auto on setting value is ever set for the current user.
+ * Checks if the auto on feature is supported for the current user.
*
- * @return `true` if the setting value is not UNSET, `false` otherwise.
+ * @throws Exception if an error occurs while checking auto-on support.
*/
- suspend fun isValuePresent(): Boolean =
+ suspend fun isAutoOnSupported(): Boolean =
withContext(backgroundDispatcher) {
- secureSettings.getIntForUser(
- SETTING_NAME,
- UNSET,
- userRepository.getSelectedUserInfo().id
- ) != UNSET
+ try {
+ bluetoothAdapter?.isAutoOnSupported ?: false
+ } catch (e: Exception) {
+ // Server could throw TimeoutException, InterruptedException or ExecutionException
+ Log.e(TAG, "Error calling isAutoOnSupported", e)
+ false
+ }
}
- /**
- * Sets the Bluetooth Auto-On setting value for the current user.
- *
- * @param value The new setting value to be applied.
- */
- suspend fun setAutoOn(value: Int) {
+ /** Sets the Bluetooth Auto-On for the current user. */
+ suspend fun setAutoOn(value: Boolean) {
withContext(backgroundDispatcher) {
- secureSettings.putIntForUser(
- SETTING_NAME,
- value,
- userRepository.getSelectedUserInfo().id
- )
+ try {
+ bluetoothAdapter?.setAutoOnEnabled(value)
+ } catch (e: Exception) {
+ // Server could throw IllegalStateException, TimeoutException, InterruptedException
+ // or ExecutionException
+ Log.e(TAG, "Error calling setAutoOnEnabled", e)
+ }
}
}
- companion object {
- const val SETTING_NAME = "bluetooth_automatic_turn_on"
- const val UNSET = -1
+ private suspend fun isAutoOnEnabled() =
+ withContext(backgroundDispatcher) {
+ try {
+ bluetoothAdapter?.isAutoOnEnabled ?: false
+ } catch (e: Exception) {
+ // Server could throw IllegalStateException, TimeoutException, InterruptedException
+ // or ExecutionException
+ Log.e(TAG, "Error calling isAutoOnEnabled", e)
+ false
+ }
+ }
+
+ private companion object {
+ const val TAG = "BluetoothAutoOnRepository"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
index 9d53703..a8d9e78 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
-import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -58,7 +57,6 @@
class BluetoothTileDialogDelegate
@AssistedInject
internal constructor(
- @Assisted private val context: Context,
@Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
@Assisted private val cachedContentHeight: Int,
@Assisted private val bluetoothToggleInitialValue: Boolean,
@@ -69,11 +67,8 @@
private val uiEventLogger: UiEventLogger,
private val logger: BluetoothTileDialogLogger,
private val systemuiDialogFactory: SystemUIDialog.Factory,
- mainLayoutInflater: LayoutInflater,
) : SystemUIDialog.Delegate {
- private val layoutInflater = mainLayoutInflater.cloneInContext(context)
-
private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> =
MutableStateFlow(bluetoothToggleInitialValue)
internal val bluetoothStateToggle
@@ -102,7 +97,6 @@
@AssistedFactory
internal interface Factory {
fun create(
- context: Context,
initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
cachedContentHeight: Int,
bluetoothEnabled: Boolean,
@@ -112,16 +106,15 @@
}
override fun createDialog(): SystemUIDialog {
- val dialog = systemuiDialogFactory.create(this, context)
-
- return dialog
+ return systemuiDialogFactory.create(this)
}
override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
SystemUIDialog.registerDismissListener(dialog, dismissListener)
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
+ val context = dialog.context
- layoutInflater.inflate(R.layout.bluetooth_tile_dialog, null).apply {
+ LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
dialog.setContentView(this)
}
@@ -201,7 +194,7 @@
setEnabled(true)
alpha = ENABLED_ALPHA
}
- getSubtitleTextView(dialog).text = context.getString(uiProperties.subTitleResId)
+ getSubtitleTextView(dialog).text = dialog.context.getString(uiProperties.subTitleResId)
getAutoOnToggleView(dialog).visibility = uiProperties.autoOnToggleVisibility
}
@@ -215,7 +208,7 @@
setEnabled(true)
alpha = ENABLED_ALPHA
}
- getAutoOnToggleInfoTextView(dialog).text = context.getString(infoResId)
+ getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId)
}
private fun setupToggle(dialog: SystemUIDialog) {
@@ -288,7 +281,7 @@
private fun setupRecyclerView(dialog: SystemUIDialog) {
getDeviceListView(dialog).apply {
- layoutManager = LinearLayoutManager(context)
+ layoutManager = LinearLayoutManager(dialog.context)
adapter = deviceItemAdapter
}
}
@@ -343,7 +336,9 @@
private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder {
- val view = layoutInflater.inflate(R.layout.bluetooth_device_item, parent, false)
+ val view =
+ LayoutInflater.from(parent.context)
+ .inflate(R.layout.bluetooth_device_item, parent, false)
return DeviceItemViewHolder(view)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index e4f3c19..fd624d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
-import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
@@ -29,7 +28,6 @@
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.flags.Flags.bluetoothQsTileDialogAutoOnToggle
import com.android.systemui.Prefs
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
@@ -78,19 +76,19 @@
/**
* Shows the dialog.
*
- * @param context The context in which the dialog is displayed.
* @param view The view from which the dialog is shown.
*/
@kotlinx.coroutines.ExperimentalCoroutinesApi
- fun showDialog(context: Context, view: View?) {
+ fun showDialog(view: View?) {
cancelJob()
job =
coroutineScope.launch(mainDispatcher) {
var updateDeviceItemJob: Job?
var updateDialogUiJob: Job? = null
- val dialogDelegate = createBluetoothTileDialog(context)
+ val dialogDelegate = createBluetoothTileDialog()
val dialog = dialogDelegate.createDialog()
+ val context = dialog.context
view?.let {
dialogTransitionAnimator.showFromView(
@@ -213,7 +211,7 @@
}
}
- private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate {
+ private suspend fun createBluetoothTileDialog(): BluetoothTileDialogDelegate {
val cachedContentHeight =
withContext(backgroundDispatcher) {
sharedPreferences.getInt(
@@ -223,7 +221,6 @@
}
return bluetoothDialogDelegateFactory.create(
- context,
UiProperties.build(
bluetoothStateInteractor.isBluetoothEnabled,
isAutoOnToggleFeatureAvailable()
@@ -277,7 +274,7 @@
@VisibleForTesting
internal suspend fun isAutoOnToggleFeatureAvailable() =
- bluetoothQsTileDialogAutoOnToggle() && bluetoothAutoOnInteractor.isValuePresent()
+ bluetoothAutoOnInteractor.isAutoOnSupported()
companion object {
private const val INTERACTION_JANK_TAG = "bluetooth_tile_dialog"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
index 2b8c335..c0fc52e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt
@@ -83,6 +83,7 @@
}
}
+ sideViewIcon = QSTileState.SideViewIcon.Chevron
contentDescription = label
supportedActions = setOf(QSTileState.UserAction.CLICK)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
index fc42ba4..b25c61c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
@@ -39,7 +39,7 @@
return sysuiDialogFactory.create(this, context)
}
- override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
with(dialog) {
setTitle(R.string.data_saver_enable_title)
setMessage(R.string.data_saver_description)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractor.kt
new file mode 100644
index 0000000..a2a9e87a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileDataInteractor.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.qs.tiles.impl.work.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.statusbar.phone.ManagedProfileController
+import com.android.systemui.util.kotlin.hasActiveWorkProfile
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Observes data saver state changes providing the [WorkModeTileModel]. */
+class WorkModeTileDataInteractor
+@Inject
+constructor(
+ private val profileController: ManagedProfileController,
+) : QSTileDataInteractor<WorkModeTileModel> {
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<WorkModeTileModel> =
+ profileController.hasActiveWorkProfile.map { hasActiveWorkProfile: Boolean ->
+ if (hasActiveWorkProfile) {
+ WorkModeTileModel.HasActiveProfile(profileController.isWorkModeEnabled)
+ } else {
+ WorkModeTileModel.NoActiveProfile
+ }
+ }
+
+ override fun availability(user: UserHandle): Flow<Boolean> =
+ profileController.hasActiveWorkProfile
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt
new file mode 100644
index 0000000..f765f8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.qs.tiles.impl.work.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import com.android.systemui.statusbar.phone.ManagedProfileController
+import javax.inject.Inject
+
+/** Handles airplane mode tile clicks and long clicks. */
+class WorkModeTileUserActionInteractor
+@Inject
+constructor(
+ private val profileController: ManagedProfileController,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<WorkModeTileModel> {
+ override suspend fun handleInput(input: QSTileInput<WorkModeTileModel>) =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ if (data is WorkModeTileModel.HasActiveProfile) {
+ profileController.setWorkModeEnabled(!data.isEnabled)
+ }
+ }
+ is QSTileUserAction.LongClick -> {
+ if (data is WorkModeTileModel.HasActiveProfile) {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_MANAGED_PROFILE_SETTINGS)
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/model/WorkModeTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/model/WorkModeTileModel.kt
new file mode 100644
index 0000000..ae8382d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/model/WorkModeTileModel.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.work.domain.model
+
+/** Work mode tile model. */
+sealed interface WorkModeTileModel {
+ /** @param isEnabled is true when the work mode is enabled */
+ data class HasActiveProfile(val isEnabled: Boolean) : WorkModeTileModel
+ data object NoActiveProfile : WorkModeTileModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt
new file mode 100644
index 0000000..55445bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.qs.tiles.impl.work.ui
+
+import android.app.admin.DevicePolicyManager
+import android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_WORK_PROFILE_LABEL
+import android.content.res.Resources
+import android.service.quicksettings.Tile
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [WorkModeTileModel] to [QSTileState]. */
+class WorkModeTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+ private val devicePolicyManager: DevicePolicyManager,
+) : QSTileDataToStateMapper<WorkModeTileModel> {
+ override fun map(config: QSTileConfig, data: WorkModeTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ label = getTileLabel()!!
+ contentDescription = label
+
+ icon = {
+ Icon.Loaded(
+ resources.getDrawable(
+ com.android.internal.R.drawable.stat_sys_managed_profile_status,
+ theme
+ ),
+ contentDescription = null
+ )
+ }
+
+ when (data) {
+ is WorkModeTileModel.HasActiveProfile -> {
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = ""
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel =
+ resources.getString(R.string.quick_settings_work_mode_paused_state)
+ }
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+ is WorkModeTileModel.NoActiveProfile -> {
+ activationState = QSTileState.ActivationState.UNAVAILABLE
+ secondaryLabel =
+ resources.getStringArray(R.array.tile_states_work)[Tile.STATE_UNAVAILABLE]
+ supportedActions = setOf()
+ }
+ }
+
+ sideViewIcon = QSTileState.SideViewIcon.None
+ }
+
+ private fun getTileLabel(): CharSequence? {
+ return devicePolicyManager.resources.getString(QS_WORK_PROFILE_LABEL) {
+ resources.getString(R.string.quick_settings_work_mode_label)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 34f66b8..c695d4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -48,6 +48,8 @@
qsSceneAdapter.isCustomizing.map { customizing ->
if (customizing) {
mapOf<UserAction, UserActionResult>(Back to UserActionResult(Scenes.QuickSettings))
+ // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade
+ // while customizing
} else {
mapOf(
Back to UserActionResult(Scenes.Shade),
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 7009816..5e4919d 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -59,6 +59,7 @@
keyguardDismissUtil: KeyguardDismissUtil,
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val panelInteractor: PanelInteractor,
+ private val issueRecordingState: IssueRecordingState,
) :
RecordingService(
controller,
@@ -90,6 +91,7 @@
DEFAULT_MAX_TRACE_SIZE,
DEFAULT_MAX_TRACE_DURATION_IN_MINUTES
)
+ issueRecordingState.isRecording = true
if (!intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)) {
// If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
// will circumvent the RecordingService's screen recording start code.
@@ -103,6 +105,7 @@
// this line should be removed.
getSystemService(LauncherApps::class.java)?.saveViewCaptureData()
TraceUtils.traceStop(contentResolver)
+ issueRecordingState.isRecording = false
}
ACTION_SHARE -> {
shareRecording(intent)
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt
new file mode 100644
index 0000000..394c5c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingState.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.recordissue
+
+import com.android.systemui.dagger.SysUISingleton
+import java.util.concurrent.CopyOnWriteArrayList
+import javax.inject.Inject
+
+@SysUISingleton
+class IssueRecordingState @Inject constructor() {
+
+ private val listeners = CopyOnWriteArrayList<Runnable>()
+
+ var isRecording = false
+ set(value) {
+ field = value
+ listeners.forEach(Runnable::run)
+ }
+
+ fun addListener(listener: Runnable) {
+ listeners.add(listener)
+ }
+
+ fun removeListener(listener: Runnable) {
+ listeners.remove(listener)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 7313a49..832fc3f 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -17,6 +17,7 @@
package com.android.systemui.recordissue
import android.annotation.SuppressLint
+import android.app.AlertDialog
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
@@ -74,7 +75,6 @@
@SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch
private lateinit var issueTypeButton: Button
- private var hasSelectedIssueType: Boolean = false
@MainThread
override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
@@ -86,15 +86,13 @@
setPositiveButton(
R.string.qs_record_issue_start,
{ _, _ ->
- if (hasSelectedIssueType) {
- onStarted.accept(
- IssueRecordingConfig(
- screenRecordSwitch.isChecked,
- true /* TODO: Base this on issueType selected */
- )
+ onStarted.accept(
+ IssueRecordingConfig(
+ screenRecordSwitch.isChecked,
+ true /* TODO: Base this on issueType selected */
)
- dismiss()
- }
+ )
+ dismiss()
},
false
)
@@ -115,8 +113,12 @@
bgExecutor.execute { onScreenRecordSwitchClicked() }
}
}
+ val startButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
issueTypeButton = requireViewById(R.id.issue_type_button)
- issueTypeButton.setOnClickListener { onIssueTypeClicked(context) }
+ issueTypeButton.setOnClickListener {
+ onIssueTypeClicked(context) { startButton.isEnabled = true }
+ }
+ startButton.isEnabled = false
}
}
@@ -159,7 +161,7 @@
}
@MainThread
- private fun onIssueTypeClicked(context: Context) {
+ private fun onIssueTypeClicked(context: Context, onIssueTypeSelected: Runnable) {
val selectedCategory = issueTypeButton.text.toString()
val popupMenu = PopupMenu(context, issueTypeButton)
@@ -174,11 +176,11 @@
popupMenu.apply {
setOnMenuItemClickListener {
issueTypeButton.text = it.title
+ onIssueTypeSelected.run()
true
}
setForceShowIcon(true)
show()
}
- hasSelectedIssueType = true
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 467089d..54ec398 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -18,18 +18,15 @@
package com.android.systemui.scene.shared.flag
-import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
-import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
-import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
-import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.Flags.keyguardWmStateRefactor
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.Flags.sceneContainer
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.Flags.SCENE_CONTAINER_ENABLED
import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
import dagger.Module
@@ -45,11 +42,11 @@
get() =
SCENE_CONTAINER_ENABLED && // mainStaticFlag
sceneContainer() && // mainAconfigFlag
- keyguardBottomAreaRefactor() &&
- migrateClocksToBlueprint() &&
+ KeyguardBottomAreaRefactor.isEnabled &&
+ MigrateClocksToBlueprint.isEnabled &&
ComposeLockscreen.isEnabled &&
MediaInSceneContainerFlag.isEnabled &&
- keyguardWmStateRefactor()
+ KeyguardWmStateRefactor.isEnabled
// NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
/**
@@ -66,9 +63,9 @@
/** The set of secondary flags which must be enabled for scene container to work properly */
inline fun getSecondaryFlags(): Sequence<FlagToken> =
sequenceOf(
- FlagToken(FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor()),
- FlagToken(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, migrateClocksToBlueprint()),
- FlagToken(FLAG_KEYGUARD_WM_STATE_REFACTOR, keyguardWmStateRefactor()),
+ KeyguardBottomAreaRefactor.token,
+ MigrateClocksToBlueprint.token,
+ KeyguardWmStateRefactor.token,
ComposeLockscreen.token,
MediaInSceneContainerFlag.token,
// NOTE: Changes should also be made in isEnabled and @EnableSceneContainer
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
new file mode 100644
index 0000000..97acccd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.screenshot
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.os.UserHandle
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/**
+ * Provides actions for screenshots. This class can be overridden by a vendor-specific SysUI
+ * implementation.
+ */
+interface ScreenshotActionsProvider {
+ data class ScreenshotAction(
+ val icon: Drawable? = null,
+ val text: String? = null,
+ val description: String,
+ val overrideTransition: Boolean = false,
+ val retrieveIntent: (Uri) -> Intent
+ )
+
+ interface ScreenshotActionsCallback {
+ fun setPreviewAction(overrideTransition: Boolean = false, retrieveIntent: (Uri) -> Intent)
+ fun addAction(action: ScreenshotAction) = addActions(listOf(action))
+ fun addActions(actions: List<ScreenshotAction>)
+ }
+
+ interface Factory {
+ fun create(
+ context: Context,
+ user: UserHandle?,
+ callback: ScreenshotActionsCallback
+ ): ScreenshotActionsProvider
+ }
+}
+
+class DefaultScreenshotActionsProvider(
+ private val context: Context,
+ private val user: UserHandle?,
+ private val callback: ScreenshotActionsProvider.ScreenshotActionsCallback
+) : ScreenshotActionsProvider {
+ init {
+ callback.setPreviewAction(true) { ActionIntentCreator.createEdit(it, context) }
+ val editAction =
+ ScreenshotActionsProvider.ScreenshotAction(
+ AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit),
+ context.resources.getString(R.string.screenshot_edit_label),
+ context.resources.getString(R.string.screenshot_edit_description),
+ true
+ ) { uri ->
+ ActionIntentCreator.createEdit(uri, context)
+ }
+ val shareAction =
+ ScreenshotActionsProvider.ScreenshotAction(
+ AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share),
+ context.resources.getString(R.string.screenshot_share_label),
+ context.resources.getString(R.string.screenshot_share_description),
+ false
+ ) { uri ->
+ ActionIntentCreator.createShare(uri)
+ }
+ callback.addActions(listOf(editAction, shareAction))
+ }
+
+ class Factory @Inject constructor() : ScreenshotActionsProvider.Factory {
+ override fun create(
+ context: Context,
+ user: UserHandle?,
+ callback: ScreenshotActionsProvider.ScreenshotActionsCallback
+ ): ScreenshotActionsProvider {
+ return DefaultScreenshotActionsProvider(context, user, callback)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index c8e13bb..b796a20 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static com.android.systemui.Flags.screenshotShelfUi;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
@@ -237,6 +238,7 @@
private final WindowContext mContext;
private final FeatureFlags mFlags;
private final ScreenshotViewProxy mViewProxy;
+ private final ScreenshotActionsProvider.Factory mActionsProviderFactory;
private final ScreenshotNotificationsController mNotificationsController;
private final ScreenshotSmartActions mScreenshotSmartActions;
private final UiEventLogger mUiEventLogger;
@@ -271,6 +273,8 @@
private boolean mScreenshotTakenInPortrait;
private boolean mBlockAttach;
+ private ScreenshotActionsProvider mActionsProvider;
+
private Animator mScreenshotAnimation;
private RequestCallback mCurrentRequestCallback;
private String mPackageName = "";
@@ -298,6 +302,7 @@
Context context,
FeatureFlags flags,
ScreenshotViewProxy.Factory viewProxyFactory,
+ ScreenshotActionsProvider.Factory actionsProviderFactory,
ScreenshotSmartActions screenshotSmartActions,
ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory,
ScrollCaptureClient scrollCaptureClient,
@@ -349,6 +354,7 @@
mAssistContentRequester = assistContentRequester;
mViewProxy = viewProxyFactory.getProxy(mContext, mDisplayId);
+ mActionsProviderFactory = actionsProviderFactory;
mScreenshotHandler.setOnTimeoutRunnable(() -> {
if (DEBUG_UI) {
@@ -393,6 +399,7 @@
void handleScreenshot(ScreenshotData screenshot, Consumer<Uri> finisher,
RequestCallback requestCallback) {
Assert.isMainThread();
+
mCurrentRequestCallback = requestCallback;
if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) {
Rect bounds = getFullScreenRect();
@@ -496,7 +503,7 @@
return mDisplayId == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
}
- void prepareViewForNewScreenshot(ScreenshotData screenshot, String oldPackageName) {
+ void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
withWindowAttached(() -> {
if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
mViewProxy.announceForAccessibility(mContext.getResources().getString(
@@ -509,6 +516,11 @@
mViewProxy.reset();
+ if (screenshotShelfUi()) {
+ mActionsProvider = mActionsProviderFactory.create(mContext, screenshot.getUserHandle(),
+ ((ScreenshotActionsProvider.ScreenshotActionsCallback) mViewProxy));
+ }
+
if (mViewProxy.isAttachedToWindow()) {
// if we didn't already dismiss for another reason
if (!mViewProxy.isDismissing()) {
@@ -983,20 +995,16 @@
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- doPostAnimation(imageData);
+ mViewProxy.setChipIntents(imageData);
}
});
} else {
- doPostAnimation(imageData);
+ mViewProxy.setChipIntents(imageData);
}
});
}
}
- private void doPostAnimation(ScreenshotController.SavedImageData imageData) {
- mViewProxy.setChipIntents(imageData);
- }
-
/**
* Sets up the action shade and its entrance animation, once we get the Quick Share action data.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
new file mode 100644
index 0000000..88bca95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -0,0 +1,259 @@
+/*
+ * 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.screenshot
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.app.Notification
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Rect
+import android.net.Uri
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.ScrollCaptureResponse
+import android.view.View
+import android.view.ViewTreeObserver
+import android.view.WindowInsets
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.log.DebugLogger.debugLog
+import com.android.systemui.res.R
+import com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS
+import com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS
+import com.android.systemui.screenshot.LogConfig.DEBUG_INPUT
+import com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW
+import com.android.systemui.screenshot.ScreenshotController.SavedImageData
+import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER
+import com.android.systemui.screenshot.scroll.ScrollCaptureController
+import com.android.systemui.screenshot.ui.ScreenshotAnimationController
+import com.android.systemui.screenshot.ui.ScreenshotShelfView
+import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder
+import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
+import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/** Controls the screenshot view and viewModel. */
+class ScreenshotShelfViewProxy
+@AssistedInject
+constructor(
+ private val logger: UiEventLogger,
+ private val viewModel: ScreenshotViewModel,
+ @Assisted private val context: Context,
+ @Assisted private val displayId: Int
+) : ScreenshotViewProxy, ScreenshotActionsProvider.ScreenshotActionsCallback {
+ override val view: ScreenshotShelfView =
+ LayoutInflater.from(context).inflate(R.layout.screenshot_shelf, null) as ScreenshotShelfView
+ override val screenshotPreview: View
+ override var packageName: String = ""
+ override var callbacks: ScreenshotView.ScreenshotViewCallback? = null
+ override var screenshot: ScreenshotData? = null
+ set(value) {
+ viewModel.setScreenshotBitmap(value?.bitmap)
+ field = value
+ }
+
+ override val isAttachedToWindow
+ get() = view.isAttachedToWindow
+ override var isDismissing = false
+ override var isPendingSharedTransition = false
+
+ private val animationController = ScreenshotAnimationController(view)
+ private var imageData: SavedImageData? = null
+ private var runOnImageDataAcquired: ((SavedImageData) -> Unit)? = null
+
+ init {
+ ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context))
+ addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }
+ setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }
+ debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" }
+ screenshotPreview = view.screenshotPreview
+ }
+
+ override fun reset() {
+ animationController.cancel()
+ isPendingSharedTransition = false
+ imageData = null
+ viewModel.reset()
+ runOnImageDataAcquired = null
+ }
+ override fun updateInsets(insets: WindowInsets) {}
+ override fun updateOrientation(insets: WindowInsets) {}
+
+ override fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator {
+ return animationController.getEntranceAnimation()
+ }
+
+ override fun addQuickShareChip(quickShareAction: Notification.Action) {}
+
+ override fun setChipIntents(data: SavedImageData) {
+ imageData = data
+ runOnImageDataAcquired?.invoke(data)
+ }
+
+ override fun requestDismissal(event: ScreenshotEvent) {
+ debugLog(DEBUG_DISMISS) { "screenshot dismissal requested: $event" }
+
+ // If we're already animating out, don't restart the animation
+ if (isDismissing) {
+ debugLog(DEBUG_DISMISS) { "Already dismissing, ignoring duplicate command $event" }
+ return
+ }
+ logger.log(event, 0, packageName)
+ val animator = animationController.getExitAnimation()
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ isDismissing = true
+ }
+ override fun onAnimationEnd(animator: Animator) {
+ isDismissing = false
+ callbacks?.onDismiss()
+ }
+ }
+ )
+ animator.start()
+ }
+
+ override fun showScrollChip(packageName: String, onClick: Runnable) {}
+
+ override fun hideScrollChip() {}
+
+ override fun prepareScrollingTransition(
+ response: ScrollCaptureResponse,
+ screenBitmap: Bitmap,
+ newScreenshot: Bitmap,
+ screenshotTakenInPortrait: Boolean,
+ onTransitionPrepared: Runnable,
+ ) {}
+
+ override fun startLongScreenshotTransition(
+ transitionDestination: Rect,
+ onTransitionEnd: Runnable,
+ longScreenshot: ScrollCaptureController.LongScreenshot
+ ) {}
+
+ override fun restoreNonScrollingUi() {}
+
+ override fun stopInputListening() {}
+
+ override fun requestFocus() {
+ view.requestFocus()
+ }
+
+ override fun announceForAccessibility(string: String) = view.announceForAccessibility(string)
+
+ override fun prepareEntranceAnimation(runnable: Runnable) {
+ view.viewTreeObserver.addOnPreDrawListener(
+ object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ debugLog(DEBUG_WINDOW) { "onPreDraw: startAnimation" }
+ view.viewTreeObserver.removeOnPreDrawListener(this)
+ runnable.run()
+ return true
+ }
+ }
+ )
+ }
+
+ private fun addPredictiveBackListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
+ val onBackInvokedCallback = OnBackInvokedCallback {
+ debugLog(DEBUG_INPUT) { "Predictive Back callback dispatched" }
+ onDismissRequested.invoke(SCREENSHOT_DISMISSED_OTHER)
+ }
+ view.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ debugLog(DEBUG_INPUT) { "Registering Predictive Back callback" }
+ view
+ .findOnBackInvokedDispatcher()
+ ?.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ onBackInvokedCallback
+ )
+ }
+
+ override fun onViewDetachedFromWindow(view: View) {
+ debugLog(DEBUG_INPUT) { "Unregistering Predictive Back callback" }
+ view
+ .findOnBackInvokedDispatcher()
+ ?.unregisterOnBackInvokedCallback(onBackInvokedCallback)
+ }
+ }
+ )
+ }
+ private fun setOnKeyListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
+ view.setOnKeyListener(
+ object : View.OnKeyListener {
+ override fun onKey(view: View, keyCode: Int, event: KeyEvent): Boolean {
+ if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ debugLog(DEBUG_INPUT) { "onKeyEvent: $keyCode" }
+ onDismissRequested.invoke(SCREENSHOT_DISMISSED_OTHER)
+ return true
+ }
+ return false
+ }
+ }
+ )
+ }
+
+ @AssistedFactory
+ interface Factory : ScreenshotViewProxy.Factory {
+ override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy
+ }
+
+ override fun setPreviewAction(overrideTransition: Boolean, retrieveIntent: (Uri) -> Intent) {
+ viewModel.setPreviewAction {
+ imageData?.let {
+ val intent = retrieveIntent(it.uri)
+ debugLog(DEBUG_ACTIONS) { "Preview tapped: $intent" }
+ isPendingSharedTransition = true
+ callbacks?.onAction(intent, it.owner, overrideTransition)
+ }
+ }
+ }
+
+ override fun addActions(actions: List<ScreenshotActionsProvider.ScreenshotAction>) {
+ viewModel.addActions(
+ actions.map { action ->
+ ActionButtonViewModel(action.icon, action.text, action.description) {
+ val actionRunnable =
+ getActionRunnable(action.retrieveIntent, action.overrideTransition)
+ imageData?.let { actionRunnable(it) }
+ ?: run { runOnImageDataAcquired = actionRunnable }
+ }
+ }
+ )
+ }
+
+ private fun getActionRunnable(
+ retrieveIntent: (Uri) -> Intent,
+ overrideTransition: Boolean
+ ): (SavedImageData) -> Unit {
+ val onClick: (SavedImageData) -> Unit = {
+ val intent = retrieveIntent(it.uri)
+ debugLog(DEBUG_ACTIONS) { "Action tapped: $intent" }
+ isPendingSharedTransition = true
+ callbacks!!.onAction(intent, it.owner, overrideTransition)
+ }
+ return onClick
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
index 06c0b8b..c89b476 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
@@ -33,6 +33,7 @@
import android.content.Intent.CaptureContentForNoteStatusCodes;
import android.content.res.Resources;
import android.os.IBinder;
+import android.util.Log;
import androidx.annotation.Nullable;
@@ -58,6 +59,8 @@
*/
public class AppClipsService extends Service {
+ private static final String TAG = AppClipsService.class.getSimpleName();
+
@Application private final Context mContext;
private final FeatureFlags mFeatureFlags;
private final Optional<Bubbles> mOptionalBubbles;
@@ -77,14 +80,22 @@
private boolean checkIndependentVariables() {
if (!mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)) {
+ Log.d(TAG, "Feature flag disabled");
return false;
}
if (mOptionalBubbles.isEmpty()) {
+ Log.d(TAG, "Bubbles not available");
return false;
}
- return isComponentValid();
+ if (isComponentValid()) {
+ Log.d(TAG, "checkIndependentVariables returned true");
+ return true;
+ }
+
+ Log.d(TAG, "checkIndependentVariables returned false");
+ return false;
}
private boolean isComponentValid() {
@@ -93,12 +104,27 @@
componentName = ComponentName.unflattenFromString(
mContext.getString(R.string.config_screenshotAppClipsActivityComponent));
} catch (Resources.NotFoundException e) {
+ Log.d(TAG, "AppClips activity component resource not defined");
return false;
}
- return componentName != null
- && !componentName.getPackageName().isEmpty()
- && !componentName.getClassName().isEmpty();
+ if (componentName == null) {
+ Log.d(TAG, "AppClips component name not defined");
+ return false;
+ }
+
+ if (componentName.getPackageName().isEmpty()) {
+ Log.d(TAG, "AppClips component package name is empty");
+ return false;
+ }
+
+ if (componentName.getClassName().isEmpty()) {
+ Log.d(TAG, "AppClips component class name is empty");
+ return false;
+ }
+
+ Log.d(TAG, "isComponentValid returned true");
+ return true;
}
@Nullable
@@ -107,24 +133,39 @@
return new IAppClipsService.Stub() {
@Override
public boolean canLaunchCaptureContentActivityForNote(int taskId) {
- return canLaunchCaptureContentActivityForNoteInternal(taskId)
- == CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+ if (canLaunchCaptureContentActivityForNoteInternal(taskId)
+ == CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
+ Log.d(TAG, String.format("Can launch AppClips returned true for %d", taskId));
+ return true;
+ }
+
+ Log.d(TAG, String.format("Can launch AppClips returned false for %d", taskId));
+ return false;
}
@Override
@CaptureContentForNoteStatusCodes
public int canLaunchCaptureContentActivityForNoteInternal(int taskId) {
if (!mAreTaskAndTimeIndependentPrerequisitesMet) {
+ Log.d(TAG,
+ String.format("Task (%d) and time independent prereqs not met", taskId));
return CAPTURE_CONTENT_FOR_NOTE_FAILED;
}
if (!mOptionalBubbles.get().isAppBubbleTaskId(taskId)) {
+ Log.d(TAG, String.format("Taskid %d is not app bubble task", taskId));
return CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
}
- return mDevicePolicyManager.getScreenCaptureDisabled(null)
- ? CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN
- : CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+ if (mDevicePolicyManager.getScreenCaptureDisabled(null)) {
+ Log.d(TAG,
+ String.format("Screen capture disabled by admin, taskId %d", taskId));
+ return CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
+ }
+
+ Log.d(TAG,
+ String.format("Can launch AppClips (internal) successful for %d", taskId));
+ return CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index cdb9abb..2ce6d83 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -16,16 +16,23 @@
package com.android.systemui.screenshot.dagger;
-import android.app.Service;
+import static com.android.systemui.Flags.screenshotShelfUi;
+import android.app.Service;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.screenshot.DefaultScreenshotActionsProvider;
import com.android.systemui.screenshot.ImageCapture;
import com.android.systemui.screenshot.ImageCaptureImpl;
import com.android.systemui.screenshot.LegacyScreenshotViewProxy;
import com.android.systemui.screenshot.RequestProcessor;
+import com.android.systemui.screenshot.ScreenshotActionsProvider;
import com.android.systemui.screenshot.ScreenshotPolicy;
import com.android.systemui.screenshot.ScreenshotPolicyImpl;
import com.android.systemui.screenshot.ScreenshotProxyService;
import com.android.systemui.screenshot.ScreenshotRequestProcessor;
+import com.android.systemui.screenshot.ScreenshotShelfViewProxy;
import com.android.systemui.screenshot.ScreenshotSoundController;
import com.android.systemui.screenshot.ScreenshotSoundControllerImpl;
import com.android.systemui.screenshot.ScreenshotSoundProvider;
@@ -34,6 +41,7 @@
import com.android.systemui.screenshot.TakeScreenshotService;
import com.android.systemui.screenshot.appclips.AppClipsScreenshotHelperService;
import com.android.systemui.screenshot.appclips.AppClipsService;
+import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel;
import dagger.Binds;
import dagger.Module;
@@ -85,9 +93,25 @@
abstract ScreenshotSoundController bindScreenshotSoundController(
ScreenshotSoundControllerImpl screenshotSoundProviderImpl);
+ @Binds
+ abstract ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory(
+ DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory);
+
+ @Provides
+ @SysUISingleton
+ static ScreenshotViewModel providesScreenshotViewModel(
+ AccessibilityManager accessibilityManager) {
+ return new ScreenshotViewModel(accessibilityManager);
+ }
+
@Provides
static ScreenshotViewProxy.Factory providesScreenshotViewProxyFactory(
+ ScreenshotShelfViewProxy.Factory shelfScreenshotViewProxyFactory,
LegacyScreenshotViewProxy.Factory legacyScreenshotViewProxyFactory) {
- return legacyScreenshotViewProxyFactory;
+ if (screenshotShelfUi()) {
+ return shelfScreenshotViewProxyFactory;
+ } else {
+ return legacyScreenshotViewProxyFactory;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
new file mode 100644
index 0000000..2c17873
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.screenshot.ui
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.view.View
+
+class ScreenshotAnimationController(private val view: View) {
+ private var animator: Animator? = null
+
+ fun getEntranceAnimation(): Animator {
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.addUpdateListener { view.alpha = it.animatedFraction }
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ view.alpha = 0f
+ }
+ override fun onAnimationEnd(animator: Animator) {
+ view.alpha = 1f
+ }
+ }
+ )
+ this.animator = animator
+ return animator
+ }
+
+ fun getExitAnimation(): Animator {
+ val animator = ValueAnimator.ofFloat(1f, 0f)
+ animator.addUpdateListener { view.alpha = it.animatedValue as Float }
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ view.alpha = 1f
+ }
+ override fun onAnimationEnd(animator: Animator) {
+ view.alpha = 0f
+ }
+ }
+ )
+ this.animator = animator
+ return animator
+ }
+
+ fun cancel() {
+ animator?.cancel()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
new file mode 100644
index 0000000..747ad4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.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.screenshot.ui
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.systemui.res.R
+
+class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) :
+ ConstraintLayout(context, attrs) {
+ lateinit var screenshotPreview: ImageView
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ screenshotPreview = requireViewById(R.id.screenshot_preview)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
new file mode 100644
index 0000000..c7fe3f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.screenshot.ui.binder
+
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.systemui.res.R
+import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
+
+object ActionButtonViewBinder {
+ /** Binds the given view to the given view-model */
+ fun bind(view: View, viewModel: ActionButtonViewModel) {
+ val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon)
+ val textView = view.requireViewById<TextView>(R.id.overlay_action_chip_text)
+ iconView.setImageDrawable(viewModel.icon)
+ textView.text = viewModel.name
+ setMargins(iconView, textView, viewModel.name?.isNotEmpty() ?: false)
+ if (viewModel.onClicked != null) {
+ view.setOnClickListener { viewModel.onClicked.invoke() }
+ } else {
+ view.setOnClickListener(null)
+ }
+ view.contentDescription = viewModel.description
+ view.visibility = View.VISIBLE
+ view.alpha = 1f
+ }
+
+ private fun setMargins(iconView: View, textView: View, hasText: Boolean) {
+ val iconParams = iconView.layoutParams as LinearLayout.LayoutParams
+ val textParams = textView.layoutParams as LinearLayout.LayoutParams
+ if (hasText) {
+ iconParams.marginStart = iconView.dpToPx(R.dimen.overlay_action_chip_padding_start)
+ iconParams.marginEnd = iconView.dpToPx(R.dimen.overlay_action_chip_spacing)
+ textParams.marginStart = 0
+ textParams.marginEnd = textView.dpToPx(R.dimen.overlay_action_chip_padding_end)
+ } else {
+ val paddingHorizontal =
+ iconView.dpToPx(R.dimen.overlay_action_chip_icon_only_padding_horizontal)
+ iconParams.marginStart = paddingHorizontal
+ iconParams.marginEnd = paddingHorizontal
+ }
+ iconView.layoutParams = iconParams
+ textView.layoutParams = textParams
+ }
+
+ private fun View.dpToPx(dimenId: Int): Int {
+ return this.resources.getDimensionPixelSize(dimenId)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
new file mode 100644
index 0000000..d878200
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.screenshot.ui.binder
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
+import com.android.systemui.util.children
+import kotlinx.coroutines.launch
+
+object ScreenshotShelfViewBinder {
+ fun bind(
+ view: ViewGroup,
+ viewModel: ScreenshotViewModel,
+ layoutInflater: LayoutInflater,
+ ) {
+ val previewView: ImageView = view.requireViewById(R.id.screenshot_preview)
+ val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border)
+ previewView.clipToOutline = true
+ val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
+ view.requireViewById<View>(R.id.screenshot_dismiss_button).visibility =
+ if (viewModel.showDismissButton) View.VISIBLE else View.GONE
+
+ view.repeatWhenAttached {
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.preview.collect { bitmap ->
+ if (bitmap != null) {
+ previewView.setImageBitmap(bitmap)
+ previewView.visibility = View.VISIBLE
+ previewBorder.visibility = View.VISIBLE
+ } else {
+ previewView.visibility = View.GONE
+ previewBorder.visibility = View.GONE
+ }
+ }
+ }
+ launch {
+ viewModel.previewAction.collect { onClick ->
+ previewView.setOnClickListener { onClick?.run() }
+ }
+ }
+ launch {
+ viewModel.actions.collect { actions ->
+ if (actions.isNotEmpty()) {
+ view
+ .requireViewById<View>(R.id.actions_container_background)
+ .visibility = View.VISIBLE
+ }
+ val viewPool = actionsContainer.children.toList()
+ actionsContainer.removeAllViews()
+ val actionButtons =
+ List(actions.size) {
+ viewPool.getOrElse(it) {
+ layoutInflater.inflate(
+ R.layout.overlay_action_chip,
+ actionsContainer,
+ false
+ )
+ }
+ }
+ actionButtons.zip(actions).forEach {
+ actionsContainer.addView(it.first)
+ ActionButtonViewBinder.bind(it.first, it.second)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt
new file mode 100644
index 0000000..05bfed1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.screenshot.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+
+data class ActionButtonViewModel(
+ val icon: Drawable?,
+ val name: CharSequence?,
+ val description: CharSequence,
+ val onClicked: (() -> Unit)?
+)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
new file mode 100644
index 0000000..dc61d1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.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.systemui.screenshot.ui.viewmodel
+
+import android.graphics.Bitmap
+import android.view.accessibility.AccessibilityManager
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) {
+ private val _preview = MutableStateFlow<Bitmap?>(null)
+ val preview: StateFlow<Bitmap?> = _preview
+ private val _previewAction = MutableStateFlow<Runnable?>(null)
+ val previewAction: StateFlow<Runnable?> = _previewAction
+ private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>())
+ val actions: StateFlow<List<ActionButtonViewModel>> = _actions
+ val showDismissButton: Boolean
+ get() = accessibilityManager.isEnabled
+
+ fun setScreenshotBitmap(bitmap: Bitmap?) {
+ _preview.value = bitmap
+ }
+
+ fun setPreviewAction(runnable: Runnable) {
+ _previewAction.value = runnable
+ }
+
+ fun addActions(actions: List<ActionButtonViewModel>) {
+ val actionList = _actions.value.toMutableList()
+ actionList.addAll(actions)
+ _actions.value = actionList
+ }
+
+ fun reset() {
+ _preview.value = null
+ _previewAction.value = null
+ _actions.value = listOf()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
index f71a401d..2fdcaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
@@ -17,8 +17,6 @@
package com.android.systemui.shade
import com.android.systemui.assist.AssistManager
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -29,7 +27,6 @@
/** A base class for non-empty implementations of ShadeController. */
@OptIn(ExperimentalCoroutinesApi::class)
abstract class BaseShadeControllerImpl(
- private val touchLog: LogBuffer,
protected val commandQueue: CommandQueue,
protected val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
protected val notificationShadeWindowController: NotificationShadeWindowController,
@@ -40,7 +37,7 @@
private val postCollapseActions = ArrayList<Runnable>()
override fun start() {
- logTouchesTo(touchLog)
+ // Do nothing by default
}
final override fun animateExpandShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9cb920a..a4b32a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -24,8 +24,6 @@
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.Flags.keyguardBottomAreaRefactor;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.Flags.predictiveBackAnimateShade;
import static com.android.systemui.Flags.smartspaceRelocateToBottom;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
@@ -129,8 +127,10 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.keyguard.KeyguardBottomAreaRefactor;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -193,6 +193,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -336,7 +337,6 @@
private final ScrimController mScrimController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
- private final ShadeHeaderController mShadeHeaderController;
private final boolean mVibrateOnOpening;
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
private final FlingAnimationUtils mFlingAnimationUtilsClosing;
@@ -734,7 +734,6 @@
FragmentService fragmentService,
IStatusBarService statusBarService,
ContentResolver contentResolver,
- ShadeHeaderController shadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
LockscreenGestureLogger lockscreenGestureLogger,
ShadeExpansionStateManager shadeExpansionStateManager,
@@ -881,7 +880,6 @@
mSplitShadeEnabled =
mSplitShadeStateController.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG_DRAWABLE);
- mShadeHeaderController = shadeHeaderController;
mLayoutInflater = layoutInflater;
mFeatureFlags = featureFlags;
mAnimateBack = predictiveBackAnimateShade();
@@ -1018,7 +1016,7 @@
instantCollapse();
} else {
mView.animate().cancel();
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mView.animate()
.alpha(0f)
.setStartDelay(0)
@@ -1075,7 +1073,7 @@
mQsController.init();
mShadeHeadsUpTracker.addTrackingHeadsUpListener(
mNotificationStackScrollLayoutController::setTrackingHeadsUp);
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled()) {
setKeyguardBottomArea(mView.findViewById(R.id.keyguard_bottom_area));
}
@@ -1116,9 +1114,6 @@
}
mTapAgainViewController.init();
- mShadeHeaderController.init();
- mShadeHeaderController.setShadeCollapseAction(
- () -> collapse(/* delayed= */ false , /* speedUpFactor= */ 1.0f));
mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
mNotificationPanelUnfoldAnimationController.ifPresent(controller ->
controller.setup(mNotificationContainerParent));
@@ -1154,7 +1149,7 @@
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
collectFlow(mView,
@@ -1165,7 +1160,7 @@
// Lockscreen->Dreaming
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
mLockscreenToDreamingTransition, mMainDispatcher);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher);
@@ -1177,7 +1172,7 @@
// Gone->Dreaming
collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
mGoneToDreamingTransition, mMainDispatcher);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
}
@@ -1188,7 +1183,7 @@
// Lockscreen->Occluded
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
mLockscreenToOccludedTransition, mMainDispatcher);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
@@ -1196,7 +1191,7 @@
}
// Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController,
/* excludeNotifications=*/ true), mMainDispatcher);
@@ -1280,7 +1275,7 @@
mKeyguardStatusViewController.onDestroy();
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
// Need a shared controller until mKeyguardStatusViewController can be removed from
// here, due to important state being set in that controller. Rebind in order to pick
// up config changes
@@ -1332,13 +1327,13 @@
private void onSplitShadeEnabledChanged() {
mShadeLog.logSplitShadeChanged(mSplitShadeEnabled);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
}
// Reset any left over overscroll state. It is a rare corner case but can happen.
mQsController.setOverScrollAmount(0);
mScrimController.setNotificationsOverScrollAmount(0);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mNotificationStackScrollLayoutController.setOverExpansion(0);
mNotificationStackScrollLayoutController.setOverScrollAmount(0);
}
@@ -1359,7 +1354,7 @@
}
updateClockAppearance();
mQsController.updateQsState();
- if (!migrateClocksToBlueprint() && !FooterViewRefactor.isEnabled()) {
+ if (!MigrateClocksToBlueprint.isEnabled() && !FooterViewRefactor.isEnabled()) {
mNotificationStackScrollLayoutController.updateFooter();
}
}
@@ -1391,7 +1386,7 @@
void reInflateViews() {
debugLog("reInflateViews");
// Re-inflate the status view group.
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
KeyguardStatusView keyguardStatusView =
mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView);
@@ -1430,7 +1425,7 @@
updateViewControllers(userAvatarView, keyguardUserSwitcherView);
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled()) {
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
mView.removeView(mKeyguardBottomArea);
@@ -1449,7 +1444,7 @@
mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
mBarState,
false,
@@ -1471,7 +1466,7 @@
mBarState);
}
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled()) {
setKeyguardBottomAreaVisibility(mBarState, false);
}
@@ -1480,14 +1475,14 @@
}
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
mKeyguardMediaController.attachSplitShadeContainer(container);
}
private void initBottomArea() {
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled()) {
mKeyguardBottomArea.init(
mKeyguardBottomAreaViewModel,
mFalsingManager,
@@ -1513,7 +1508,7 @@
}
private void updateMaxDisplayedNotifications(boolean recompute) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
@@ -1630,7 +1625,7 @@
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange();
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mKeyguardClockInteractor.setClockSize(computeDesiredClockSize());
} else {
mKeyguardStatusViewController.displayClock(computeDesiredClockSize(),
@@ -1671,11 +1666,11 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.setLockscreenClockY(
mClockPositionAlgorithm.getExpandedPreferredClockY());
}
- if (!(migrateClocksToBlueprint() || keyguardBottomAreaRefactor())) {
+ if (!(MigrateClocksToBlueprint.isEnabled() || KeyguardBottomAreaRefactor.isEnabled())) {
mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
}
@@ -1683,7 +1678,7 @@
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY,
mClockPositionResult.clockScale, animateClock);
@@ -1740,7 +1735,7 @@
// To prevent the weather clock from overlapping with the notification shelf on AOD, we use
// the small clock here
// With migrateClocksToBlueprint, weather clock will have behaviors similar to other clocks
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
if (mKeyguardStatusViewController.isLargeClockBlockingNotificationShelf()
&& hasVisibleNotifications() && isOnAod()) {
return SMALL;
@@ -1758,7 +1753,7 @@
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered();
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
return;
}
@@ -1941,7 +1936,7 @@
}
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
// TODO (b/296373478) This is for split shade media movement.
} else {
mKeyguardStatusViewController
@@ -2498,7 +2493,7 @@
}
if (!mKeyguardBypassController.getBypassEnabled()) {
- if (migrateClocksToBlueprint() && !mSplitShadeEnabled) {
+ if (MigrateClocksToBlueprint.isEnabled() && !mSplitShadeEnabled) {
return (int) mKeyguardInteractor.getNotificationContainerBounds()
.getValue().getTop();
}
@@ -2531,7 +2526,7 @@
void requestScrollerTopPaddingUpdate(boolean animate) {
float padding = mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
getKeyguardNotificationStaticPadding(), mExpandedFraction);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mSharedNotificationContainerInteractor.setTopPosition(padding);
} else {
mNotificationStackScrollLayoutController.updateTopPadding(padding, animate);
@@ -2712,7 +2707,7 @@
return;
}
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
float alpha = 1f;
if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp
&& !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -2748,7 +2743,7 @@
}
private void updateKeyguardBottomAreaAlpha() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
if (mIsOcclusionTransitionRunning) {
@@ -2766,7 +2761,7 @@
float alpha = Math.min(expansionAlpha, 1 - mQsController.computeExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled()) {
mKeyguardInteractor.setAlpha(alpha);
} else {
mKeyguardBottomAreaInteractor.setAlpha(alpha);
@@ -2978,7 +2973,7 @@
}
private void updateDozingVisibilities(boolean animate) {
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled()) {
mKeyguardInteractor.setAnimateDozingTransitions(animate);
} else {
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
@@ -2990,7 +2985,7 @@
@Override
public void onScreenTurningOn() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.dozeTimeTick();
}
}
@@ -3189,7 +3184,7 @@
mDozing = dozing;
// TODO (b/) make listeners for this
mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled()) {
mKeyguardInteractor.setAnimateDozingTransitions(animate);
} else {
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
@@ -3245,7 +3240,7 @@
public void dozeTimeTick() {
mLockIconViewController.dozeTimeTick();
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.dozeTimeTick();
}
if (mInterpolatedDarkAmount > 0) {
@@ -3324,7 +3319,7 @@
/** Updates the views to the initial state for the fold to AOD animation. */
@Override
public void prepareFoldToAodAnimation() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
// Force show AOD UI even if we are not locked
@@ -3348,7 +3343,7 @@
@Override
public void startFoldToAodAnimation(Runnable startAction, Runnable endAction,
Runnable cancelAction) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
final ViewPropertyAnimator viewAnimator = mView.animate();
@@ -3386,7 +3381,7 @@
/** Cancels fold to AOD transition and resets view state. */
@Override
public void cancelFoldToAodAnimation() {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return;
}
cancelAnimation();
@@ -3597,11 +3592,6 @@
}
@Override
- public void disableHeader(int state1, int state2, boolean animated) {
- mShadeHeaderController.disable(state1, state2, animated);
- }
-
- @Override
public boolean closeUserSwitcherIfOpen() {
if (mKeyguardUserSwitcherController != null) {
return mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(
@@ -4381,6 +4371,10 @@
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
+ if (NotificationsHeadsUpRefactor.isEnabled()) {
+ return;
+ }
+
if (!isKeyguardShowing()) {
mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, true);
}
@@ -4388,6 +4382,9 @@
@Override
public void onHeadsUpUnPinned(NotificationEntry entry) {
+ if (NotificationsHeadsUpRefactor.isEnabled()) {
+ return;
+ }
// When we're unpinning the notification via active edge they remain heads-upped,
// we need to make sure that an animation happens in this case, otherwise the
@@ -4460,7 +4457,7 @@
&& statusBarState == KEYGUARD) {
// This means we're doing the screen off animation - position the keyguard status
// view where it'll be on AOD, so we can animate it in.
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX,
mClockPositionResult.clockYFullyDozing,
@@ -4469,7 +4466,7 @@
}
}
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
statusBarState,
keyguardFadingAway,
@@ -4477,7 +4474,7 @@
mBarState);
}
- if (!keyguardBottomAreaRefactor()) {
+ if (!KeyguardBottomAreaRefactor.isEnabled()) {
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
}
@@ -4582,7 +4579,7 @@
setDozing(true /* dozing */, false /* animate */);
mStatusBarStateController.setUpcomingState(KEYGUARD);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mStatusBarStateController.setState(KEYGUARD);
} else {
mStatusBarStateListener.onStateChanged(KEYGUARD);
@@ -4645,7 +4642,7 @@
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot (used by anti-burnin transformations)
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.updatePivot(mView.getWidth(), mView.getHeight());
}
@@ -4746,7 +4743,7 @@
stackScroller.setMaxAlphaForKeyguard(alpha, "NPVC.setTransitionAlpha()");
}
- if (keyguardBottomAreaRefactor()) {
+ if (KeyguardBottomAreaRefactor.isEnabled()) {
mKeyguardInteractor.setAlpha(alpha);
} else {
mKeyguardBottomAreaInteractor.setAlpha(alpha);
@@ -4765,7 +4762,7 @@
private Consumer<Float> setTransitionY(
NotificationStackScrollLayoutController stackScroller) {
return (Float translationY) -> {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mKeyguardStatusViewController.setTranslationY(translationY,
/* excludeMedia= */false);
stackScroller.setTranslationY(translationY);
@@ -4807,7 +4804,7 @@
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (migrateClocksToBlueprint() && !mUseExternalTouch) {
+ if (MigrateClocksToBlueprint.isEnabled() && !mUseExternalTouch) {
return false;
}
@@ -4878,7 +4875,7 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mCentralSurfaces.userActivity();
}
mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation;
@@ -4979,7 +4976,7 @@
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (migrateClocksToBlueprint() && !mUseExternalTouch) {
+ if (MigrateClocksToBlueprint.isEnabled() && !mUseExternalTouch) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index e577178..e8e629c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -16,7 +16,6 @@
package com.android.systemui.shade;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
@@ -48,6 +47,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -320,7 +320,7 @@
mTouchActive = true;
mTouchCancelled = false;
mDownEvent = ev;
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
mService.userActivity();
}
} else if (ev.getActionMasked() == MotionEvent.ACTION_UP
@@ -475,7 +475,7 @@
&& !bouncerShowing
&& !mStatusBarStateController.isDozing()) {
if (mDragDownHelper.isDragDownEnabled()) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
// When on lockscreen, if the touch originates at the top of the screen
// go directly to QS and not the shade
if (mStatusBarStateController.getState() == KEYGUARD
@@ -488,7 +488,7 @@
// This handles drag down over lockscreen
boolean result = mDragDownHelper.onInterceptTouchEvent(ev);
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
if (result) {
mLastInterceptWasDragDownHelper = true;
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -511,7 +511,7 @@
return true;
}
}
- } else if (migrateClocksToBlueprint()) {
+ } else if (MigrateClocksToBlueprint.isEnabled()) {
// This final check handles swipes on HUNs and when Pulsing
if (!bouncerShowing && didNotificationPanelInterceptEvent(ev)) {
mShadeLogger.d("NSWVC: intercepted for HUN/PULSING");
@@ -526,7 +526,7 @@
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
}
cancellation.recycle();
@@ -541,7 +541,7 @@
if (mStatusBarKeyguardViewManager.onTouch(ev)) {
return true;
}
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) {
// we still want to finish our drag down gesture when locking the screen
handled |= mDragDownHelper.onTouchEvent(ev) || handled;
@@ -631,7 +631,7 @@
}
private boolean didNotificationPanelInterceptEvent(MotionEvent ev) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
// Since NotificationStackScrollLayout is now a sibling of notification_panel, we need
// to also ask NotificationPanelViewController directly, in order to process swipe up
// events originating from notifications
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 29de688..8b88da1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -28,10 +28,10 @@
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.lifecycle.lifecycleScope
import com.android.systemui.Flags.centralizedStatusBarHeightFix
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.fragments.FragmentService
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.navigationbar.NavigationModeController
import com.android.systemui.plugins.qs.QS
@@ -52,11 +52,12 @@
import kotlin.reflect.KMutableProperty0
import kotlinx.coroutines.launch
-@VisibleForTesting
-internal const val INSET_DEBOUNCE_MILLIS = 500L
+@VisibleForTesting internal const val INSET_DEBOUNCE_MILLIS = 500L
@SysUISingleton
-class NotificationsQSContainerController @Inject constructor(
+class NotificationsQSContainerController
+@Inject
+constructor(
view: NotificationsQuickSettingsContainer,
private val navigationModeController: NavigationModeController,
private val overviewProxyService: OverviewProxyService,
@@ -64,8 +65,7 @@
private val shadeInteractor: ShadeInteractor,
private val fragmentService: FragmentService,
@Main private val delayableExecutor: DelayableExecutor,
- private val
- notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
+ private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
private val splitShadeStateController: SplitShadeStateController,
private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
@@ -88,45 +88,48 @@
private var isGestureNavigation = true
private var taskbarVisible = false
- private val taskbarVisibilityListener: OverviewProxyListener = object : OverviewProxyListener {
- override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) {
- taskbarVisible = visible
+ private val taskbarVisibilityListener: OverviewProxyListener =
+ object : OverviewProxyListener {
+ override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) {
+ taskbarVisible = visible
+ }
}
- }
// With certain configuration changes (like light/dark changes), the nav bar will disappear
// for a bit, causing `bottomStableInsets` to be unstable for some time. Debounce the value
// for 500ms.
// All interactions with this object happen in the main thread.
- private val delayedInsetSetter = object : Runnable, Consumer<WindowInsets> {
- private var canceller: Runnable? = null
- private var stableInsets = 0
- private var cutoutInsets = 0
+ private val delayedInsetSetter =
+ object : Runnable, Consumer<WindowInsets> {
+ private var canceller: Runnable? = null
+ private var stableInsets = 0
+ private var cutoutInsets = 0
- override fun accept(insets: WindowInsets) {
- // when taskbar is visible, stableInsetBottom will include its height
- stableInsets = insets.stableInsetBottom
- cutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
- canceller?.run()
- canceller = delayableExecutor.executeDelayed(this, INSET_DEBOUNCE_MILLIS)
- }
+ override fun accept(insets: WindowInsets) {
+ // when taskbar is visible, stableInsetBottom will include its height
+ stableInsets = insets.stableInsetBottom
+ cutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
+ canceller?.run()
+ canceller = delayableExecutor.executeDelayed(this, INSET_DEBOUNCE_MILLIS)
+ }
- override fun run() {
- bottomStableInsets = stableInsets
- bottomCutoutInsets = cutoutInsets
- updateBottomSpacing()
+ override fun run() {
+ bottomStableInsets = stableInsets
+ bottomCutoutInsets = cutoutInsets
+ updateBottomSpacing()
+ }
}
- }
override fun onInit() {
mView.repeatWhenAttached {
lifecycleScope.launch {
- shadeInteractor.isQsExpanded.collect{ _ -> mView.invalidate() }
+ shadeInteractor.isQsExpanded.collect { _ -> mView.invalidate() }
}
}
- val currentMode: Int = navigationModeController.addListener { mode: Int ->
- isGestureNavigation = QuickStepContract.isGesturalMode(mode)
- }
+ val currentMode: Int =
+ navigationModeController.addListener { mode: Int ->
+ isGestureNavigation = QuickStepContract.isGesturalMode(mode)
+ }
isGestureNavigation = QuickStepContract.isGesturalMode(currentMode)
mView.setStackScroller(notificationStackScrollLayoutController.getView())
@@ -151,30 +154,35 @@
fun updateResources() {
val newSplitShadeEnabled =
- splitShadeStateController.shouldUseSplitNotificationShade(resources)
+ splitShadeStateController.shouldUseSplitNotificationShade(resources)
val splitShadeEnabledChanged = newSplitShadeEnabled != splitShadeEnabled
splitShadeEnabled = newSplitShadeEnabled
largeScreenShadeHeaderActive = LargeScreenUtils.shouldUseLargeScreenShadeHeader(resources)
- notificationsBottomMargin = resources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_bottom)
+ notificationsBottomMargin =
+ resources.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom)
largeScreenShadeHeaderHeight = calculateLargeShadeHeaderHeight()
shadeHeaderHeight = calculateShadeHeaderHeight()
- panelMarginHorizontal = resources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_horizontal)
- topMargin = if (largeScreenShadeHeaderActive) {
- largeScreenShadeHeaderHeight
- } else {
- resources.getDimensionPixelSize(R.dimen.notification_panel_margin_top)
- }
+ panelMarginHorizontal =
+ resources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)
+ topMargin =
+ if (largeScreenShadeHeaderActive) {
+ largeScreenShadeHeaderHeight
+ } else {
+ resources.getDimensionPixelSize(R.dimen.notification_panel_margin_top)
+ }
updateConstraints()
- val scrimMarginChanged = ::scrimShadeBottomMargin.setAndReportChange(
- resources.getDimensionPixelSize(R.dimen.split_shade_notifications_scrim_margin_bottom)
- )
- val footerOffsetChanged = ::footerActionsOffset.setAndReportChange(
- resources.getDimensionPixelSize(R.dimen.qs_footer_action_inset) +
- resources.getDimensionPixelSize(R.dimen.qs_footer_actions_bottom_padding)
- )
+ val scrimMarginChanged =
+ ::scrimShadeBottomMargin.setAndReportChange(
+ resources.getDimensionPixelSize(
+ R.dimen.split_shade_notifications_scrim_margin_bottom
+ )
+ )
+ val footerOffsetChanged =
+ ::footerActionsOffset.setAndReportChange(
+ resources.getDimensionPixelSize(R.dimen.qs_footer_action_inset) +
+ resources.getDimensionPixelSize(R.dimen.qs_footer_actions_bottom_padding)
+ )
val dimensChanged = scrimMarginChanged || footerOffsetChanged
if (splitShadeEnabledChanged || dimensChanged) {
@@ -198,7 +206,7 @@
// 2. carrier_group height (R.dimen.large_screen_shade_header_min_height)
// 3. date height (R.dimen.new_qs_header_non_clickable_element_height)
val estimatedHeight =
- 2 * resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height) +
+ 2 * resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height) +
resources.getDimensionPixelSize(R.dimen.new_qs_header_non_clickable_element_height)
return estimatedHeight.coerceAtLeast(minHeight)
}
@@ -250,16 +258,17 @@
containerPadding = 0
stackScrollMargin = bottomStableInsets + notificationsBottomMargin
}
- val qsContainerPadding = if (!isQSDetailShowing) {
- // We also want this padding in the bottom in these cases
- if (splitShadeEnabled) {
- stackScrollMargin - scrimShadeBottomMargin - footerActionsOffset
+ val qsContainerPadding =
+ if (!isQSDetailShowing) {
+ // We also want this padding in the bottom in these cases
+ if (splitShadeEnabled) {
+ stackScrollMargin - scrimShadeBottomMargin - footerActionsOffset
+ } else {
+ bottomStableInsets
+ }
} else {
- bottomStableInsets
+ 0
}
- } else {
- 0
- }
return Paddings(containerPadding, stackScrollMargin, qsContainerPadding)
}
@@ -284,7 +293,7 @@
}
private fun setNotificationsConstraints(constraintSet: ConstraintSet) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled) {
return
}
val startConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
@@ -309,8 +318,8 @@
}
private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) {
- val statusViewMarginHorizontal = resources.getDimensionPixelSize(
- R.dimen.status_view_margin_horizontal)
+ val statusViewMarginHorizontal =
+ resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
constraintSet.apply {
setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal)
setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
index e82f2d3..1333055 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
@@ -18,8 +18,6 @@
import static androidx.constraintlayout.core.widgets.Optimizer.OPTIMIZATION_GRAPH;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
-
import android.app.Fragment;
import android.content.Context;
import android.content.res.Configuration;
@@ -35,6 +33,7 @@
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
@@ -190,7 +189,7 @@
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- if (migrateClocksToBlueprint()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
return super.drawChild(canvas, child, drawingTime);
}
int layoutIndex = mLayoutDrawingOrder.indexOf(child);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 8ba0544..3a0e167 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -21,7 +21,6 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.systemui.Flags.centralizedStatusBarHeightFix;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.shade.NotificationPanelViewController.COUNTER_PANEL_OPEN_QS;
import static com.android.systemui.shade.NotificationPanelViewController.FLING_COLLAPSE;
@@ -71,6 +70,7 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
@@ -1280,18 +1280,20 @@
mScrimController.setScrimCornerRadius(radius);
- // Convert global clipping coordinates to local ones,
- // relative to NotificationStackScrollLayout
- int nsslLeft = calculateNsslLeft(left);
- int nsslRight = calculateNsslRight(right);
- int nsslTop = getNotificationsClippingTopBounds(top);
- int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
- int bottomRadius = mSplitShadeEnabled ? radius : 0;
- // TODO (b/265193930): remove dependency on NPVC
- int topRadius = mSplitShadeEnabled
- && mPanelViewControllerLazy.get().isExpandingFromHeadsUp() ? 0 : radius;
- mNotificationStackScrollLayoutController.setRoundedClippingBounds(
- nsslLeft, nsslTop, nsslRight, nsslBottom, topRadius, bottomRadius);
+ if (!SceneContainerFlag.isEnabled()) {
+ // Convert global clipping coordinates to local ones,
+ // relative to NotificationStackScrollLayout
+ int nsslLeft = calculateNsslLeft(left);
+ int nsslRight = calculateNsslRight(right);
+ int nsslTop = getNotificationsClippingTopBounds(top);
+ int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
+ int bottomRadius = mSplitShadeEnabled ? radius : 0;
+ // TODO (b/265193930): remove dependency on NPVC
+ int topRadius = mSplitShadeEnabled
+ && mPanelViewControllerLazy.get().isExpandingFromHeadsUp() ? 0 : radius;
+ mNotificationStackScrollLayoutController.setRoundedClippingBounds(
+ nsslLeft, nsslTop, nsslRight, nsslBottom, topRadius, bottomRadius);
+ }
}
/**
@@ -1776,7 +1778,7 @@
// Dragging down on the lockscreen statusbar should prohibit other interactions
// immediately, otherwise we'll wait on the touchslop. This is to allow
// dragging down to expanded quick settings directly on the lockscreen.
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
}
}
@@ -1821,7 +1823,7 @@
&& Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(
mInitialTouchX, mInitialTouchY, h)) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mPanelView.getParent().requestDisallowInterceptTouchEvent(true);
}
mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 5f5e5ce..037dc4d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -21,15 +21,13 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewTreeObserver;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.systemui.DejankUtils;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.dagger.ShadeTouchLog;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
@@ -81,7 +79,6 @@
public ShadeControllerImpl(
CommandQueue commandQueue,
@Main Executor mainExecutor,
- @ShadeTouchLog LogBuffer touchLog,
WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
@@ -89,13 +86,12 @@
StatusBarWindowController statusBarWindowController,
DeviceProvisionedController deviceProvisionedController,
NotificationShadeWindowController notificationShadeWindowController,
- WindowManager windowManager,
+ @DisplayId int displayId,
Lazy<NotificationPanelViewController> shadeViewControllerLazy,
Lazy<AssistManager> assistManagerLazy,
Lazy<NotificationGutsManager> gutsManager
) {
- super(touchLog,
- commandQueue,
+ super(commandQueue,
statusBarKeyguardViewManager,
notificationShadeWindowController,
assistManagerLazy);
@@ -110,7 +106,7 @@
mGutsManager = gutsManager;
mNotificationShadeWindowController = notificationShadeWindowController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- mDisplayId = windowManager.getDefaultDisplay().getDisplayId();
+ mDisplayId = displayId;
mKeyguardStateController = keyguardStateController;
mAssistManagerLazy = assistManagerLazy;
}
@@ -385,7 +381,6 @@
@Override
public void start() {
- super.start();
getNpvc().setTrackingStartedListener(this::runPostCollapseActions);
getNpvc().setOpenCloseListener(
new OpenCloseListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index c20efea..c5e07e8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -70,7 +70,6 @@
assistManagerLazy: Lazy<AssistManager>,
) :
BaseShadeControllerImpl(
- touchLog,
commandQueue,
statusBarKeyguardViewManager,
notificationShadeWindowController,
@@ -248,7 +247,7 @@
}
override fun onStatusBarTouch(event: MotionEvent) {
- // The only call to this doesn't happen with migrateClocksToBlueprint() enabled
+ // The only call to this doesn't happen with MigrateClocksToBlueprint.isEnabled enabled
throw UnsupportedOperationException()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt
index 25e27ae..7425807 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt
@@ -27,6 +27,7 @@
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractorEmptyImpl
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 3e9a32b..2d3833c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -36,6 +36,7 @@
import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl
import com.android.systemui.shade.domain.interactor.ShadeInteractorSceneContainerImpl
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractorImpl
import dagger.Binds
import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 5c276b1..d02c215 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -18,6 +18,7 @@
import android.view.ViewPropertyAnimator
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.statusbar.GestureRecorder
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.HeadsUpManager
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 9902a32..9963f81 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -36,13 +36,6 @@
/** Returns whether status bar icons should be hidden when the shade is expanded. */
fun shouldHideStatusBarIconsWhenExpanded(): Boolean
- /**
- * Disables the shade header.
- *
- * @see ShadeHeaderController.disable
- */
- fun disableHeader(state1: Int, state2: Int, animated: Boolean)
-
/** If the latency tracker is enabled, begins tracking expand latency. */
@Deprecated("No longer supported. Do not add new calls to this.")
fun startExpandLatencyTracking()
@@ -71,14 +64,6 @@
fun updateTouchableRegion()
/**
- * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
- * screen off animation controller in order to animate in AOD without "actually" fully switching
- * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
- * change.
- */
- fun showAodUi()
-
- /**
* Sends an external (e.g. Status Bar) touch event to the Shade touch handler.
*
* This is different from [startInputFocusTransfer] as it doesn't rely on setting the launcher
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 93c3772..e037c70 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -20,6 +20,7 @@
import android.view.ViewGroup
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController
import java.util.function.Consumer
@@ -44,7 +45,6 @@
override val isViewEnabled: Boolean = false
override fun shouldHideStatusBarIconsWhenExpanded() = false
@Deprecated("Not supported by scenes") override fun blockExpansionForCurrentTouch() {}
- override fun disableHeader(state1: Int, state2: Int, animated: Boolean) {}
override fun startExpandLatencyTracking() {}
override fun startBouncerPreHideAnimation() {}
override fun dozeTimeTick() {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index bc60c83..cde45f2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -66,7 +66,7 @@
val isAnyExpanded: StateFlow<Boolean>
/** The amount [0-1] that the shade has been opened. */
- val shadeExpansion: Flow<Float>
+ val shadeExpansion: StateFlow<Float>
/**
* The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index e9bb4c6..5fbd2cf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -29,7 +29,7 @@
private val inactiveFlowBoolean = MutableStateFlow(false)
private val inactiveFlowFloat = MutableStateFlow(0f)
override val isShadeEnabled: StateFlow<Boolean> = inactiveFlowBoolean
- override val shadeExpansion: Flow<Float> = inactiveFlowFloat
+ override val shadeExpansion: StateFlow<Float> = inactiveFlowFloat
override val qsExpansion: StateFlow<Float> = inactiveFlowFloat
override val isQsExpanded: StateFlow<Boolean> = inactiveFlowBoolean
override val isQsBypassingShade: Flow<Boolean> = inactiveFlowBoolean
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
index 421a761..ac881b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
@@ -50,7 +50,7 @@
* The amount [0-1] that the shade has been opened. Uses stateIn to avoid redundant calculations
* in downstream flows.
*/
- override val shadeExpansion: Flow<Float> =
+ override val shadeExpansion: StateFlow<Float> =
combine(
repository.lockscreenShadeExpansion,
keyguardRepository.statusBarState,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 7785eda..7f35f17 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -49,7 +49,9 @@
sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
shadeRepository: ShadeRepository,
) : BaseShadeInteractor {
- override val shadeExpansion: Flow<Float> = sceneBasedExpansion(sceneInteractor, Scenes.Shade)
+ override val shadeExpansion: StateFlow<Float> =
+ sceneBasedExpansion(sceneInteractor, Scenes.Shade)
+ .stateIn(scope, SharingStarted.Eagerly, 0f)
private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLockscreenInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/shade/ShadeLockscreenInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt
index 859fce5..2611092 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLockscreenInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.shade
+package com.android.systemui.shade.domain.interactor
/** Allows the lockscreen to control the shade. */
interface ShadeLockscreenInteractor {
@@ -73,4 +73,12 @@
* @param alpha value between 0 and 1. -1 if the value is to be reset.
*/
@Deprecated("TODO(b/325072511) delete this") fun setKeyguardStatusBarAlpha(alpha: Float)
+
+ /**
+ * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
+ * screen off animation controller in order to animate in AOD without "actually" fully switching
+ * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
+ * change.
+ */
+ fun showAodUi()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
index d9c441f..318da55 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
@@ -20,7 +20,6 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.ShadeLockscreenInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@@ -84,6 +83,11 @@
// TODO(b/325072511) delete this
}
+ override fun showAodUi() {
+ sceneInteractor.changeScene(Scenes.Lockscreen, "showAodUi")
+ // TODO(b/330311871) implement transition to AOD
+ }
+
private fun changeToShadeScene() {
sceneInteractor.changeScene(
Scenes.Shade,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index 11ce818..1fb0fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -21,6 +21,11 @@
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.dagger.ShadeTouchLog
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeHeaderController
+import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.policy.SplitShadeStateController
@@ -36,13 +41,25 @@
constructor(
@Application private val applicationScope: CoroutineScope,
@Application private val applicationContext: Context,
+ @ShadeTouchLog private val touchLog: LogBuffer,
private val configurationRepository: ConfigurationRepository,
private val shadeRepository: ShadeRepository,
private val controller: SplitShadeStateController,
+ private val shadeController: ShadeController,
+ private val shadeHeaderController: ShadeHeaderController,
) : CoreStartable {
override fun start() {
hydrateShadeMode()
+ logTouchesTo(touchLog)
+ initHeaderController()
+ }
+
+ private fun initHeaderController() {
+ shadeHeaderController.init()
+ shadeHeaderController.shadeCollapseAction = Runnable {
+ shadeController.animateCollapseShade()
+ }
}
private fun hydrateShadeMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index ea549f2..24b7533 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -66,11 +66,13 @@
deviceEntryInteractor.isUnlocked,
deviceEntryInteractor.canSwipeToEnter,
shadeInteractor.shadeMode,
- ) { isUnlocked, canSwipeToDismiss, shadeMode ->
+ qsSceneAdapter.isCustomizing
+ ) { isUnlocked, canSwipeToDismiss, shadeMode, isCustomizing ->
destinationScenes(
isUnlocked = isUnlocked,
canSwipeToDismiss = canSwipeToDismiss,
shadeMode = shadeMode,
+ isCustomizing = isCustomizing
)
}
.stateIn(
@@ -81,6 +83,7 @@
isUnlocked = deviceEntryInteractor.isUnlocked.value,
canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value,
shadeMode = shadeInteractor.shadeMode.value,
+ isCustomizing = qsSceneAdapter.isCustomizing.value,
),
)
@@ -120,6 +123,7 @@
isUnlocked: Boolean,
canSwipeToDismiss: Boolean?,
shadeMode: ShadeMode,
+ isCustomizing: Boolean,
): Map<UserAction, UserActionResult> {
val up =
when {
@@ -131,7 +135,9 @@
val down = Scenes.QuickSettings.takeIf { shadeMode is ShadeMode.Single }
return buildMap {
- this[Swipe(SwipeDirection.Up)] = UserActionResult(up)
+ if (!isCustomizing) {
+ this[Swipe(SwipeDirection.Up)] = UserActionResult(up)
+ } // TODO(b/330200163) Add an else to be able to collapse the shade while customizing
down?.let { this[Swipe(SwipeDirection.Down)] = UserActionResult(down) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 4406813..e7b159a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -529,9 +529,9 @@
default void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) {}
/**
- * @see IStatusBar#enterDesktop(int)
+ * @see IStatusBar#moveFocusedTaskToDesktop(int)
*/
- default void enterDesktop(int displayId) {}
+ default void moveFocusedTaskToDesktop(int displayId) {}
}
@VisibleForTesting
@@ -1444,7 +1444,7 @@
}
@Override
- public void enterDesktop(int displayId) {
+ public void moveFocusedTaskToDesktop(int displayId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = displayId;
mHandler.obtainMessage(MSG_ENTER_DESKTOP, args).sendToTarget();
@@ -1960,7 +1960,7 @@
args = (SomeArgs) msg.obj;
int displayId = args.argi1;
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).enterDesktop(displayId);
+ mCallbacks.get(i).moveFocusedTaskToDesktop(displayId);
}
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index da8c1be..d6858ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -631,34 +631,41 @@
// Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
// Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
// Switch from Split screen to full screen: Meta + Ctrl + Up arrow
- String[] shortcutLabels = {
- context.getString(R.string.system_multitasking_rhs),
- context.getString(R.string.system_multitasking_lhs),
- context.getString(R.string.system_multitasking_full_screen),
- };
- int[] keyCodes = {
- KeyEvent.KEYCODE_DPAD_RIGHT,
- KeyEvent.KEYCODE_DPAD_LEFT,
- KeyEvent.KEYCODE_DPAD_UP,
- };
-
- for (int i = 0; i < shortcutLabels.length; i++) {
- List<ShortcutKeyGroup> shortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(
- new KeyboardShortcutInfo(
- shortcutLabels[i],
- keyCodes[i],
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON),
- null));
- ShortcutMultiMappingInfo shortcutMultiMappingInfo =
- new ShortcutMultiMappingInfo(
- shortcutLabels[i],
- null,
- shortcutKeyGroups);
- systemMultitaskingGroup.addItem(shortcutMultiMappingInfo);
- }
+ // Change split screen focus to RHS: Meta + Alt + Right arrow
+ // Change split screen focus to LHS: Meta + Alt + Left arrow
+ systemMultitaskingGroup.addItem(
+ getMultitaskingShortcut(context.getString(R.string.system_multitasking_rhs),
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON));
+ systemMultitaskingGroup.addItem(
+ getMultitaskingShortcut(context.getString(R.string.system_multitasking_lhs),
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON));
+ systemMultitaskingGroup.addItem(
+ getMultitaskingShortcut(context.getString(R.string.system_multitasking_full_screen),
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON));
+ systemMultitaskingGroup.addItem(
+ getMultitaskingShortcut(
+ context.getString(R.string.system_multitasking_splitscreen_focus_rhs),
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON));
+ systemMultitaskingGroup.addItem(
+ getMultitaskingShortcut(
+ context.getString(R.string.system_multitasking_splitscreen_focus_lhs),
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON));
return systemMultitaskingGroup;
}
+ private static ShortcutMultiMappingInfo getMultitaskingShortcut(String shortcutLabel,
+ int keycode, int modifiers) {
+ List<ShortcutKeyGroup> shortcutKeyGroups = Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(shortcutLabel, keycode, modifiers),
+ null));
+ return new ShortcutMultiMappingInfo(shortcutLabel, null, shortcutKeyGroups);
+ }
+
private static KeyboardShortcutMultiMappingGroup getMultiMappingInputShortcuts(
Context context) {
List<ShortcutMultiMappingInfo> shortcutMultiMappingInfoList = Arrays.asList(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
index 9f098e7..72f2aa5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
@@ -6,7 +6,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
import com.android.systemui.res.R
-import com.android.systemui.shade.ShadeLockscreenInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 4b16126..fc1dc62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -15,13 +15,13 @@
import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper
import com.android.systemui.Flags.nsslFalsingFix
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.Gefingerpoken
import com.android.systemui.biometrics.UdfpsKeyguardViewControllerLegacy
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
@@ -33,7 +33,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.res.R
-import com.android.systemui.shade.ShadeLockscreenInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -69,7 +69,7 @@
private val mediaHierarchyManager: MediaHierarchyManager,
private val scrimTransitionController: LockscreenShadeScrimTransitionController,
private val keyguardTransitionControllerFactory:
- LockscreenShadeKeyguardTransitionController.Factory,
+ LockscreenShadeKeyguardTransitionController.Factory,
private val depthController: NotificationShadeDepthController,
private val context: Context,
private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory,
@@ -292,8 +292,7 @@
/** @return true if the interaction is accepted, false if it should be cancelled */
internal fun canDragDown(): Boolean {
return (statusBarStateController.state == StatusBarState.KEYGUARD ||
- nsslController.isInLockedDownShade()) &&
- (isQsFullyCollapsed || useSplitShade)
+ nsslController.isInLockedDownShade()) && (isQsFullyCollapsed || useSplitShade)
}
/** Called by the touch helper when when a gesture has completed all the way and released. */
@@ -885,7 +884,7 @@
isDraggingDown = false
isTrackpadReverseScroll = false
shadeRepository.setLegacyLockscreenShadeTracking(false)
- if (nsslFalsingFix() || migrateClocksToBlueprint()) {
+ if (nsslFalsingFix() || MigrateClocksToBlueprint.isEnabled) {
return true
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 5171a5c..9a82ecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -863,7 +863,7 @@
boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
iconState.hidden = isAppearing
|| (view instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow) view).isLowPriority()
+ && ((ExpandableNotificationRow) view).isMinimized()
&& mShelfIcons.areIconsOverflowing())
|| (transitionAmount == 0.0f && !iconState.isAnimating(icon))
|| row.isAboveShelf()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index e0dd7f0..9b2a6df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -46,6 +46,9 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
+import com.android.systemui.plugins.clocks.ClockController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
@@ -108,6 +111,7 @@
private final Lazy<ShadeInteractor> mShadeInteractorLazy;
private final Lazy<DeviceUnlockedInteractor> mDeviceUnlockedInteractorLazy;
private final Lazy<SceneInteractor> mSceneInteractorLazy;
+ private final Lazy<KeyguardClockInteractor> mKeyguardClockInteractorLazy;
private int mState;
private int mLastState;
private int mUpcomingState;
@@ -173,13 +177,15 @@
JavaAdapter javaAdapter,
Lazy<ShadeInteractor> shadeInteractorLazy,
Lazy<DeviceUnlockedInteractor> deviceUnlockedInteractorLazy,
- Lazy<SceneInteractor> sceneInteractorLazy) {
+ Lazy<SceneInteractor> sceneInteractorLazy,
+ Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy) {
mUiEventLogger = uiEventLogger;
mInteractionJankMonitor = interactionJankMonitor;
mJavaAdapter = javaAdapter;
mShadeInteractorLazy = shadeInteractorLazy;
mDeviceUnlockedInteractorLazy = deviceUnlockedInteractorLazy;
mSceneInteractorLazy = sceneInteractorLazy;
+ mKeyguardClockInteractorLazy = keyguardClockInteractorLazy;
for (int i = 0; i < HISTORY_SIZE; i++) {
mHistoricalRecords[i] = new HistoricalState();
}
@@ -461,6 +467,16 @@
/** Returns the id of the currently rendering clock */
public String getClockId() {
+ if (MigrateClocksToBlueprint.isEnabled()) {
+ ClockController clock = mKeyguardClockInteractorLazy.get()
+ .getCurrentClock().getValue();
+ if (clock == null) {
+ Log.e(TAG, "No clock is available");
+ return KeyguardClockSwitch.MISSING_CLOCK_ID;
+ }
+ return clock.getConfig().getId();
+ }
+
if (mClockSwitchView == null) {
Log.e(TAG, "Clock container was missing");
return KeyguardClockSwitch.MISSING_CLOCK_ID;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index e111525..8cdf60b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -42,7 +42,6 @@
import android.app.RemoteInput;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
-import android.content.pm.ShortcutInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
@@ -133,7 +132,6 @@
public Uri remoteInputUri;
public ContentInfo remoteInputAttachment;
private Notification.BubbleMetadata mBubbleMetadata;
- private ShortcutInfo mShortcutInfo;
/**
* If {@link RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is
@@ -168,10 +166,8 @@
private ListenerSet<OnSensitivityChangedListener> mOnSensitivityChangedListeners =
new ListenerSet<>();
- private boolean mAutoHeadsUp;
private boolean mPulseSupressed;
private int mBucket = BUCKET_ALERTING;
- @Nullable private Long mPendingAnimationDuration;
private boolean mIsMarkedForUserTriggeredMovement;
private boolean mIsHeadsUpEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 0c69a65..8531eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -22,6 +22,7 @@
import android.provider.Settings
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
+import com.android.systemui.Flags.notificationMinimalismPrototype
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
@@ -59,6 +60,7 @@
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -260,8 +262,11 @@
}
}
- private suspend fun trackUnseenFilterSettingChanges() {
- secureSettings
+ private fun unseenFeatureEnabled(): Flow<Boolean> {
+ if (notificationMinimalismPrototype()) {
+ return flowOf(true)
+ }
+ return secureSettings
// emit whenever the setting has changed
.observerFlow(
UserHandle.USER_ALL,
@@ -283,17 +288,20 @@
// only track the most recent emission, if events are happening faster than they can be
// consumed
.conflate()
- .collectLatest { setting ->
- // update local field and invalidate if necessary
- if (setting != unseenFilterEnabled) {
- unseenFilterEnabled = setting
- unseenNotifFilter.invalidateList("unseen setting changed")
- }
- // if the setting is enabled, then start tracking and filtering unseen notifications
- if (setting) {
- trackSeenNotifications()
- }
+ }
+
+ private suspend fun trackUnseenFilterSettingChanges() {
+ unseenFeatureEnabled().collectLatest { setting ->
+ // update local field and invalidate if necessary
+ if (setting != unseenFilterEnabled) {
+ unseenFilterEnabled = setting
+ unseenNotifFilter.invalidateList("unseen setting changed")
}
+ // if the setting is enabled, then start tracking and filtering unseen notifications
+ if (setting) {
+ trackSeenNotifications()
+ }
+ }
}
private val collectionListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index dcfccd8..0bbde21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static com.android.systemui.media.controls.domain.pipeline.MediaDataManagerKt.isMediaNotification;
+import static com.android.systemui.media.controls.domain.pipeline.MediaDataManager.isMediaNotification;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index dfb0f9b..7a7b184 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -363,7 +363,7 @@
NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) {
return new NotifInflater.Params(
- /* isLowPriority = */ adjustment.isMinimized(),
+ /* isMinimized = */ adjustment.isMinimized(),
/* reason = */ reason,
/* showSnooze = */ adjustment.isSnoozeEnabled(),
/* isChildInGroup = */ adjustment.isChildInGroup(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
index 7b8a062..ff72888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
@@ -56,7 +56,7 @@
/** A class holding parameters used when inflating the notification row */
class Params(
- val isLowPriority: Boolean,
+ val isMinimized: Boolean,
val reason: String,
val showSnooze: Boolean,
val isChildInGroup: Boolean = false,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4bbe035..4a895c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -243,7 +243,7 @@
@Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
final boolean useIncreasedCollapsedHeight =
mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance());
- final boolean isLowPriority = inflaterParams.isLowPriority();
+ final boolean isMinimized = inflaterParams.isMinimized();
// Set show snooze action
row.setShowSnooze(inflaterParams.getShowSnooze());
@@ -252,7 +252,7 @@
params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
- params.setUseLowPriority(isLowPriority);
+ params.setUseMinimized(isMinimized);
if (screenshareNotificationHiding()
? inflaterParams.getNeedsRedaction()
@@ -275,7 +275,7 @@
if (AsyncGroupHeaderViewInflation.isEnabled()) {
if (inflaterParams.isGroupSummary()) {
params.requireContentViews(FLAG_GROUP_SUMMARY_HEADER);
- if (isLowPriority) {
+ if (isMinimized) {
params.requireContentViews(FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER);
}
} else {
@@ -288,7 +288,7 @@
mRowContentBindStage.requestRebind(entry, en -> {
mLogger.logRebindComplete(entry);
row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
- row.setIsLowPriority(isLowPriority);
+ row.setIsMinimized(isMinimized);
if (inflationCallback != null) {
inflationCallback.onAsyncInflationFinished(en);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index e5e5292..2b0d2aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.statusbar.notification.data
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationRepository
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationRepositoryImpl
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import dagger.Binds
import dagger.Module
@@ -27,8 +27,5 @@
]
)
interface NotificationDataLayerModule {
- @Binds
- fun bindHeadsUpNotificationRepository(
- impl: HeadsUpNotificationRepositoryImpl
- ): HeadsUpNotificationRepository
+ @Binds fun bindHeadsUpNotificationRepository(impl: HeadsUpManagerPhone): HeadsUpRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationRepository.kt
deleted file mode 100644
index d60ee98..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationRepository.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.notification.data.repository
-
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
-import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-
-class HeadsUpNotificationRepositoryImpl
-@Inject
-constructor(
- headsUpManager: HeadsUpManager,
-) : HeadsUpNotificationRepository {
- override val hasPinnedHeadsUp: Flow<Boolean> = conflatedCallbackFlow {
- val listener =
- object : OnHeadsUpChangedListener {
- override fun onHeadsUpPinnedModeChanged(inPinnedMode: Boolean) {
- trySend(headsUpManager.hasPinnedHeadsUp())
- }
-
- override fun onHeadsUpPinned(entry: NotificationEntry?) {
- trySend(headsUpManager.hasPinnedHeadsUp())
- }
-
- override fun onHeadsUpUnPinned(entry: NotificationEntry?) {
- trySend(headsUpManager.hasPinnedHeadsUp())
- }
-
- override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
- trySend(headsUpManager.hasPinnedHeadsUp())
- }
- }
- trySend(headsUpManager.hasPinnedHeadsUp())
- headsUpManager.addListener(listener)
- awaitClose { headsUpManager.removeListener(listener) }
- }
-}
-
-interface HeadsUpNotificationRepository {
- val hasPinnedHeadsUp: Flow<Boolean>
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt
new file mode 100644
index 0000000..ed8c056
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.notification.data.repository
+
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * A repository of currently displayed heads up notifications.
+ *
+ * This repository serves as a boundary between the
+ * [com.android.systemui.statusbar.policy.HeadsUpManager] and the modern notifications presentation
+ * codebase.
+ */
+interface HeadsUpRepository {
+
+ /**
+ * True if we are exiting the headsUp pinned mode, and some notifications might still be
+ * animating out. This is used to keep the touchable regions in a reasonable state.
+ */
+ val headsUpAnimatingAway: Flow<Boolean>
+
+ /** The heads up row that should be displayed on top. */
+ val topHeadsUpRow: Flow<HeadsUpRowRepository?>
+
+ /** Set of currently active top-level heads up rows to be displayed. */
+ val activeHeadsUpRows: Flow<Set<HeadsUpRowRepository>>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt
new file mode 100644
index 0000000..7b40812
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRowRepository.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.notification.data.repository
+
+import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
+import kotlinx.coroutines.flow.StateFlow
+
+/** Representation of a top-level heads up row. */
+interface HeadsUpRowRepository : HeadsUpRowKey {
+ /**
+ * The key for this notification. Guaranteed to be immutable and unique.
+ *
+ * @see com.android.systemui.statusbar.notification.collection.NotificationEntry.getKey
+ */
+ val key: String
+
+ /** A key to identify this row in the view hierarchy. */
+ val elementKey: Any
+
+ /** Whether this notification is "pinned", meaning that it should stay on top of the screen. */
+ val isPinned: StateFlow<Boolean>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
index 5c8f354..d1dd7b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
@@ -14,14 +14,59 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.statusbar.notification.domain.interactor
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
+import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
-class HeadsUpNotificationInteractor @Inject constructor(repository: HeadsUpNotificationRepository) {
+class HeadsUpNotificationInteractor @Inject constructor(repository: HeadsUpRepository) {
+
+ val topHeadsUpRow: Flow<HeadsUpRowKey?> = repository.topHeadsUpRow
+
+ /** Set of currently pinned top-level heads up rows to be displayed. */
+ val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> =
+ repository.activeHeadsUpRows.flatMapLatest { repositories ->
+ if (repositories.isNotEmpty()) {
+ val toCombine: List<Flow<Pair<HeadsUpRowRepository, Boolean>>> =
+ repositories.map { repo -> repo.isPinned.map { isPinned -> repo to isPinned } }
+ combine(toCombine) { pairs ->
+ pairs.filter { (_, isPinned) -> isPinned }.map { (repo, _) -> repo }.toSet()
+ }
+ } else {
+ // if the set is empty, there are no flows to combine
+ flowOf(emptySet())
+ }
+ }
+
+ /** Are there any pinned heads up rows to display? */
+ val hasPinnedRows: Flow<Boolean> =
+ repository.activeHeadsUpRows.flatMapLatest { rows ->
+ if (rows.isNotEmpty()) {
+ combine(rows.map { it.isPinned }) { pins -> pins.any { it } }
+ } else {
+ // if the set is empty, there are no flows to combine
+ flowOf(false)
+ }
+ }
+
val isHeadsUpOrAnimatingAway: Flow<Boolean> =
- // TODO(b/296118689): Needs to include the animating away state.
- repository.hasPinnedHeadsUp
+ combine(hasPinnedRows, repository.headsUpAnimatingAway) { hasPinnedRows, animatingAway ->
+ hasPinnedRows || animatingAway
+ }
+
+ fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
+ HeadsUpRowInteractor(key as HeadsUpRowRepository)
+ fun elementKeyFor(key: HeadsUpRowKey) = (key as HeadsUpRowRepository).elementKey
}
+
+class HeadsUpRowInteractor(repository: HeadsUpRowRepository)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index f792898..adcbbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -58,6 +58,7 @@
private FooterViewButton mClearAllButton;
private FooterViewButton mManageOrHistoryButton;
+ private boolean mShouldBeHidden;
private boolean mShowHistory;
// String cache, for performance reasons.
// Reading them from a Resources object can be quite slow sometimes.
@@ -110,6 +111,20 @@
setSecondaryVisible(visible, animate, onAnimationEnded);
}
+ /** See {@link this#setShouldBeHidden} below. */
+ public boolean shouldBeHidden() {
+ return mShouldBeHidden;
+ }
+
+ /**
+ * Whether this view's visibility should be set to INVISIBLE. Note that this is different from
+ * the {@link StackScrollerDecorView#setVisible} method, which in turn handles visibility
+ * transitions between VISIBLE and GONE.
+ */
+ public void setShouldBeHidden(boolean hide) {
+ mShouldBeHidden = hide;
+ }
+
@Override
public void dump(PrintWriter pwOriginal, String[] args) {
IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c05c3c3..eb6c7b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -327,7 +327,7 @@
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
- if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
+ if (!shouldShowPublic() && (!mIsMinimized || isExpanded())
&& mGroupMembershipManager.isGroupSummary(mEntry)) {
mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
@@ -382,7 +382,7 @@
private boolean mAboveShelf;
private OnUserInteractionCallback mOnUserInteractionCallback;
private NotificationGutsManager mNotificationGutsManager;
- private boolean mIsLowPriority;
+ private boolean mIsMinimized;
private boolean mUseIncreasedCollapsedHeight;
private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
@@ -467,7 +467,8 @@
if (viewWrapper != null) {
setIconAnimationRunningForChild(running, viewWrapper.getIcon());
}
- NotificationViewWrapper lowPriWrapper = mChildrenContainer.getLowPriorityViewWrapper();
+ NotificationViewWrapper lowPriWrapper = mChildrenContainer
+ .getMinimizedGroupHeaderWrapper();
if (lowPriWrapper != null) {
setIconAnimationRunningForChild(running, lowPriWrapper.getIcon());
}
@@ -680,7 +681,7 @@
if (color != Notification.COLOR_INVALID) {
return color;
} else {
- return mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
+ return mEntry.getContrastedColor(mContext, mIsMinimized && !isExpanded(),
getBackgroundColorWithoutTint());
}
}
@@ -1545,7 +1546,7 @@
* Set the low-priority group notification header view
* @param headerView header view to set
*/
- public void setLowPriorityGroupHeader(NotificationHeaderView headerView) {
+ public void setMinimizedGroupHeader(NotificationHeaderView headerView) {
NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
childrenContainer.setLowPriorityGroupHeader(
/* headerViewLowPriority= */ headerView,
@@ -1664,16 +1665,19 @@
}
}
- public void setIsLowPriority(boolean isLowPriority) {
- mIsLowPriority = isLowPriority;
- mPrivateLayout.setIsLowPriority(isLowPriority);
+ /**
+ * Set if the row is minimized.
+ */
+ public void setIsMinimized(boolean isMinimized) {
+ mIsMinimized = isMinimized;
+ mPrivateLayout.setIsLowPriority(isMinimized);
if (mChildrenContainer != null) {
- mChildrenContainer.setIsLowPriority(isLowPriority);
+ mChildrenContainer.setIsMinimized(isMinimized);
}
}
- public boolean isLowPriority() {
- return mIsLowPriority;
+ public boolean isMinimized() {
+ return mIsMinimized;
}
public void setUsesIncreasedCollapsedHeight(boolean use) {
@@ -1763,9 +1767,7 @@
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
this(context, attrs, context);
- if (com.android.systemui.Flags.notificationRowUserContext()) {
- Log.wtf(TAG, "This constructor shouldn't be called");
- }
+ Log.wtf(TAG, "This constructor shouldn't be called");
}
/**
@@ -2050,7 +2052,7 @@
mChildrenContainerStub = findViewById(R.id.child_container_stub);
mChildrenContainerStub.setOnInflateListener((stub, inflated) -> {
mChildrenContainer = (NotificationChildrenContainer) inflated;
- mChildrenContainer.setIsLowPriority(mIsLowPriority);
+ mChildrenContainer.setIsMinimized(mIsMinimized);
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
mChildrenContainer.setLogger(mChildrenContainerLogger);
@@ -3435,7 +3437,7 @@
private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
boolean nowExpanded = isExpanded();
- if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
+ if (mIsSummaryWithChildren && (!mIsMinimized || wasExpanded)) {
nowExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
}
if (nowExpanded != wasExpanded) {
@@ -3492,7 +3494,7 @@
if (!expandable) {
if (mIsSummaryWithChildren) {
expandable = true;
- if (!mIsLowPriority || isExpanded()) {
+ if (!mIsMinimized || isExpanded()) {
isExpanded = isGroupExpanded();
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 6bc2b2f..ba1cfcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -30,14 +30,21 @@
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.ConversationAvatarData;
+import com.android.internal.widget.ConversationAvatarData.GroupConversationAvatarData;
+import com.android.internal.widget.ConversationAvatarData.OneToOneConversationAvatarData;
+import com.android.internal.widget.ConversationHeaderData;
import com.android.internal.widget.ConversationLayout;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
+import com.android.systemui.statusbar.notification.row.shared.ConversationStyleSetAvatarAsync;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ConversationAvatar;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.FacePile;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleIcon;
+import java.util.Objects;
+
/**
* A hybrid view which may contain information about one ore more conversations.
*/
@@ -103,7 +110,7 @@
@Override
public void bind(@Nullable CharSequence title, @Nullable CharSequence text,
- @Nullable View contentView) {
+ @Nullable View contentView) {
AsyncHybridViewInflation.assertInLegacyMode();
if (!(contentView instanceof ConversationLayout)) {
super.bind(title, text, contentView);
@@ -111,34 +118,7 @@
}
ConversationLayout conversationLayout = (ConversationLayout) contentView;
- Icon conversationIcon = conversationLayout.getConversationIcon();
- if (conversationIcon != null) {
- mConversationFacePile.setVisibility(GONE);
- mConversationIconView.setVisibility(VISIBLE);
- mConversationIconView.setImageIcon(conversationIcon);
- setSize(mConversationIconView, mSingleAvatarSize);
- } else {
- // If there isn't an icon, generate a "face pile" based on the sender avatars
- mConversationIconView.setVisibility(GONE);
- mConversationFacePile.setVisibility(VISIBLE);
-
- mConversationFacePile =
- requireViewById(com.android.internal.R.id.conversation_face_pile);
- ImageView facePileBottomBg = mConversationFacePile.requireViewById(
- com.android.internal.R.id.conversation_face_pile_bottom_background);
- ImageView facePileBottom = mConversationFacePile.requireViewById(
- com.android.internal.R.id.conversation_face_pile_bottom);
- ImageView facePileTop = mConversationFacePile.requireViewById(
- com.android.internal.R.id.conversation_face_pile_top);
- conversationLayout.bindFacePile(facePileBottomBg, facePileBottom, facePileTop);
- setSize(mConversationFacePile, mFacePileSize);
- setSize(facePileBottom, mFacePileAvatarSize);
- setSize(facePileTop, mFacePileAvatarSize);
- setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
- mTransformationHelper.addViewTransformingToSimilar(facePileTop);
- mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
- mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
- }
+ loadConversationAvatar(conversationLayout);
CharSequence conversationTitle = conversationLayout.getConversationTitle();
if (TextUtils.isEmpty(conversationTitle)) {
conversationTitle = title;
@@ -156,6 +136,90 @@
super.bind(conversationTitle, conversationText, conversationLayout);
}
+ private void loadConversationAvatar(ConversationLayout conversationLayout) {
+ AsyncHybridViewInflation.assertInLegacyMode();
+ if (ConversationStyleSetAvatarAsync.isEnabled()) {
+ loadConversationAvatarWithDrawable(conversationLayout);
+ } else {
+ loadConversationAvatarWithIcon(conversationLayout);
+ }
+ }
+
+ @Deprecated
+ private void loadConversationAvatarWithIcon(ConversationLayout conversationLayout) {
+ ConversationStyleSetAvatarAsync.assertInLegacyMode();
+ AsyncHybridViewInflation.assertInLegacyMode();
+ final Icon conversationIcon = conversationLayout.getConversationIcon();
+ if (conversationIcon != null) {
+ mConversationFacePile.setVisibility(GONE);
+ mConversationIconView.setVisibility(VISIBLE);
+ mConversationIconView.setImageIcon(conversationIcon);
+ setSize(mConversationIconView, mSingleAvatarSize);
+ } else {
+ // If there isn't an icon, generate a "face pile" based on the sender avatars
+ mConversationIconView.setVisibility(GONE);
+ mConversationFacePile.setVisibility(VISIBLE);
+
+ mConversationFacePile =
+ requireViewById(com.android.internal.R.id.conversation_face_pile);
+ final ImageView facePileBottomBg = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom_background);
+ final ImageView facePileBottom = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom);
+ final ImageView facePileTop = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_top);
+ conversationLayout.bindFacePile(facePileBottomBg, facePileBottom, facePileTop);
+ setSize(mConversationFacePile, mFacePileSize);
+ setSize(facePileBottom, mFacePileAvatarSize);
+ setSize(facePileTop, mFacePileAvatarSize);
+ setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
+ mTransformationHelper.addViewTransformingToSimilar(facePileTop);
+ mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
+ mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
+ }
+ }
+
+ private void loadConversationAvatarWithDrawable(ConversationLayout conversationLayout) {
+ AsyncHybridViewInflation.assertInLegacyMode();
+ final ConversationHeaderData conversationHeaderData = Objects.requireNonNull(
+ conversationLayout.getConversationHeaderData(),
+ /* message = */ "conversationHeaderData should not be null");
+ final ConversationAvatarData conversationAvatar =
+ Objects.requireNonNull(conversationHeaderData.getConversationAvatar(),
+ /* message = */"conversationAvatar should not be null");
+
+ if (conversationAvatar instanceof OneToOneConversationAvatarData oneToOneAvatar) {
+ mConversationFacePile.setVisibility(GONE);
+ mConversationIconView.setVisibility(VISIBLE);
+ mConversationIconView.setImageDrawable(oneToOneAvatar.mDrawable);
+ setSize(mConversationIconView, mSingleAvatarSize);
+ } else {
+ // If there isn't an icon, generate a "face pile" based on the sender avatars
+ mConversationIconView.setVisibility(GONE);
+ mConversationFacePile.setVisibility(VISIBLE);
+
+ final GroupConversationAvatarData groupAvatar =
+ (GroupConversationAvatarData) conversationAvatar;
+ mConversationFacePile =
+ requireViewById(com.android.internal.R.id.conversation_face_pile);
+ final ImageView facePileBottomBg = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom_background);
+ final ImageView facePileBottom = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom);
+ final ImageView facePileTop = mConversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_top);
+ conversationLayout.bindFacePileWithDrawable(facePileBottomBg, facePileBottom,
+ facePileTop, groupAvatar);
+ setSize(mConversationFacePile, mFacePileSize);
+ setSize(facePileBottom, mFacePileAvatarSize);
+ setSize(facePileTop, mFacePileAvatarSize);
+ setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
+ mTransformationHelper.addViewTransformingToSimilar(facePileTop);
+ mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
+ mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
+ }
+ }
+
/**
* Set the avatar using ConversationAvatar from SingleLineViewModel
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index f835cca..ded635c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -150,7 +150,7 @@
entry,
mConversationProcessor,
row,
- bindParams.isLowPriority,
+ bindParams.isMinimized,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
callback,
@@ -178,7 +178,7 @@
SmartReplyStateInflater smartRepliesInflater) {
InflationProgress result = createRemoteViews(reInflateFlags,
builder,
- bindParams.isLowPriority,
+ bindParams.isMinimized,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
packageContext,
@@ -215,6 +215,7 @@
apply(
mInflationExecutor,
inflateSynchronously,
+ bindParams.isMinimized,
result,
reInflateFlags,
mRemoteViewCache,
@@ -365,7 +366,7 @@
}
private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags,
- Notification.Builder builder, boolean isLowPriority, boolean usesIncreasedHeight,
+ Notification.Builder builder, boolean isMinimized, boolean usesIncreasedHeight,
boolean usesIncreasedHeadsUpHeight, Context packageContext,
ExpandableNotificationRow row,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
@@ -376,13 +377,13 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating contracted remote view");
- result.newContentView = createContentView(builder, isLowPriority,
+ result.newContentView = createContentView(builder, isMinimized,
usesIncreasedHeight);
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating expanded remote view");
- result.newExpandedView = createExpandedView(builder, isLowPriority);
+ result.newExpandedView = createExpandedView(builder, isMinimized);
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
@@ -393,7 +394,7 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating public remote view");
- result.newPublicView = builder.makePublicContentView(isLowPriority);
+ result.newPublicView = builder.makePublicContentView(isMinimized);
}
if (AsyncGroupHeaderViewInflation.isEnabled()) {
@@ -406,7 +407,7 @@
if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
logger.logAsyncTaskProgress(entryForLogging,
"creating low-priority group summary remote view");
- result.mNewLowPriorityGroupHeaderView =
+ result.mNewMinimizedGroupHeaderView =
builder.makeLowPriorityContentView(true /* useRegularSubtext */);
}
}
@@ -444,6 +445,7 @@
private static CancellationSignal apply(
Executor inflationExecutor,
boolean inflateSynchronously,
+ boolean isMinimized,
InflationProgress result,
@InflationFlag int reInflateFlags,
NotifRemoteViewCache remoteViewCache,
@@ -475,7 +477,8 @@
}
};
logger.logAsyncTaskProgress(entry, "applying contracted view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags, flag,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized, result,
+ reInflateFlags, flag,
remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
privateLayout, privateLayout.getContractedChild(),
privateLayout.getVisibleWrapper(
@@ -502,7 +505,8 @@
}
};
logger.logAsyncTaskProgress(entry, "applying expanded view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized, result,
+ reInflateFlags,
flag, remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getExpandedChild(),
privateLayout.getVisibleWrapper(VISIBLE_TYPE_EXPANDED), runningInflations,
@@ -529,7 +533,8 @@
}
};
logger.logAsyncTaskProgress(entry, "applying heads up view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized,
+ result, reInflateFlags,
flag, remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getHeadsUpChild(),
privateLayout.getVisibleWrapper(VISIBLE_TYPE_HEADSUP), runningInflations,
@@ -555,7 +560,8 @@
}
};
logger.logAsyncTaskProgress(entry, "applying public view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags, flag,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized,
+ result, reInflateFlags, flag,
remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
publicLayout, publicLayout.getContractedChild(),
publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
@@ -583,11 +589,12 @@
}
};
logger.logAsyncTaskProgress(entry, "applying group header view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized,
+ result, reInflateFlags,
/* inflationId = */ FLAG_GROUP_SUMMARY_HEADER,
remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
/* parentLayout = */ childrenContainer,
- /* existingView = */ childrenContainer.getNotificationHeader(),
+ /* existingView = */ childrenContainer.getGroupHeader(),
/* existingWrapper = */ childrenContainer.getNotificationHeaderWrapper(),
runningInflations, applyCallback, logger);
}
@@ -595,7 +602,7 @@
if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
boolean isNewView =
!canReapplyRemoteView(
- /* newView = */ result.mNewLowPriorityGroupHeaderView,
+ /* newView = */ result.mNewMinimizedGroupHeaderView,
/* oldView = */ remoteViewCache.getCachedView(
entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER));
ApplyCallback applyCallback = new ApplyCallback() {
@@ -603,29 +610,30 @@
public void setResultView(View v) {
logger.logAsyncTaskProgress(entry,
"low-priority group header view applied");
- result.mInflatedLowPriorityGroupHeaderView = (NotificationHeaderView) v;
+ result.mInflatedMinimizedGroupHeaderView = (NotificationHeaderView) v;
}
@Override
public RemoteViews getRemoteView() {
- return result.mNewLowPriorityGroupHeaderView;
+ return result.mNewMinimizedGroupHeaderView;
}
};
logger.logAsyncTaskProgress(entry, "applying low priority group header view");
- applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+ applyRemoteView(inflationExecutor, inflateSynchronously, isMinimized,
+ result, reInflateFlags,
/* inflationId = */ FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
/* parentLayout = */ childrenContainer,
- /* existingView = */ childrenContainer.getNotificationHeaderLowPriority(),
+ /* existingView = */ childrenContainer.getMinimizedNotificationHeader(),
/* existingWrapper = */ childrenContainer
- .getLowPriorityViewWrapper(),
+ .getMinimizedGroupHeaderWrapper(),
runningInflations, applyCallback, logger);
}
}
// Let's try to finish, maybe nobody is even inflating anything
- finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
- row, logger);
+ finishIfDone(result, isMinimized, reInflateFlags, remoteViewCache, runningInflations,
+ callback, entry, row, logger);
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
() -> {
@@ -641,6 +649,7 @@
static void applyRemoteView(
Executor inflationExecutor,
boolean inflateSynchronously,
+ boolean isMinimized,
final InflationProgress result,
final @InflationFlag int reInflateFlags,
@InflationFlag int inflationId,
@@ -707,7 +716,8 @@
existingWrapper.onReinflated();
}
runningInflations.remove(inflationId);
- finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations,
+ finishIfDone(result, isMinimized,
+ reInflateFlags, remoteViewCache, runningInflations,
callback, entry, row, logger);
}
@@ -838,6 +848,7 @@
* @return true if the inflation was finished
*/
private static boolean finishIfDone(InflationProgress result,
+ boolean isMinimized,
@InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
HashMap<Integer, CancellationSignal> runningInflations,
@Nullable InflationCallback endListener, NotificationEntry entry,
@@ -944,7 +955,9 @@
if (AsyncGroupHeaderViewInflation.isEnabled()) {
if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) {
if (result.mInflatedGroupHeaderView != null) {
- row.setIsLowPriority(false);
+ // We need to set if the row is minimized before setting the group header to
+ // make sure the setting of header view works correctly
+ row.setIsMinimized(isMinimized);
row.setGroupHeader(/* headerView= */ result.mInflatedGroupHeaderView);
remoteViewCache.putCachedView(entry, FLAG_GROUP_SUMMARY_HEADER,
result.mNewGroupHeaderView);
@@ -957,13 +970,14 @@
}
if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
- if (result.mInflatedLowPriorityGroupHeaderView != null) {
- // New view case, set row to low priority
- row.setIsLowPriority(true);
- row.setLowPriorityGroupHeader(
- /* headerView= */ result.mInflatedLowPriorityGroupHeaderView);
+ if (result.mInflatedMinimizedGroupHeaderView != null) {
+ // We need to set if the row is minimized before setting the group header to
+ // make sure the setting of header view works correctly
+ row.setIsMinimized(isMinimized);
+ row.setMinimizedGroupHeader(
+ /* headerView= */ result.mInflatedMinimizedGroupHeaderView);
remoteViewCache.putCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
- result.mNewLowPriorityGroupHeaderView);
+ result.mNewMinimizedGroupHeaderView);
} else if (remoteViewCache.hasCachedView(entry,
FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)) {
// Re-inflation case. Only update if it's still cached (i.e. view has not
@@ -984,12 +998,12 @@
}
private static RemoteViews createExpandedView(Notification.Builder builder,
- boolean isLowPriority) {
+ boolean isMinimized) {
RemoteViews bigContentView = builder.createBigContentView();
if (bigContentView != null) {
return bigContentView;
}
- if (isLowPriority) {
+ if (isMinimized) {
RemoteViews contentView = builder.createContentView();
Notification.Builder.makeHeaderExpanded(contentView);
return contentView;
@@ -998,8 +1012,8 @@
}
private static RemoteViews createContentView(Notification.Builder builder,
- boolean isLowPriority, boolean useLarge) {
- if (isLowPriority) {
+ boolean isMinimized, boolean useLarge) {
+ if (isMinimized) {
return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
}
return builder.createContentView(useLarge);
@@ -1038,7 +1052,7 @@
private final NotificationEntry mEntry;
private final Context mContext;
private final boolean mInflateSynchronously;
- private final boolean mIsLowPriority;
+ private final boolean mIsMinimized;
private final boolean mUsesIncreasedHeight;
private final InflationCallback mCallback;
private final boolean mUsesIncreasedHeadsUpHeight;
@@ -1063,7 +1077,7 @@
NotificationEntry entry,
ConversationNotificationProcessor conversationProcessor,
ExpandableNotificationRow row,
- boolean isLowPriority,
+ boolean isMinimized,
boolean usesIncreasedHeight,
boolean usesIncreasedHeadsUpHeight,
InflationCallback callback,
@@ -1080,7 +1094,7 @@
mRemoteViewCache = cache;
mSmartRepliesInflater = smartRepliesInflater;
mContext = mRow.getContext();
- mIsLowPriority = isLowPriority;
+ mIsMinimized = isMinimized;
mUsesIncreasedHeight = usesIncreasedHeight;
mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
mRemoteViewClickHandler = remoteViewClickHandler;
@@ -1150,7 +1164,7 @@
mEntry, recoveredBuilder, mLogger);
}
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
- recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
+ recoveredBuilder, mIsMinimized, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext, mRow,
mNotifLayoutInflaterFactoryProvider, mLogger);
@@ -1209,6 +1223,7 @@
mCancellationSignal = apply(
mInflationExecutor,
mInflateSynchronously,
+ mIsMinimized,
result,
mReInflateFlags,
mRemoteViewCache,
@@ -1295,7 +1310,7 @@
private RemoteViews newExpandedView;
private RemoteViews newPublicView;
private RemoteViews mNewGroupHeaderView;
- private RemoteViews mNewLowPriorityGroupHeaderView;
+ private RemoteViews mNewMinimizedGroupHeaderView;
@VisibleForTesting
Context packageContext;
@@ -1305,7 +1320,7 @@
private View inflatedExpandedView;
private View inflatedPublicView;
private NotificationHeaderView mInflatedGroupHeaderView;
- private NotificationHeaderView mInflatedLowPriorityGroupHeaderView;
+ private NotificationHeaderView mInflatedMinimizedGroupHeaderView;
private CharSequence headsUpStatusBarText;
private CharSequence headsUpStatusBarTextPublic;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 8a3e7e8..6f00d96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1514,7 +1514,7 @@
}
ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
- LinearLayout actionListMarginTarget = layout.findViewById(
+ ViewGroup actionListMarginTarget = layout.findViewById(
com.android.internal.R.id.notification_action_list_margin_target);
if (bubbleButton == null || actionContainer == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 609b15e..3e932aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -31,7 +31,6 @@
import com.android.internal.widget.ImageResolver;
import com.android.internal.widget.LocalImageResolver;
import com.android.internal.widget.MessagingMessage;
-import com.android.systemui.Flags;
import java.util.HashSet;
import java.util.List;
@@ -67,11 +66,7 @@
* @param imageCache The implementation of internal cache.
*/
public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
- if (Flags.notificationRowUserContext()) {
- mContext = context;
- } else {
- mContext = context.getApplicationContext();
- }
+ mContext = context;
mImageCache = imageCache;
if (mImageCache != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index b0fd475..33339a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -128,9 +128,9 @@
class BindParams {
/**
- * Bind a low priority version of the content views.
+ * Bind a minimized version of the content views.
*/
- public boolean isLowPriority;
+ public boolean isMinimized;
/**
* Use increased height when binding contracted view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
index 1494c27..bae89fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java
@@ -26,7 +26,7 @@
* Parameters for {@link RowContentBindStage}.
*/
public final class RowContentBindParams {
- private boolean mUseLowPriority;
+ private boolean mUseMinimized;
private boolean mUseIncreasedHeight;
private boolean mUseIncreasedHeadsUpHeight;
private boolean mViewsNeedReinflation;
@@ -41,17 +41,20 @@
private @InflationFlag int mDirtyContentViews = mContentViews;
/**
- * Set whether content should use a low priority version of its content views.
+ * Set whether content should use a minimized version of its content views.
*/
- public void setUseLowPriority(boolean useLowPriority) {
- if (mUseLowPriority != useLowPriority) {
+ public void setUseMinimized(boolean useMinimized) {
+ if (mUseMinimized != useMinimized) {
mDirtyContentViews |= (FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED);
}
- mUseLowPriority = useLowPriority;
+ mUseMinimized = useMinimized;
}
- public boolean useLowPriority() {
- return mUseLowPriority;
+ /**
+ * @return Whether the row uses the minimized style.
+ */
+ public boolean useMinimized() {
+ return mUseMinimized;
}
/**
@@ -149,9 +152,9 @@
@Override
public String toString() {
return String.format("RowContentBindParams[mContentViews=%x mDirtyContentViews=%x "
- + "mUseLowPriority=%b mUseIncreasedHeight=%b "
+ + "mUseMinimized=%b mUseIncreasedHeight=%b "
+ "mUseIncreasedHeadsUpHeight=%b mViewsNeedReinflation=%b]",
- mContentViews, mDirtyContentViews, mUseLowPriority, mUseIncreasedHeight,
+ mContentViews, mDirtyContentViews, mUseMinimized, mUseIncreasedHeight,
mUseIncreasedHeadsUpHeight, mViewsNeedReinflation);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index f4f8374..89fcda9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -73,7 +73,7 @@
mBinder.unbindContent(entry, row, contentToUnbind);
BindParams bindParams = new BindParams();
- bindParams.isLowPriority = params.useLowPriority();
+ bindParams.isMinimized = params.useMinimized();
bindParams.usesIncreasedHeight = params.useIncreasedHeight();
bindParams.usesIncreasedHeadsUpHeight = params.useIncreasedHeadsUpHeight();
boolean forceInflate = params.needsReinflation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index ea3036e..5fbcebd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -66,9 +66,7 @@
mInflateOrigin = new Throwable("inflate requested here");
}
mListener = listener;
- AsyncLayoutInflater inflater = com.android.systemui.Flags.notificationRowUserContext()
- ? new AsyncLayoutInflater(context, makeRowInflater(entry))
- : new AsyncLayoutInflater(context);
+ AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, makeRowInflater(entry));
mEntry = entry;
entry.setInflationTask(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/ConversationStyleSetAvatarAsync.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/ConversationStyleSetAvatarAsync.kt
new file mode 100644
index 0000000..3c056c9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/ConversationStyleSetAvatarAsync.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.notification.row.shared
+
+import android.widget.flags.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the conversation style set avatar async flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object ConversationStyleSetAvatarAsync {
+ const val FLAG_NAME = Flags.FLAG_CONVERSATION_STYLE_SET_AVATAR_ASYNC
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is async hybrid (single-line) view inflation enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.conversationStyleSetAvatarAsync()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/HeadsUpRowKey.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/HeadsUpRowKey.kt
new file mode 100644
index 0000000..8dc395d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/HeadsUpRowKey.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.notification.shared
+
+/**
+ * A unique key representing a top-level heads up notification.
+ *
+ * @see com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
+ */
+interface HeadsUpRowKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.kt
new file mode 100644
index 0000000..62641fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsHeadsUpRefactor.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.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the notifications heads up refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationsHeadsUpRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationsHeadsUpRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 28f874d..5dc37e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -110,14 +110,14 @@
*/
private boolean mEnableShadowOnChildNotifications;
- private NotificationHeaderView mNotificationHeader;
- private NotificationHeaderViewWrapper mNotificationHeaderWrapper;
- private NotificationHeaderView mNotificationHeaderLowPriority;
- private NotificationHeaderViewWrapper mNotificationHeaderWrapperLowPriority;
+ private NotificationHeaderView mGroupHeader;
+ private NotificationHeaderViewWrapper mGroupHeaderWrapper;
+ private NotificationHeaderView mMinimizedGroupHeader;
+ private NotificationHeaderViewWrapper mMinimizedGroupHeaderWrapper;
private NotificationGroupingUtil mGroupingUtil;
private ViewState mHeaderViewState;
private int mClipBottomAmount;
- private boolean mIsLowPriority;
+ private boolean mIsMinimized;
private OnClickListener mHeaderClickListener;
private ViewGroup mCurrentHeader;
private boolean mIsConversation;
@@ -217,14 +217,14 @@
int right = left + mOverflowNumber.getMeasuredWidth();
mOverflowNumber.layout(left, 0, right, mOverflowNumber.getMeasuredHeight());
}
- if (mNotificationHeader != null) {
- mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
- mNotificationHeader.getMeasuredHeight());
+ if (mGroupHeader != null) {
+ mGroupHeader.layout(0, 0, mGroupHeader.getMeasuredWidth(),
+ mGroupHeader.getMeasuredHeight());
}
- if (mNotificationHeaderLowPriority != null) {
- mNotificationHeaderLowPriority.layout(0, 0,
- mNotificationHeaderLowPriority.getMeasuredWidth(),
- mNotificationHeaderLowPriority.getMeasuredHeight());
+ if (mMinimizedGroupHeader != null) {
+ mMinimizedGroupHeader.layout(0, 0,
+ mMinimizedGroupHeader.getMeasuredWidth(),
+ mMinimizedGroupHeader.getMeasuredHeight());
}
}
@@ -271,11 +271,11 @@
}
int headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
- if (mNotificationHeader != null) {
- mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
+ if (mGroupHeader != null) {
+ mGroupHeader.measure(widthMeasureSpec, headerHeightSpec);
}
- if (mNotificationHeaderLowPriority != null) {
- mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
+ if (mMinimizedGroupHeader != null) {
+ mMinimizedGroupHeader.measure(widthMeasureSpec, headerHeightSpec);
}
setMeasuredDimension(width, height);
@@ -308,11 +308,11 @@
* appropriately.
*/
public void setNotificationGroupWhen(long whenMillis) {
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.setNotificationWhen(whenMillis);
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setNotificationWhen(whenMillis);
}
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.setNotificationWhen(whenMillis);
+ if (mMinimizedGroupHeaderWrapper != null) {
+ mMinimizedGroupHeaderWrapper.setNotificationWhen(whenMillis);
}
}
@@ -410,28 +410,28 @@
Trace.beginSection("recreateHeader#makeNotificationGroupHeader");
RemoteViews header = builder.makeNotificationGroupHeader();
Trace.endSection();
- if (mNotificationHeader == null) {
+ if (mGroupHeader == null) {
Trace.beginSection("recreateHeader#apply");
- mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
+ mGroupHeader = (NotificationHeaderView) header.apply(getContext(), this);
Trace.endSection();
- mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
+ mGroupHeader.findViewById(com.android.internal.R.id.expand_button)
.setVisibility(VISIBLE);
- mNotificationHeader.setOnClickListener(mHeaderClickListener);
- mNotificationHeaderWrapper =
+ mGroupHeader.setOnClickListener(mHeaderClickListener);
+ mGroupHeaderWrapper =
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
getContext(),
- mNotificationHeader,
+ mGroupHeader,
mContainingNotification);
- mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
- addView(mNotificationHeader, 0);
+ mGroupHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
+ addView(mGroupHeader, 0);
invalidate();
} else {
Trace.beginSection("recreateHeader#reapply");
- header.reapply(getContext(), mNotificationHeader);
+ header.reapply(getContext(), mGroupHeader);
Trace.endSection();
}
- mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
- mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
+ mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
+ mGroupHeaderWrapper.onContentUpdated(mContainingNotification);
recreateLowPriorityHeader(builder, isConversation);
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
@@ -439,21 +439,21 @@
}
private void removeGroupHeader() {
- if (mNotificationHeader == null) {
+ if (mGroupHeader == null) {
return;
}
- removeView(mNotificationHeader);
- mNotificationHeader = null;
- mNotificationHeaderWrapper = null;
+ removeView(mGroupHeader);
+ mGroupHeader = null;
+ mGroupHeaderWrapper = null;
}
private void removeLowPriorityGroupHeader() {
- if (mNotificationHeaderLowPriority == null) {
+ if (mMinimizedGroupHeader == null) {
return;
}
- removeView(mNotificationHeaderLowPriority);
- mNotificationHeaderLowPriority = null;
- mNotificationHeaderWrapperLowPriority = null;
+ removeView(mMinimizedGroupHeader);
+ mMinimizedGroupHeader = null;
+ mMinimizedGroupHeaderWrapper = null;
}
/**
@@ -474,21 +474,21 @@
return;
}
- mNotificationHeader = headerView;
- mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
+ mGroupHeader = headerView;
+ mGroupHeader.findViewById(com.android.internal.R.id.expand_button)
.setVisibility(VISIBLE);
- mNotificationHeader.setOnClickListener(mHeaderClickListener);
- mNotificationHeaderWrapper =
+ mGroupHeader.setOnClickListener(mHeaderClickListener);
+ mGroupHeaderWrapper =
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
getContext(),
- mNotificationHeader,
+ mGroupHeader,
mContainingNotification);
- mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
- addView(mNotificationHeader, 0);
+ mGroupHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
+ addView(mGroupHeader, 0);
invalidate();
- mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
- mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
+ mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
+ mGroupHeaderWrapper.onContentUpdated(mContainingNotification);
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
@@ -511,20 +511,20 @@
return;
}
- mNotificationHeaderLowPriority = headerViewLowPriority;
- mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button)
+ mMinimizedGroupHeader = headerViewLowPriority;
+ mMinimizedGroupHeader.findViewById(com.android.internal.R.id.expand_button)
.setVisibility(VISIBLE);
- mNotificationHeaderLowPriority.setOnClickListener(onClickListener);
- mNotificationHeaderWrapperLowPriority =
+ mMinimizedGroupHeader.setOnClickListener(onClickListener);
+ mMinimizedGroupHeaderWrapper =
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
getContext(),
- mNotificationHeaderLowPriority,
+ mMinimizedGroupHeader,
mContainingNotification);
- mNotificationHeaderWrapperLowPriority.setOnRoundnessChangedListener(this::invalidate);
- addView(mNotificationHeaderLowPriority, 0);
+ mMinimizedGroupHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
+ addView(mMinimizedGroupHeader, 0);
invalidate();
- mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification);
+ mMinimizedGroupHeaderWrapper.onContentUpdated(mContainingNotification);
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
}
@@ -539,35 +539,35 @@
AsyncGroupHeaderViewInflation.assertInLegacyMode();
RemoteViews header;
StatusBarNotification notification = mContainingNotification.getEntry().getSbn();
- if (mIsLowPriority) {
+ if (mIsMinimized) {
if (builder == null) {
builder = Notification.Builder.recoverBuilder(getContext(),
notification.getNotification());
}
header = builder.makeLowPriorityContentView(true /* useRegularSubtext */);
- if (mNotificationHeaderLowPriority == null) {
- mNotificationHeaderLowPriority = (NotificationHeaderView) header.apply(getContext(),
+ if (mMinimizedGroupHeader == null) {
+ mMinimizedGroupHeader = (NotificationHeaderView) header.apply(getContext(),
this);
- mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button)
+ mMinimizedGroupHeader.findViewById(com.android.internal.R.id.expand_button)
.setVisibility(VISIBLE);
- mNotificationHeaderLowPriority.setOnClickListener(mHeaderClickListener);
- mNotificationHeaderWrapperLowPriority =
+ mMinimizedGroupHeader.setOnClickListener(mHeaderClickListener);
+ mMinimizedGroupHeaderWrapper =
(NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
getContext(),
- mNotificationHeaderLowPriority,
+ mMinimizedGroupHeader,
mContainingNotification);
- mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
- addView(mNotificationHeaderLowPriority, 0);
+ mGroupHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
+ addView(mMinimizedGroupHeader, 0);
invalidate();
} else {
- header.reapply(getContext(), mNotificationHeaderLowPriority);
+ header.reapply(getContext(), mMinimizedGroupHeader);
}
- mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification);
- resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader());
+ mMinimizedGroupHeaderWrapper.onContentUpdated(mContainingNotification);
+ resetHeaderVisibilityIfNeeded(mMinimizedGroupHeader, calculateDesiredHeader());
} else {
- removeView(mNotificationHeaderLowPriority);
- mNotificationHeaderLowPriority = null;
- mNotificationHeaderWrapperLowPriority = null;
+ removeView(mMinimizedGroupHeader);
+ mMinimizedGroupHeader = null;
+ mMinimizedGroupHeaderWrapper = null;
}
}
@@ -588,8 +588,8 @@
public void updateGroupOverflow() {
if (mShowGroupCountInExpander) {
- setExpandButtonNumber(mNotificationHeaderWrapper);
- setExpandButtonNumber(mNotificationHeaderWrapperLowPriority);
+ setExpandButtonNumber(mGroupHeaderWrapper);
+ setExpandButtonNumber(mMinimizedGroupHeaderWrapper);
return;
}
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
@@ -641,9 +641,9 @@
* @param alpha alpha value to apply to the content
*/
public void setContentAlpha(float alpha) {
- if (mNotificationHeader != null) {
- for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
- mNotificationHeader.getChildAt(i).setAlpha(alpha);
+ if (mGroupHeader != null) {
+ for (int i = 0; i < mGroupHeader.getChildCount(); i++) {
+ mGroupHeader.getChildAt(i).setAlpha(alpha);
}
}
for (ExpandableNotificationRow child : getAttachedChildren()) {
@@ -683,7 +683,7 @@
if (AsyncGroupHeaderViewInflation.isEnabled()) {
return mHeaderHeight;
} else {
- return mNotificationHeaderLowPriority.getHeight();
+ return mMinimizedGroupHeader.getHeight();
}
}
int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation;
@@ -837,15 +837,15 @@
mGroupOverFlowState.setAlpha(0.0f);
}
}
- if (mNotificationHeader != null) {
+ if (mGroupHeader != null) {
if (mHeaderViewState == null) {
mHeaderViewState = new ViewState();
}
- mHeaderViewState.initFrom(mNotificationHeader);
+ mHeaderViewState.initFrom(mGroupHeader);
if (mContainingNotification.hasExpandingChild()) {
// Not modifying translationZ during expand animation.
- mHeaderViewState.setZTranslation(mNotificationHeader.getTranslationZ());
+ mHeaderViewState.setZTranslation(mGroupHeader.getTranslationZ());
} else if (childrenExpandedAndNotAnimating) {
mHeaderViewState.setZTranslation(parentState.getZTranslation());
} else {
@@ -898,7 +898,7 @@
&& !showingAsLowPriority()) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
- if (mIsLowPriority
+ if (mIsMinimized
|| (!mContainingNotification.isOnKeyguard() && mContainingNotification.isExpanded())
|| (mContainingNotification.isHeadsUpState()
&& mContainingNotification.canShowHeadsUp())) {
@@ -946,7 +946,7 @@
mNeverAppliedGroupState = false;
}
if (mHeaderViewState != null) {
- mHeaderViewState.applyToView(mNotificationHeader);
+ mHeaderViewState.applyToView(mGroupHeader);
}
updateChildrenClipping();
}
@@ -1006,8 +1006,8 @@
}
if (child instanceof NotificationHeaderView
- && mNotificationHeaderWrapper.hasRoundedCorner()) {
- float[] radii = mNotificationHeaderWrapper.getUpdatedRadii();
+ && mGroupHeaderWrapper.hasRoundedCorner()) {
+ float[] radii = mGroupHeaderWrapper.getUpdatedRadii();
mHeaderPath.reset();
mHeaderPath.addRoundRect(
child.getLeft(),
@@ -1085,8 +1085,8 @@
}
mGroupOverFlowState.animateTo(mOverflowNumber, properties);
}
- if (mNotificationHeader != null) {
- mHeaderViewState.applyToView(mNotificationHeader);
+ if (mGroupHeader != null) {
+ mHeaderViewState.applyToView(mGroupHeader);
}
updateChildrenClipping();
}
@@ -1109,8 +1109,8 @@
public void setChildrenExpanded(boolean childrenExpanded) {
mChildrenExpanded = childrenExpanded;
updateExpansionStates();
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.setExpanded(childrenExpanded);
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setExpanded(childrenExpanded);
}
final int count = mAttachedChildren.size();
for (int childIdx = 0; childIdx < count; childIdx++) {
@@ -1130,11 +1130,11 @@
}
public NotificationViewWrapper getNotificationViewWrapper() {
- return mNotificationHeaderWrapper;
+ return mGroupHeaderWrapper;
}
- public NotificationViewWrapper getLowPriorityViewWrapper() {
- return mNotificationHeaderWrapperLowPriority;
+ public NotificationViewWrapper getMinimizedGroupHeaderWrapper() {
+ return mMinimizedGroupHeaderWrapper;
}
@VisibleForTesting
@@ -1142,12 +1142,12 @@
return mCurrentHeader;
}
- public NotificationHeaderView getNotificationHeader() {
- return mNotificationHeader;
+ public NotificationHeaderView getGroupHeader() {
+ return mGroupHeader;
}
- public NotificationHeaderView getNotificationHeaderLowPriority() {
- return mNotificationHeaderLowPriority;
+ public NotificationHeaderView getMinimizedNotificationHeader() {
+ return mMinimizedGroupHeader;
}
private void updateHeaderVisibility(boolean animate) {
@@ -1171,7 +1171,7 @@
NotificationViewWrapper hiddenWrapper = getWrapperForView(currentHeader);
visibleWrapper.transformFrom(hiddenWrapper);
hiddenWrapper.transformTo(visibleWrapper, () -> updateHeaderVisibility(false));
- startChildAlphaAnimations(desiredHeader == mNotificationHeader);
+ startChildAlphaAnimations(desiredHeader == mGroupHeader);
} else {
animate = false;
}
@@ -1192,8 +1192,8 @@
}
}
- resetHeaderVisibilityIfNeeded(mNotificationHeader, desiredHeader);
- resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, desiredHeader);
+ resetHeaderVisibilityIfNeeded(mGroupHeader, desiredHeader);
+ resetHeaderVisibilityIfNeeded(mMinimizedGroupHeader, desiredHeader);
mCurrentHeader = desiredHeader;
}
@@ -1215,9 +1215,9 @@
private ViewGroup calculateDesiredHeader() {
ViewGroup desiredHeader;
if (showingAsLowPriority()) {
- desiredHeader = mNotificationHeaderLowPriority;
+ desiredHeader = mMinimizedGroupHeader;
} else {
- desiredHeader = mNotificationHeader;
+ desiredHeader = mGroupHeader;
}
return desiredHeader;
}
@@ -1244,20 +1244,20 @@
private void updateHeaderTransformation() {
if (mUserLocked && showingAsLowPriority()) {
float fraction = getGroupExpandFraction();
- mNotificationHeaderWrapper.transformFrom(mNotificationHeaderWrapperLowPriority,
+ mGroupHeaderWrapper.transformFrom(mMinimizedGroupHeaderWrapper,
fraction);
- mNotificationHeader.setVisibility(VISIBLE);
- mNotificationHeaderWrapperLowPriority.transformTo(mNotificationHeaderWrapper,
+ mGroupHeader.setVisibility(VISIBLE);
+ mMinimizedGroupHeaderWrapper.transformTo(mGroupHeaderWrapper,
fraction);
}
}
private NotificationViewWrapper getWrapperForView(View visibleHeader) {
- if (visibleHeader == mNotificationHeader) {
- return mNotificationHeaderWrapper;
+ if (visibleHeader == mGroupHeader) {
+ return mGroupHeaderWrapper;
}
- return mNotificationHeaderWrapperLowPriority;
+ return mMinimizedGroupHeaderWrapper;
}
/**
@@ -1266,13 +1266,13 @@
* @param expanded whether the group is expanded.
*/
public void updateHeaderForExpansion(boolean expanded) {
- if (mNotificationHeader != null) {
+ if (mGroupHeader != null) {
if (expanded) {
ColorDrawable cd = new ColorDrawable();
cd.setColor(mContainingNotification.calculateBgColor());
- mNotificationHeader.setHeaderBackgroundDrawable(cd);
+ mGroupHeader.setHeaderBackgroundDrawable(cd);
} else {
- mNotificationHeader.setHeaderBackgroundDrawable(null);
+ mGroupHeader.setHeaderBackgroundDrawable(null);
}
}
}
@@ -1405,11 +1405,11 @@
if (AsyncGroupHeaderViewInflation.isEnabled()) {
return mHeaderHeight;
}
- if (mNotificationHeaderLowPriority == null) {
+ if (mMinimizedGroupHeader == null) {
Log.e(TAG, "getMinHeight: low priority header is null", new Exception());
return 0;
}
- return mNotificationHeaderLowPriority.getHeight();
+ return mMinimizedGroupHeader.getHeight();
}
int minExpandHeight = mNotificationHeaderMargin + headerTranslation;
int visibleChildren = 0;
@@ -1443,20 +1443,20 @@
}
public boolean showingAsLowPriority() {
- return mIsLowPriority && !mContainingNotification.isExpanded();
+ return mIsMinimized && !mContainingNotification.isExpanded();
}
public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
if (!AsyncGroupHeaderViewInflation.isEnabled()) {
// When Async header inflation is enabled, we do not reinflate headers because they are
// inflated from the background thread
- if (mNotificationHeader != null) {
- removeView(mNotificationHeader);
- mNotificationHeader = null;
+ if (mGroupHeader != null) {
+ removeView(mGroupHeader);
+ mGroupHeader = null;
}
- if (mNotificationHeaderLowPriority != null) {
- removeView(mNotificationHeaderLowPriority);
- mNotificationHeaderLowPriority = null;
+ if (mMinimizedGroupHeader != null) {
+ removeView(mMinimizedGroupHeader);
+ mMinimizedGroupHeader = null;
}
recreateNotificationHeader(listener, mIsConversation);
}
@@ -1489,8 +1489,8 @@
}
private void updateHeaderTouchability() {
- if (mNotificationHeader != null) {
- mNotificationHeader.setAcceptAllTouches(mChildrenExpanded || mUserLocked);
+ if (mGroupHeader != null) {
+ mGroupHeader.setAcceptAllTouches(mChildrenExpanded || mUserLocked);
}
}
@@ -1534,8 +1534,11 @@
updateChildrenClipping();
}
- public void setIsLowPriority(boolean isLowPriority) {
- mIsLowPriority = isLowPriority;
+ /**
+ * Set whether the children container is minimized.
+ */
+ public void setIsMinimized(boolean isMinimized) {
+ mIsMinimized = isMinimized;
if (mContainingNotification != null) { /* we're not yet set up yet otherwise */
if (!AsyncGroupHeaderViewInflation.isEnabled()) {
recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation);
@@ -1552,13 +1555,13 @@
*/
public NotificationViewWrapper getVisibleWrapper() {
if (showingAsLowPriority()) {
- return mNotificationHeaderWrapperLowPriority;
+ return mMinimizedGroupHeaderWrapper;
}
- return mNotificationHeaderWrapper;
+ return mGroupHeaderWrapper;
}
public void onExpansionChanged() {
- if (mIsLowPriority) {
+ if (mIsMinimized) {
if (mUserLocked) {
setUserLocked(mUserLocked);
}
@@ -1574,15 +1577,15 @@
@Override
public void applyRoundnessAndInvalidate() {
boolean last = true;
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.requestTopRoundness(
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.requestTopRoundness(
/* value = */ getTopRoundness(),
/* sourceType = */ FROM_PARENT,
/* animate = */ false
);
}
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.requestTopRoundness(
+ if (mMinimizedGroupHeaderWrapper != null) {
+ mMinimizedGroupHeaderWrapper.requestTopRoundness(
/* value = */ getTopRoundness(),
/* sourceType = */ FROM_PARENT,
/* animate = */ false
@@ -1612,31 +1615,31 @@
* Shows the given feedback icon, or hides the icon if null.
*/
public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.setFeedbackIcon(icon);
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setFeedbackIcon(icon);
}
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.setFeedbackIcon(icon);
+ if (mMinimizedGroupHeaderWrapper != null) {
+ mMinimizedGroupHeaderWrapper.setFeedbackIcon(icon);
}
}
public void setRecentlyAudiblyAlerted(boolean audiblyAlertedRecently) {
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
}
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+ if (mMinimizedGroupHeaderWrapper != null) {
+ mMinimizedGroupHeaderWrapper.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
}
}
@Override
public void setNotificationFaded(boolean faded) {
mContainingNotificationIsFaded = faded;
- if (mNotificationHeaderWrapper != null) {
- mNotificationHeaderWrapper.setNotificationFaded(faded);
+ if (mGroupHeaderWrapper != null) {
+ mGroupHeaderWrapper.setNotificationFaded(faded);
}
- if (mNotificationHeaderWrapperLowPriority != null) {
- mNotificationHeaderWrapperLowPriority.setNotificationFaded(faded);
+ if (mMinimizedGroupHeaderWrapper != null) {
+ mMinimizedGroupHeaderWrapper.setNotificationFaded(faded);
}
for (ExpandableNotificationRow child : mAttachedChildren) {
child.setNotificationFaded(faded);
@@ -1654,7 +1657,7 @@
}
public NotificationHeaderViewWrapper getNotificationHeaderWrapper() {
- return mNotificationHeaderWrapper;
+ return mGroupHeaderWrapper;
}
public void setLogger(NotificationChildrenContainerLogger logger) {
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 9479762..fb52838 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
@@ -812,6 +812,10 @@
} else {
mDebugTextUsedYPositions.clear();
}
+
+ mDebugPaint.setColor(Color.DKGRAY);
+ canvas.drawPath(mRoundedClipPath, mDebugPaint);
+
int y = 0;
drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
@@ -843,14 +847,14 @@
drawDebugInfo(canvas, y, Color.LTGRAY,
/* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
- y = (int) mAmbientState.getStackY() + mContentHeight;
- drawDebugInfo(canvas, y, Color.MAGENTA,
- /* label= */ "mAmbientState.getStackY() + mContentHeight = " + y);
-
y = (int) (mAmbientState.getStackY() + mIntrinsicContentHeight);
drawDebugInfo(canvas, y, Color.YELLOW,
/* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
+ y = mContentHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA,
+ /* label= */ "mContentHeight = " + y);
+
drawDebugInfo(canvas, mRoundedRectClippingBottom, Color.DKGRAY,
/* label= */ "mRoundedRectClippingBottom) = " + y);
}
@@ -4940,6 +4944,9 @@
println(pw, "intrinsicPadding", mIntrinsicPadding);
println(pw, "topPadding", mTopPadding);
println(pw, "bottomPadding", mBottomPadding);
+ dumpRoundedRectClipping(pw);
+ println(pw, "requestedClipBounds", mRequestedClipBounds);
+ println(pw, "isClipped", mIsClipped);
println(pw, "translationX", getTranslationX());
println(pw, "translationY", getTranslationY());
println(pw, "translationZ", getTranslationZ());
@@ -4994,6 +5001,15 @@
});
}
+ private void dumpRoundedRectClipping(IndentingPrintWriter pw) {
+ pw.append("roundedRectClipping{l=").print(mRoundedRectClippingLeft);
+ pw.append(" t=").print(mRoundedRectClippingTop);
+ pw.append(" r=").print(mRoundedRectClippingRight);
+ pw.append(" b=").print(mRoundedRectClippingBottom);
+ pw.append("} topRadius=").print(mBgCornerRadii[0]);
+ pw.append(" bottomRadius=").println(mBgCornerRadii[4]);
+ }
+
private void dumpFooterViewVisibility(IndentingPrintWriter pw) {
FooterViewRefactor.assertInLegacyMode();
final boolean showDismissView = shouldShowDismissView();
@@ -5389,7 +5405,7 @@
/**
* @param topHeadsUpRow the first headsUp row in z-order.
*/
- public void setTopHeadsUpRow(ExpandableNotificationRow topHeadsUpRow) {
+ public void setTopHeadsUpRow(@Nullable ExpandableNotificationRow topHeadsUpRow) {
mTopHeadsUpRow = topHeadsUpRow;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 8ed1ca2..ec111a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -23,7 +23,6 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
import static com.android.server.notification.Flags.screenshareNotificationHiding;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.Flags.nsslFalsingFix;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
@@ -71,6 +70,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -126,6 +126,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
@@ -685,11 +686,13 @@
new OnHeadsUpChangedListener() {
@Override
public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
mView.setInHeadsUpPinnedMode(inPinnedMode);
}
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
mView.setTopHeadsUpRow(topEntry != null ? topEntry.getRow() : null);
generateHeadsUpAnimation(entry, isHeadsUp);
@@ -870,7 +873,9 @@
});
}
- mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
+ if (!NotificationsHeadsUpRefactor.isEnabled()) {
+ mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
+ }
mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
@@ -2090,7 +2095,7 @@
}
boolean horizontalSwipeWantsIt = false;
boolean scrollerWantsIt = false;
- if (nsslFalsingFix() || migrateClocksToBlueprint()) {
+ if (nsslFalsingFix() || MigrateClocksToBlueprint.isEnabled()) {
// Reverse the order relative to the else statement. onScrollTouch will reset on an
// UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
if (mLongPressedView == null && !mView.isBeingDragged()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 2d9c63e..1b53cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -20,6 +20,7 @@
import android.util.Log
import android.view.View.GONE
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags.notificationMinimalismPrototype
import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -66,6 +67,11 @@
*/
private var maxKeyguardNotifications by notNull<Int>()
+ /**
+ * Whether [maxKeyguardNotifications] will have 1 added to it when media is shown in the stack.
+ */
+ private var maxNotificationsExcludesMedia = false
+
/** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
private var dividerHeight by notNull<Float>()
@@ -168,7 +174,11 @@
log { "\n" }
val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfHeight)
+
+ // TODO: Avoid making this split shade assumption by simply checking the stack for media
val isMediaShowing = mediaDataManager.hasActiveMediaOrRecommendation()
+ val isMediaShowingInStack = isMediaShowing && !splitShadeStateController
+ .shouldUseSplitNotificationShade(resources)
log { "\tGet maxNotifWithoutSavingSpace ---" }
val maxNotifWithoutSavingSpace =
@@ -181,12 +191,11 @@
}
// How many notifications we can show at heightWithoutLockscreenConstraints
- var minCountAtHeightWithoutConstraints =
- if (isMediaShowing && !splitShadeStateController
- .shouldUseSplitNotificationShade(resources)) 2 else 1
+ val minCountAtHeightWithoutConstraints = if (isMediaShowingInStack) 2 else 1
log {
"\t---maxNotifWithoutSavingSpace=$maxNotifWithoutSavingSpace " +
"isMediaShowing=$isMediaShowing" +
+ "isMediaShowingInStack=$isMediaShowingInStack" +
"minCountAtHeightWithoutConstraints=$minCountAtHeightWithoutConstraints"
}
log { "\n" }
@@ -223,7 +232,9 @@
}
if (onLockscreen()) {
- maxNotifications = min(maxKeyguardNotifications, maxNotifications)
+ val increaseMaxForMedia = maxNotificationsExcludesMedia && isMediaShowingInStack
+ val lockscreenMax = maxKeyguardNotifications.safeIncrementIf(increaseMaxForMedia)
+ maxNotifications = min(lockscreenMax, maxNotifications)
}
// Could be < 0 if the space available is less than the shelf size. Returns 0 in this case.
@@ -276,7 +287,7 @@
height = notifsHeight + shelfHeightWithSpaceBefore
log {
"--- computeHeight(maxNotifs=$maxNotifs, shelfHeight=$shelfHeight)" +
- " -> ${height}=($notifsHeight+$shelfHeightWithSpaceBefore)" +
+ " -> $height=($notifsHeight+$shelfHeightWithSpaceBefore)" +
" | saveSpaceOnLockscreen=$saveSpaceOnLockscreen"
}
}
@@ -367,8 +378,9 @@
}
fun updateResources() {
- maxKeyguardNotifications =
- infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+ maxKeyguardNotifications = if (notificationMinimalismPrototype()) 1
+ else infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+ maxNotificationsExcludesMedia = notificationMinimalismPrototype()
dividerHeight =
max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
@@ -486,6 +498,13 @@
v
}
+ private fun Int.safeIncrementIf(condition: Boolean): Int =
+ if (condition && this != Int.MAX_VALUE) {
+ this + 1
+ } else {
+ this
+ }
+
/** Returns the last index where [predicate] returns true, or -1 if it was always false. */
private fun <T> Sequence<T>.lastIndexWhile(predicate: (T) -> Boolean): Int =
takeWhile(predicate).count() - 1
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 9b1952b..5eaccd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -53,9 +53,7 @@
public static final float START_FRACTION = 0.5f;
private static final String TAG = "StackScrollAlgorithm";
- private static final Boolean DEBUG = false;
private static final SourceType STACK_SCROLL_ALGO = SourceType.from("StackScrollAlgorithm");
-
private final ViewGroup mHostView;
private float mPaddingBetweenElements;
private float mGapHeight;
@@ -247,13 +245,11 @@
>= ambientState.getMaxHeadsUpTranslation();
}
- public static void log(String s) {
- if (DEBUG) {
- android.util.Log.i(TAG, s);
- }
+ public static void debugLog(String s) {
+ android.util.Log.i(TAG, s);
}
- public static void logView(View view, String s) {
+ public static void debugLogView(View view, String s) {
String viewString = "";
if (view instanceof ExpandableNotificationRow row) {
if (row.getEntry() == null) {
@@ -274,7 +270,7 @@
} else {
viewString = view.toString();
}
- log(viewString + " " + s);
+ debugLog(viewString + " " + s);
}
private void resetChildViewStates() {
@@ -598,15 +594,16 @@
);
if (view instanceof FooterView) {
if (FooterViewRefactor.isEnabled()) {
- final float footerEnd = algorithmState.mCurrentExpandedYPosition
- + view.getIntrinsicHeight();
- final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
- // TODO(b/293167744): May be able to keep only noSpaceForFooter here if we add an
- // emission when clearAllNotifications is called, and then use that in the footer
- // visibility flow.
- ((FooterView.FooterViewState) viewState).hideContent =
- noSpaceForFooter || (ambientState.isClearAllInProgress()
- && !hasNonClearableNotifs(algorithmState));
+ if (((FooterView) view).shouldBeHidden()) {
+ viewState.hidden = true;
+ } else {
+ final float footerEnd = algorithmState.mCurrentExpandedYPosition
+ + view.getIntrinsicHeight();
+ final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
+ ((FooterView.FooterViewState) viewState).hideContent =
+ noSpaceForFooter || (ambientState.isClearAllInProgress()
+ && !hasNonClearableNotifs(algorithmState));
+ }
} else {
final boolean shadeClosed = !ambientState.isShadeExpanded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt
index 9efe632..79ba25e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.stack.data.repository
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
@@ -26,7 +26,7 @@
@SysUISingleton
class NotificationStackAppearanceRepository @Inject constructor() {
/** The bounds of the notification stack in the current scene. */
- val stackBounds = MutableStateFlow(NotificationContainerBounds())
+ val stackBounds = MutableStateFlow(StackBounds())
/**
* The height in px of the contents of notification stack. Depending on the number of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index 08df473..f05d017 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -17,13 +17,19 @@
package com.android.systemui.statusbar.notification.stack.domain.interactor
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.data.repository.NotificationStackAppearanceRepository
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.StackRounding
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
/** An interactor which controls the appearance of the NSSL */
@SysUISingleton
@@ -31,9 +37,30 @@
@Inject
constructor(
private val repository: NotificationStackAppearanceRepository,
+ shadeInteractor: ShadeInteractor,
) {
/** The bounds of the notification stack in the current scene. */
- val stackBounds: StateFlow<NotificationContainerBounds> = repository.stackBounds.asStateFlow()
+ val stackBounds: StateFlow<StackBounds> = repository.stackBounds.asStateFlow()
+
+ /**
+ * Whether the stack is expanding from GONE-with-HUN to SHADE
+ *
+ * TODO(b/296118689): implement this to match legacy QSController logic
+ */
+ private val isExpandingFromHeadsUp: Flow<Boolean> = flowOf(false)
+
+ /** The rounding of the notification stack. */
+ val stackRounding: Flow<StackRounding> =
+ combine(
+ shadeInteractor.shadeMode,
+ isExpandingFromHeadsUp,
+ ) { shadeMode, isExpandingFromHeadsUp ->
+ StackRounding(
+ roundTop = !(shadeMode == ShadeMode.Split && isExpandingFromHeadsUp),
+ roundBottom = shadeMode != ShadeMode.Single,
+ )
+ }
+ .distinctUntilChanged()
/**
* The height in px of the contents of notification stack. Depending on the number of
@@ -59,7 +86,7 @@
val syntheticScroll: Flow<Float> = repository.syntheticScroll.asStateFlow()
/** Sets the position of the notification stack in the current scene. */
- fun setStackBounds(bounds: NotificationContainerBounds) {
+ fun setStackBounds(bounds: StackBounds) {
check(bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" }
repository.stackBounds.value = bounds
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackBounds.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackBounds.kt
new file mode 100644
index 0000000..1fc9a18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackBounds.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.notification.stack.shared.model
+
+/** Models the bounds of the notification stack. */
+data class StackBounds(
+ /** The position of the left of the stack in its window coordinate system, in pixels. */
+ val left: Float = 0f,
+ /** The position of the top of the stack in its window coordinate system, in pixels. */
+ val top: Float = 0f,
+ /** The position of the right of the stack in its window coordinate system, in pixels. */
+ val right: Float = 0f,
+ /** The position of the bottom of the stack in its window coordinate system, in pixels. */
+ val bottom: Float = 0f,
+) {
+ /** The current height of the notification container. */
+ val height: Float = bottom - top
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackClipping.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackClipping.kt
new file mode 100644
index 0000000..0c92b50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackClipping.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.notification.stack.shared.model
+
+/** Models the clipping rounded rectangle of the notification stack */
+data class StackClipping(val bounds: StackBounds, val rounding: StackRounding)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackRounding.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackRounding.kt
new file mode 100644
index 0000000..ddc5d7ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/StackRounding.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.notification.stack.shared.model
+
+/** Models the corner rounds of the notification stack. */
+data class StackRounding(
+ /** Whether the top corners of the notification stack should be rounded. */
+ val roundTop: Boolean = false,
+ /** Whether the bottom corners of the notification stack should be rounded. */
+ val roundBottom: Boolean = false,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 6b30393..18bb5119 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerShelfViewBinder
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinder
import com.android.systemui.statusbar.notification.stack.DisplaySwitchNotificationsHiderTracker
@@ -44,6 +45,7 @@
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationStatsLogger
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.HideNotificationsBinder.bindHideList
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel
+import com.android.systemui.statusbar.notification.ui.viewbinder.HeadsUpNotificationViewBinder
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.util.kotlin.awaitCancellationThenDispose
import com.android.systemui.util.kotlin.getOrNull
@@ -71,6 +73,7 @@
private val hiderTracker: DisplaySwitchNotificationsHiderTracker,
private val configuration: ConfigurationState,
private val falsingManager: FalsingManager,
+ private val hunBinder: HeadsUpNotificationViewBinder,
private val iconAreaController: NotificationIconAreaController,
private val loggerOptional: Optional<NotificationStatsLogger>,
private val metricsLogger: MetricsLogger,
@@ -92,6 +95,9 @@
view.repeatWhenAttached {
lifecycleScope.launch {
+ if (NotificationsHeadsUpRefactor.isEnabled) {
+ launch { hunBinder.bindHeadsUpNotifications(view) }
+ }
launch { bindShelf(shelf) }
bindHideList(viewController, viewModel, hiderTracker)
@@ -187,13 +193,14 @@
},
)
launch {
- viewModel.shouldShowFooterView.collect { animatedVisibility ->
+ viewModel.shouldIncludeFooterView.collect { animatedVisibility ->
footerView.setVisible(
/* visible = */ animatedVisibility.value,
/* animate = */ animatedVisibility.isAnimating,
)
}
}
+ launch { viewModel.shouldHideFooterView.collect { footerView.setShouldBeHidden(it) } }
disposableHandle.awaitCancellationThenDispose()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
deleted file mode 100644
index f10e5f1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
+++ /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 com.android.systemui.statusbar.notification.stack.ui.viewbinder
-
-import android.content.Context
-import android.util.TypedValue
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
-import kotlin.math.roundToInt
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
-
-/** Binds the shared notification container to its view-model. */
-object NotificationStackAppearanceViewBinder {
- const val SCRIM_CORNER_RADIUS = 32f
-
- @JvmStatic
- fun bind(
- context: Context,
- view: SharedNotificationContainer,
- viewModel: NotificationStackAppearanceViewModel,
- ambientState: AmbientState,
- controller: NotificationStackScrollLayoutController,
- @Main mainImmediateDispatcher: CoroutineDispatcher,
- ): DisposableHandle {
- return view.repeatWhenAttached(mainImmediateDispatcher) {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- viewModel.stackBounds.collect { bounds ->
- val viewLeft = controller.view.left
- val viewTop = controller.view.top
- controller.setRoundedClippingBounds(
- bounds.left.roundToInt() - viewLeft,
- bounds.top.roundToInt() - viewTop,
- bounds.right.roundToInt() - viewLeft,
- bounds.bottom.roundToInt() - viewTop,
- SCRIM_CORNER_RADIUS.dpToPx(context),
- 0,
- )
- }
- }
-
- launch {
- viewModel.contentTop.collect {
- controller.updateTopPadding(it, controller.isAddOrRemoveAnimationPending)
- }
- }
-
- launch {
- var wasExpanding = false
- viewModel.expandFraction.collect { expandFraction ->
- val nowExpanding = expandFraction != 0f && expandFraction != 1f
- if (nowExpanding && !wasExpanding) {
- controller.onExpansionStarted()
- }
- ambientState.expansionFraction = expandFraction
- controller.expandedHeight = expandFraction * controller.view.height
- if (!nowExpanding && wasExpanding) {
- controller.onExpansionStopped()
- }
- wasExpanding = nowExpanding
- }
- }
-
- launch { viewModel.isScrollable.collect { controller.setScrollingEnabled(it) } }
- }
- }
- }
-
- private fun Float.dpToPx(context: Context): Int {
- return TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- this,
- context.resources.displayMetrics
- )
- .roundToInt()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackViewBinder.kt
new file mode 100644
index 0000000..1a34bb4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackViewBinder.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewbinder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
+import javax.inject.Inject
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+/** Binds the NSSL/Controller/AmbientState to their ViewModel. */
+@SysUISingleton
+class NotificationStackViewBinder
+@Inject
+constructor(
+ @Main private val mainImmediateDispatcher: CoroutineDispatcher,
+ private val ambientState: AmbientState,
+ private val view: NotificationStackScrollLayout,
+ private val controller: NotificationStackScrollLayoutController,
+ private val viewModel: NotificationStackAppearanceViewModel,
+ private val configuration: ConfigurationState,
+) {
+
+ fun bindWhileAttached(): DisposableHandle {
+ return view.repeatWhenAttached(mainImmediateDispatcher) {
+ repeatOnLifecycle(Lifecycle.State.CREATED) { bind() }
+ }
+ }
+
+ suspend fun bind() = coroutineScope {
+ launch {
+ combine(viewModel.stackClipping, clipRadius, ::Pair).collect { (clipping, clipRadius) ->
+ val (bounds, rounding) = clipping
+ val viewLeft = controller.view.left
+ val viewTop = controller.view.top
+ controller.setRoundedClippingBounds(
+ bounds.left.roundToInt() - viewLeft,
+ bounds.top.roundToInt() - viewTop,
+ bounds.right.roundToInt() - viewLeft,
+ bounds.bottom.roundToInt() - viewTop,
+ if (rounding.roundTop) clipRadius else 0,
+ if (rounding.roundBottom) clipRadius else 0,
+ )
+ }
+ }
+
+ launch {
+ viewModel.contentTop.collect {
+ controller.updateTopPadding(it, controller.isAddOrRemoveAnimationPending)
+ }
+ }
+
+ launch {
+ var wasExpanding = false
+ viewModel.expandFraction.collect { expandFraction ->
+ val nowExpanding = expandFraction != 0f && expandFraction != 1f
+ if (nowExpanding && !wasExpanding) {
+ controller.onExpansionStarted()
+ }
+ ambientState.expansionFraction = expandFraction
+ controller.expandedHeight = expandFraction * controller.view.height
+ if (!nowExpanding && wasExpanding) {
+ controller.onExpansionStopped()
+ }
+ wasExpanding = nowExpanding
+ }
+ }
+
+ launch { viewModel.isScrollable.collect { controller.setScrollingEnabled(it) } }
+ }
+
+ private val clipRadius: Flow<Int>
+ get() = configuration.getDimensionPixelOffset(R.dimen.notification_scrim_corner_radius)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 7c76ddb..ecf737a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -20,6 +20,7 @@
import android.view.WindowInsets
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
@@ -30,6 +31,8 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
+import com.android.systemui.util.kotlin.DisposableHandles
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.MutableStateFlow
@@ -38,18 +41,24 @@
import kotlinx.coroutines.launch
/** Binds the shared notification container to its view-model. */
-object SharedNotificationContainerBinder {
+@SysUISingleton
+class SharedNotificationContainerBinder
+@Inject
+constructor(
+ private val sceneContainerFlags: SceneContainerFlags,
+ private val controller: NotificationStackScrollLayoutController,
+ private val notificationStackSizeCalculator: NotificationStackSizeCalculator,
+ private val notificationStackViewBinder: NotificationStackViewBinder,
+ @Main private val mainImmediateDispatcher: CoroutineDispatcher,
+) {
- @JvmStatic
fun bind(
view: SharedNotificationContainer,
viewModel: SharedNotificationContainerViewModel,
- sceneContainerFlags: SceneContainerFlags,
- controller: NotificationStackScrollLayoutController,
- notificationStackSizeCalculator: NotificationStackSizeCalculator,
- @Main mainImmediateDispatcher: CoroutineDispatcher,
): DisposableHandle {
- val disposableHandle =
+ val disposables = DisposableHandles()
+
+ disposables +=
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
@@ -72,24 +81,6 @@
}
}
- // Required to capture keyguard media changes and ensure the notification count is correct
- val layoutChangeListener =
- object : View.OnLayoutChangeListener {
- override fun onLayoutChange(
- view: View,
- left: Int,
- top: Int,
- right: Int,
- bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
- ) {
- viewModel.notificationStackChanged()
- }
- }
-
val burnInParams = MutableStateFlow(BurnInParameters())
val viewState =
ViewStateAccessor(
@@ -100,7 +91,7 @@
* For animation sensitive coroutines, immediately run just like applicationScope does
* instead of doing a post() to the main thread. This extra delay can cause visible jitter.
*/
- val disposableHandleMainImmediate =
+ disposables +=
view.repeatWhenAttached(mainImmediateDispatcher) {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
@@ -167,7 +158,12 @@
}
}
- controller.setOnHeightChangedRunnable(Runnable { viewModel.notificationStackChanged() })
+ if (sceneContainerFlags.isEnabled()) {
+ disposables += notificationStackViewBinder.bindWhileAttached()
+ }
+
+ controller.setOnHeightChangedRunnable { viewModel.notificationStackChanged() }
+ disposables += DisposableHandle { controller.setOnHeightChangedRunnable(null) }
view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets ->
val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout()
@@ -176,16 +172,16 @@
}
insets
}
- view.addOnLayoutChangeListener(layoutChangeListener)
+ disposables += DisposableHandle { view.setOnApplyWindowInsetsListener(null) }
- return object : DisposableHandle {
- override fun dispose() {
- disposableHandle.dispose()
- disposableHandleMainImmediate.dispose()
- controller.setOnHeightChangedRunnable(null)
- view.setOnApplyWindowInsetsListener(null)
- view.removeOnLayoutChangeListener(layoutChangeListener)
+ // Required to capture keyguard media changes and ensure the notification count is correct
+ val layoutChangeListener =
+ View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
+ viewModel.notificationStackChanged()
}
- }
+ view.addOnLayoutChangeListener(layoutChangeListener)
+ disposables += DisposableHandle { view.removeOnLayoutChangeListener(layoutChangeListener) }
+
+ return disposables
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HeadsUpRowViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HeadsUpRowViewModel.kt
new file mode 100644
index 0000000..ec5e5be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HeadsUpRowViewModel.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.notification.stack.ui.viewmodel
+
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpRowInteractor
+
+class HeadsUpRowViewModel(headsUpRowInteractor: HeadsUpRowInteractor)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 4744fcb..5a7433d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -17,17 +17,20 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
+import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor
import com.android.systemui.statusbar.policy.domain.interactor.UserSetupInteractor
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
-import com.android.systemui.util.kotlin.combine
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.ui.AnimatableEvent
import com.android.systemui.util.ui.AnimatedValue
@@ -53,6 +56,8 @@
val logger: Optional<NotificationLoggerViewModel>,
activeNotificationsInteractor: ActiveNotificationsInteractor,
notificationStackInteractor: NotificationStackInteractor,
+ private val headsUpNotificationInteractor: HeadsUpNotificationInteractor,
+ keyguardInteractor: KeyguardInteractor,
remoteInputInteractor: RemoteInputInteractor,
seenNotificationsInteractor: SeenNotificationsInteractor,
shadeInteractor: ShadeInteractor,
@@ -105,7 +110,32 @@
}
}
- val shouldShowFooterView: Flow<AnimatedValue<Boolean>> by lazy {
+ /**
+ * Whether the footer should not be visible for the user, even if it's present in the list (as
+ * per [shouldIncludeFooterView] below).
+ *
+ * This essentially corresponds to having the view set to INVISIBLE.
+ */
+ val shouldHideFooterView: Flow<Boolean> by lazy {
+ if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(false)
+ } else {
+ // When the shade is closed, the footer is still present in the list, but not visible.
+ // This prevents the footer from being shown when a HUN is present, while still allowing
+ // the footer to be counted as part of the shade for measurements.
+ shadeInteractor.shadeExpansion.map { it == 0f }.distinctUntilChanged()
+ }
+ }
+
+ /**
+ * Whether the footer should be part of the list or not, and whether the transition from one
+ * state to another should be animated. This essentially corresponds to transitioning the view
+ * visibility from VISIBLE to GONE and vice versa.
+ *
+ * Note that this value being true doesn't necessarily mean that the footer is visible. It could
+ * be hidden by another condition (see [shouldHideFooterView] above).
+ */
+ val shouldIncludeFooterView: Flow<AnimatedValue<Boolean>> by lazy {
if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
flowOf(AnimatedValue.NotAnimating(false))
} else {
@@ -114,34 +144,30 @@
userSetupInteractor.isUserSetUp,
notificationStackInteractor.isShowingOnLockscreen,
shadeInteractor.isQsFullscreen,
- remoteInputInteractor.isRemoteInputActive,
- shadeInteractor.shadeExpansion.map { it == 0f }.distinctUntilChanged(),
+ remoteInputInteractor.isRemoteInputActive
) {
hasNotifications,
isUserSetUp,
isShowingOnLockscreen,
qsFullScreen,
- isRemoteInputActive,
- isShadeClosed ->
+ isRemoteInputActive ->
when {
- !hasNotifications -> VisibilityChange.HIDE_WITH_ANIMATION
+ !hasNotifications -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
// Hide the footer until the user setup is complete, to prevent access
// to settings (b/193149550).
- !isUserSetUp -> VisibilityChange.HIDE_WITH_ANIMATION
+ !isUserSetUp -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
// Do not show the footer if the lockscreen is visible (incl. AOD),
// except if the shade is opened on top. See also b/219680200.
// Do not animate, as that makes the footer appear briefly when
// transitioning between the shade and keyguard.
- isShowingOnLockscreen -> VisibilityChange.HIDE_WITHOUT_ANIMATION
+ isShowingOnLockscreen -> VisibilityChange.DISAPPEAR_WITHOUT_ANIMATION
// Do not show the footer if quick settings are fully expanded (except
// for the foldable split shade view). See b/201427195 && b/222699879.
- qsFullScreen -> VisibilityChange.HIDE_WITH_ANIMATION
+ qsFullScreen -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
// Hide the footer if remote input is active (i.e. user is replying to a
// notification). See b/75984847.
- isRemoteInputActive -> VisibilityChange.HIDE_WITH_ANIMATION
- // Never show the footer if the shade is collapsed (e.g. when HUNing).
- isShadeClosed -> VisibilityChange.HIDE_WITHOUT_ANIMATION
- else -> VisibilityChange.SHOW_WITH_ANIMATION
+ isRemoteInputActive -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
+ else -> VisibilityChange.APPEAR_WITH_ANIMATION
}
}
.flowOn(bgDispatcher)
@@ -174,9 +200,9 @@
}
enum class VisibilityChange(val visible: Boolean, val canAnimate: Boolean) {
- HIDE_WITHOUT_ANIMATION(visible = false, canAnimate = false),
- HIDE_WITH_ANIMATION(visible = false, canAnimate = true),
- SHOW_WITH_ANIMATION(visible = true, canAnimate = true)
+ DISAPPEAR_WITHOUT_ANIMATION(visible = false, canAnimate = false),
+ DISAPPEAR_WITH_ANIMATION(visible = false, canAnimate = true),
+ APPEAR_WITH_ANIMATION(visible = true, canAnimate = true)
}
// TODO(b/308591475): This should be tracked separately by the empty shade.
@@ -212,4 +238,41 @@
activeNotificationsInteractor.hasNonClearableSilentNotifications
}
}
+
+ val topHeadsUpRow: Flow<HeadsUpRowKey?> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(null)
+ } else {
+ headsUpNotificationInteractor.topHeadsUpRow
+ }
+ }
+
+ val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(emptySet())
+ } else {
+ headsUpNotificationInteractor.pinnedHeadsUpRows
+ }
+ }
+
+ val headsUpAnimationsEnabled: Flow<Boolean> by lazy {
+ combine(keyguardInteractor.isKeyguardShowing, shadeInteractor.isShadeFullyExpanded) {
+ (isKeyguardShowing, isShadeFullyExpanded) ->
+ // TODO(b/325936094) use isShadeFullyCollapsed instead
+ !isKeyguardShowing && !isShadeFullyExpanded
+ }
+ }
+
+ val hasPinnedHeadsUpRow: Flow<Boolean> by lazy {
+ if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
+ flowOf(false)
+ } else {
+ headsUpNotificationInteractor.hasPinnedRows
+ }
+ }
+
+ // TODO(b/325936094) use it for the text displayed in the StatusBar
+ fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowViewModel =
+ HeadsUpRowViewModel(headsUpNotificationInteractor.headsUpRow(key))
+ fun elementKeyFor(key: HeadsUpRowKey): Any = headsUpNotificationInteractor.elementKeyFor(key)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
index b6167e1..a7cbc33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
@@ -18,7 +18,6 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
@@ -27,6 +26,7 @@
import com.android.systemui.scene.shared.model.Scenes.Shade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.model.StackClipping
import com.android.systemui.util.kotlin.FlowDumperImpl
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -83,8 +83,13 @@
.dumpWhileCollecting("expandFraction")
/** The bounds of the notification stack in the current scene. */
- val stackBounds: Flow<NotificationContainerBounds> =
- stackAppearanceInteractor.stackBounds.dumpValue("stackBounds")
+ val stackClipping: Flow<StackClipping> =
+ combine(
+ stackAppearanceInteractor.stackBounds,
+ stackAppearanceInteractor.stackRounding,
+ ::StackClipping
+ )
+ .dumpWhileCollecting("stackClipping")
/** The y-coordinate in px of top of the contents of the notification stack. */
val contentTop: StateFlow<Float> = stackAppearanceInteractor.contentTop.dumpValue("contentTop")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 9e2497d..bd83121 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -24,6 +24,8 @@
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.model.StackBounds
+import com.android.systemui.statusbar.notification.stack.shared.model.StackRounding
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -61,12 +63,17 @@
right: Float,
bottom: Float,
) {
- val notificationContainerBounds =
- NotificationContainerBounds(top = top, bottom = bottom, left = left, right = right)
- keyguardInteractor.setNotificationContainerBounds(notificationContainerBounds)
- interactor.setStackBounds(notificationContainerBounds)
+ keyguardInteractor.setNotificationContainerBounds(
+ NotificationContainerBounds(top = top, bottom = bottom)
+ )
+ interactor.setStackBounds(
+ StackBounds(top = top, bottom = bottom, left = left, right = right)
+ )
}
+ /** Corner rounding of the stack */
+ val stackRounding: Flow<StackRounding> = interactor.stackRounding
+
/**
* The height in px of the contents of notification stack. Depending on the number of
* notifications, this can exceed the space available on screen to show notifications, at which
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index a38840b..d112edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -35,7 +35,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
-import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
@@ -366,27 +366,40 @@
}
}
}
- .onStart { emit(0f) }
+ .onStart { emit(1f) }
.dumpWhileCollecting("alphaForShadeAndQsExpansion")
- private val alphaWhenGoneAndShadeState: Flow<Float> =
- combineTransform(
- keyguardTransitionInteractor.transitions
- .map { step -> step.to == GONE && step.transitionState == FINISHED }
- .distinctUntilChanged(),
- keyguardInteractor.statusBarState,
- ) { isGoneTransitionFinished, statusBarState ->
- if (isGoneTransitionFinished && statusBarState == SHADE) {
- emit(1f)
+ private val isGoneTransitionRunning: Flow<Boolean> =
+ flow {
+ while (currentCoroutineContext().isActive) {
+ emit(false)
+ // Ensure start where GONE is inactive
+ keyguardTransitionInteractor.transitionValue(GONE).first { it == 0f }
+ // Wait for a GONE transition to begin
+ keyguardTransitionInteractor.transitionStepsToState(GONE).first {
+ it.value > 0f && it.transitionState == RUNNING
+ }
+ emit(true)
+ // Now await the signal that SHADE state has been reached or the GONE transition
+ // was reversed. Until SHADE state has been replaced and merged with GONE, it is
+ // the only source of when it is considered safe to reset alpha to 1f for HUNs.
+ combine(
+ keyguardInteractor.statusBarState,
+ // Emit -1f on start to make sure the flow runs
+ keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(-1f) }
+ ) { statusBarState, goneValue ->
+ statusBarState == SHADE || goneValue == 0f
+ }
+ .first { it }
}
}
- .dumpWhileCollecting("alphaWhenGoneAndShadeState")
+ .dumpWhileCollecting("goneTransitionInProgress")
fun keyguardAlpha(viewState: ViewStateAccessor): Flow<Float> {
// All transition view models are mututally exclusive, and safe to merge
val alphaTransitions =
merge(
- alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ alternateBouncerToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToLockscreenTransitionViewModel.notificationAlpha,
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
@@ -407,12 +420,11 @@
return merge(
alphaTransitions,
- // Sends a final alpha value of 1f when truly gone, to make sure HUNs appear
- alphaWhenGoneAndShadeState,
// These remaining cases handle alpha changes within an existing state, such as
// shade expansion or swipe to dismiss
combineTransform(
isOnLockscreenWithoutShade,
+ isGoneTransitionRunning,
shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
keyguardInteractor.dismissAlpha.dumpWhileCollecting(
@@ -420,6 +432,7 @@
),
) {
isOnLockscreenWithoutShade,
+ isGoneTransitionRunning,
shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
dismissAlpha ->
@@ -427,7 +440,7 @@
if (!shadeCollapseFadeIn && dismissAlpha != null) {
emit(dismissAlpha)
}
- } else {
+ } else if (!isGoneTransitionRunning) {
emit(alphaForShadeAndQsExpansion)
}
},
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
new file mode 100644
index 0000000..cb360fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.notification.ui.viewbinder
+
+import android.util.Log
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+private const val TAG = "HunBinder"
+private val DEBUG = true // Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG)
+
+class HeadsUpNotificationViewBinder
+@Inject
+constructor(private val viewModel: NotificationListViewModel) {
+ suspend fun bindHeadsUpNotifications(parentView: NotificationStackScrollLayout): Unit =
+ coroutineScope {
+ launch {
+ var previousKeys = emptySet<HeadsUpRowKey>()
+ viewModel.pinnedHeadsUpRows
+ .sample(viewModel.headsUpAnimationsEnabled, ::Pair)
+ .collect { (newKeys, animationsEnabled) ->
+ if (DEBUG) {
+ Log.d(TAG, "update:$newKeys")
+ }
+
+ val added = newKeys - previousKeys
+ val removed = previousKeys - newKeys
+ previousKeys = newKeys
+
+ if (animationsEnabled) {
+ added.forEach { key ->
+ parentView.generateHeadsUpAnimation(
+ obtainView(key),
+ /* isHeadsUp = */ true
+ )
+ }
+ removed.forEach { key ->
+ val row = obtainView(key)
+ parentView.generateHeadsUpAnimation(row, /* isHeadsUp = */ false)
+ row.setHeadsUpIsVisible()
+ }
+ }
+ }
+ }
+ launch {
+ viewModel.topHeadsUpRow.collect { key ->
+ parentView.setTopHeadsUpRow(key?.let(::obtainView))
+ }
+ }
+ launch {
+ viewModel.hasPinnedHeadsUpRow.collect { parentView.setInHeadsUpPinnedMode(it) }
+ }
+ }
+
+ private fun obtainView(key: HeadsUpRowKey): ExpandableNotificationRow {
+ return viewModel.elementKeyFor(key) as ExpandableNotificationRow
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index a55de25..37646ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -21,6 +21,7 @@
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
+import android.os.Bundle
import android.os.RemoteException
import android.os.UserHandle
import android.provider.Settings
@@ -149,6 +150,23 @@
)
}
+ override fun startPendingIntentMaybeDismissingKeyguard(
+ intent: PendingIntent,
+ intentSentUiThreadCallback: Runnable?,
+ animationController: ActivityTransitionAnimator.Controller?,
+ fillInIntent: Intent?,
+ extraOptions: Bundle?,
+ ) {
+ activityStarterInternal.startPendingIntentDismissingKeyguard(
+ intent = intent,
+ intentSentUiThreadCallback = intentSentUiThreadCallback,
+ animationController = animationController,
+ showOverLockscreen = true,
+ fillInIntent = fillInIntent,
+ extraOptions = extraOptions,
+ )
+ }
+
/**
* TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
* this.
@@ -554,6 +572,8 @@
associatedView: View? = null,
animationController: ActivityTransitionAnimator.Controller? = null,
showOverLockscreen: Boolean = false,
+ fillInIntent: Intent? = null,
+ extraOptions: Bundle? = null,
) {
val animationController =
if (associatedView is ExpandableNotificationRow) {
@@ -614,9 +634,10 @@
val options =
ActivityOptions(
CentralSurfaces.getActivityOptions(
- displayId,
- animationAdapter
- )
+ displayId,
+ animationAdapter
+ )
+ .apply { extraOptions?.let { putAll(it) } }
)
// TODO b/221255671: restrict this to only be set for
// notifications
@@ -625,9 +646,9 @@
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
return intent.sendAndReturnResult(
- null,
+ context,
0,
- null,
+ fillInIntent,
null,
null,
null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 665fc0a..ad3012e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -56,7 +56,7 @@
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -80,8 +80,8 @@
private final ScreenPinningRequest mScreenPinningRequest;
private final com.android.systemui.shade.ShadeController mShadeController;
private final CommandQueue mCommandQueue;
- private final ShadeViewController mShadeViewController;
private final PanelExpansionInteractor mPanelExpansionInteractor;
+ private final ShadeHeaderController mShadeHeaderController;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -119,8 +119,8 @@
ScreenPinningRequest screenPinningRequest,
ShadeController shadeController,
CommandQueue commandQueue,
- ShadeViewController shadeViewController,
PanelExpansionInteractor panelExpansionInteractor,
+ ShadeHeaderController shadeHeaderController,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
MetricsLogger metricsLogger,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -146,8 +146,8 @@
mScreenPinningRequest = screenPinningRequest;
mShadeController = shadeController;
mCommandQueue = commandQueue;
- mShadeViewController = shadeViewController;
mPanelExpansionInteractor = panelExpansionInteractor;
+ mShadeHeaderController = shadeHeaderController;
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mMetricsLogger = metricsLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -279,7 +279,7 @@
}
}
- mShadeViewController.disableHeader(state1, state2, animate);
+ mShadeHeaderController.disable(state1, state2, animate);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index d32e88b..f76de04c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -27,7 +27,6 @@
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import static com.android.systemui.Flags.lightRevealMigration;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import static com.android.systemui.Flags.newAodTransition;
import static com.android.systemui.Flags.predictiveBackSysui;
import static com.android.systemui.Flags.truncatedStatusBarIconsFix;
@@ -142,6 +141,7 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder;
@@ -1470,7 +1470,7 @@
return (v, event) -> {
mAutoHideController.checkUserAutoHide(event);
mRemoteInputManager.checkRemoteInputOutside(event);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mShadeController.onStatusBarTouch(event);
}
return getNotificationShadeWindowView().onTouchEvent(event);
@@ -2507,7 +2507,7 @@
mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
mDeviceInteractive = true;
- boolean isFlaggedOff = newAodTransition() && migrateClocksToBlueprint();
+ boolean isFlaggedOff = newAodTransition() && MigrateClocksToBlueprint.isEnabled();
if (!isFlaggedOff && shouldAnimateDozeWakeup()) {
// If this is false, the power button must be physically pressed in order to
// trigger fingerprint authentication.
@@ -3147,7 +3147,14 @@
public void onDozeAmountChanged(float linear, float eased) {
if (!lightRevealMigration()
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
- mLightRevealScrim.setRevealAmount(1f - linear);
+ if (DeviceEntryUdfpsRefactor.isEnabled()) {
+ // If wakeAndUnlocking, this is handled in AuthRippleInteractor
+ if (!mBiometricUnlockController.isWakeAndUnlock()) {
+ mLightRevealScrim.setRevealAmount(1f - linear);
+ }
+ } else {
+ mLightRevealScrim.setRevealAmount(1f - linear);
+ }
}
}
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 442e43a..7abcf13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -41,7 +41,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
import com.android.systemui.shade.NotificationShadeWindowViewController;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 24be3db..3f200d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -22,6 +22,7 @@
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Handler;
+import android.util.ArrayMap;
import android.util.Pools;
import androidx.collection.ArraySet;
@@ -40,7 +41,10 @@
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.AnimationStateHandler;
import com.android.systemui.statusbar.policy.AvalancheController;
@@ -58,13 +62,21 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.Stack;
import javax.inject.Inject;
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
/** A implementation of HeadsUpManager for phone. */
@SysUISingleton
-public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUpChangedListener {
+public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
+ HeadsUpRepository, OnHeadsUpChangedListener {
private static final String TAG = "HeadsUpManagerPhone";
@VisibleForTesting
@@ -73,15 +85,20 @@
private final GroupMembershipManager mGroupMembershipManager;
private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
private final VisualStabilityProvider mVisualStabilityProvider;
- private boolean mReleaseOnExpandFinish;
+ // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
+ private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
+ StateFlowKt.MutableStateFlow(null);
+ private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =
+ StateFlowKt.MutableStateFlow(new HashSet<>());
+ private final MutableStateFlow<Boolean> mHeadsUpGoingAway = StateFlowKt.MutableStateFlow(false);
+ private boolean mReleaseOnExpandFinish;
private boolean mTrackingHeadsUp;
private final HashSet<String> mSwipedOutKeys = new HashSet<>();
private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
private final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
- private boolean mHeadsUpGoingAway;
private int mStatusBarState;
private AnimationStateHandler mAnimationStateHandler;
private int mHeadsUpInset;
@@ -94,6 +111,7 @@
@Override
public HeadsUpEntryPhone acquire() {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
if (!mPoolObjects.isEmpty()) {
return mPoolObjects.pop();
}
@@ -102,6 +120,7 @@
@Override
public boolean release(@NonNull HeadsUpEntryPhone instance) {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
mPoolObjects.push(instance);
return true;
}
@@ -245,7 +264,7 @@
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
if (isExpanded) {
- mHeadsUpGoingAway = false;
+ mHeadsUpGoingAway.setValue(false);
}
}
}
@@ -256,17 +275,17 @@
*/
@Override
public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
- if (headsUpGoingAway != mHeadsUpGoingAway) {
- mHeadsUpGoingAway = headsUpGoingAway;
+ if (headsUpGoingAway != mHeadsUpGoingAway.getValue()) {
for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
listener.onHeadsUpGoingAwayStateChanged(headsUpGoingAway);
}
+ mHeadsUpGoingAway.setValue(headsUpGoingAway);
}
}
@Override
public boolean isHeadsUpGoingAway() {
- return mHeadsUpGoingAway;
+ return mHeadsUpGoingAway.getValue();
}
/**
@@ -285,6 +304,7 @@
} else {
headsUpEntry.updateEntry(false /* updatePostTime */, "setRemoteInputActive(false)");
}
+ onEntryUpdated(headsUpEntry);
}
}
@@ -371,15 +391,48 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// HeadsUpManager utility (protected) methods overrides:
+ @NonNull
@Override
- protected HeadsUpEntry createHeadsUpEntry() {
- return mEntryPool.acquire();
+ protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
+ if (NotificationsHeadsUpRefactor.isEnabled()) {
+ return new HeadsUpEntryPhone(entry);
+ } else {
+ HeadsUpEntryPhone headsUpEntry = mEntryPool.acquire();
+ headsUpEntry.setEntry(entry);
+ return headsUpEntry;
+ }
+ }
+
+ @Override
+ protected void onEntryAdded(HeadsUpEntry headsUpEntry) {
+ super.onEntryAdded(headsUpEntry);
+ updateTopHeadsUpFlow();
+ updateHeadsUpFlow();
+ }
+
+ @Override
+ protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
+ super.onEntryUpdated(headsUpEntry);
+ // no need to update the list here
+ updateTopHeadsUpFlow();
}
@Override
protected void onEntryRemoved(HeadsUpEntry headsUpEntry) {
super.onEntryRemoved(headsUpEntry);
- mEntryPool.release((HeadsUpEntryPhone) headsUpEntry);
+ if (!NotificationsHeadsUpRefactor.isEnabled()) {
+ mEntryPool.release((HeadsUpEntryPhone) headsUpEntry);
+ }
+ updateTopHeadsUpFlow();
+ updateHeadsUpFlow();
+ }
+
+ private void updateTopHeadsUpFlow() {
+ mTopHeadsUpRow.setValue((HeadsUpRowRepository) getTopHeadsUpEntry());
+ }
+
+ private void updateHeadsUpFlow() {
+ mHeadsUpNotificationRows.setValue(new HashSet<>(getHeadsUpEntryPhoneMap().values()));
}
@Override
@@ -403,6 +456,12 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Private utility methods:
+ @NonNull
+ private ArrayMap<String, HeadsUpEntryPhone> getHeadsUpEntryPhoneMap() {
+ //noinspection unchecked
+ return (ArrayMap<String, HeadsUpEntryPhone>) ((ArrayMap) mHeadsUpEntryMap);
+ }
+
@Nullable
private HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
return (HeadsUpEntryPhone) mHeadsUpEntryMap.get(key);
@@ -410,7 +469,11 @@
@Nullable
private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
- return (HeadsUpEntryPhone) getTopHeadsUpEntry();
+ if (NotificationsHeadsUpRefactor.isEnabled()) {
+ return (HeadsUpEntryPhone) mTopHeadsUpRow.getValue();
+ } else {
+ return (HeadsUpEntryPhone) getTopHeadsUpEntry();
+ }
}
@Override
@@ -427,26 +490,73 @@
return headsUpEntry == null || headsUpEntry != topEntry || super.canRemoveImmediately(key);
}
+ @Override
+ @NonNull
+ public Flow<HeadsUpRowRepository> getTopHeadsUpRow() {
+ return mTopHeadsUpRow;
+ }
+
+ @Override
+ @NonNull
+ public Flow<Set<HeadsUpRowRepository>> getActiveHeadsUpRows() {
+ return mHeadsUpNotificationRows;
+ }
+
+ @Override
+ @NonNull
+ public Flow<Boolean> getHeadsUpAnimatingAway() {
+ return mHeadsUpGoingAway;
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// HeadsUpEntryPhone:
- protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry {
+ protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry implements
+ HeadsUpRowRepository {
private boolean mGutsShownPinned;
+ private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
/**
* If the time this entry has been on was extended
*/
private boolean extended;
-
@Override
public boolean isSticky() {
return super.isSticky() || mGutsShownPinned;
}
- public void setEntry(@NonNull final NotificationEntry entry) {
- Runnable removeHeadsUpRunnable = () -> {
+ public HeadsUpEntryPhone() {
+ super();
+ }
+
+ public HeadsUpEntryPhone(NotificationEntry entry) {
+ super(entry);
+ }
+
+ @Override
+ @NonNull
+ public String getKey() {
+ return requireEntry().getKey();
+ }
+
+ @Override
+ @NonNull
+ public StateFlow<Boolean> isPinned() {
+ return mIsPinned;
+ }
+
+ @Override
+ protected void setRowPinned(boolean pinned) {
+ // TODO(b/327624082): replace this super call with a ViewBinder
+ super.setRowPinned(pinned);
+ mIsPinned.setValue(pinned);
+ }
+
+ @Override
+ protected Runnable createRemoveRunnable(NotificationEntry entry) {
+ return () -> {
if (!mVisualStabilityProvider.isReorderingAllowed()
// We don't want to allow reordering while pulsing, but headsup need to
// time out anyway
@@ -460,8 +570,6 @@
removeEntry(entry.getKey());
}
};
-
- setEntry(entry, removeHeadsUpRunnable);
}
@Override
@@ -521,6 +629,17 @@
protected long calculateFinishTime() {
return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
}
+
+ @Override
+ @NonNull
+ public Object getElementKey() {
+ return requireEntry().getRow();
+ }
+
+ private NotificationEntry requireEntry() {
+ /* check if */ NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode();
+ return Objects.requireNonNull(mEntry);
+ }
}
private final StateListener mStatusBarStateListener = new StateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index 94f62e0..f84efbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.Flags.newAodTransition;
-import static com.android.systemui.Flags.migrateClocksToBlueprint;
import android.content.Context;
import android.content.res.Resources;
@@ -41,6 +40,7 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -545,7 +545,7 @@
return;
}
if (mScreenOffAnimationController.shouldAnimateAodIcons()) {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mAodIcons.setTranslationY(-mAodIconAppearTranslation);
}
mAodIcons.setAlpha(0);
@@ -557,14 +557,14 @@
.start();
} else {
mAodIcons.setAlpha(1.0f);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mAodIcons.setTranslationY(0);
}
}
}
private void animateInAodIconTranslation() {
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mAodIcons.animate()
.setInterpolator(Interpolators.DECELERATE_QUINT)
.translationY(0)
@@ -667,7 +667,7 @@
}
} else {
mAodIcons.setAlpha(1.0f);
- if (!migrateClocksToBlueprint()) {
+ if (!MigrateClocksToBlueprint.isEnabled()) {
mAodIcons.setTranslationY(0);
}
mAodIcons.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f99817a..a99834a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -89,7 +89,7 @@
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -106,6 +106,8 @@
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -115,7 +117,6 @@
import javax.inject.Inject;
-import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.ExperimentalCoroutinesApi;
import kotlinx.coroutines.Job;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 67d2299..479aef1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -19,10 +19,11 @@
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.DejankUtils
import com.android.systemui.Flags.lightRevealMigration
-import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.CircleReveal
@@ -45,9 +46,7 @@
*/
private const val ANIMATE_IN_KEYGUARD_DELAY = 600L
-/**
- * Duration for the light reveal portion of the animation.
- */
+/** Duration for the light reveal portion of the animation. */
private const val LIGHT_REVEAL_ANIMATION_DURATION = 500L
/**
@@ -58,7 +57,9 @@
* and then animates in the AOD UI.
*/
@SysUISingleton
-class UnlockedScreenOffAnimationController @Inject constructor(
+class UnlockedScreenOffAnimationController
+@Inject
+constructor(
private val context: Context,
private val wakefulnessLifecycle: WakefulnessLifecycle,
private val statusBarStateControllerImpl: StatusBarStateControllerImpl,
@@ -69,11 +70,11 @@
private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>,
private val interactionJankMonitor: InteractionJankMonitor,
private val powerManager: PowerManager,
+ private val shadeLockscreenInteractorLazy: Lazy<ShadeLockscreenInteractor>,
private val panelExpansionInteractorLazy: Lazy<PanelExpansionInteractor>,
private val handler: Handler = Handler(),
) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
private lateinit var centralSurfaces: CentralSurfaces
- private lateinit var shadeViewController: ShadeViewController
/**
* Whether or not [initialize] has been called to provide us with the StatusBar,
* NotificationPanelViewController, and LightRevealSrim so that we can run the unlocked screen
@@ -95,52 +96,61 @@
*/
private var decidedToAnimateGoingToSleep: Boolean? = null
- private val lightRevealAnimator = ValueAnimator.ofFloat(1f, 0f).apply {
- duration = LIGHT_REVEAL_ANIMATION_DURATION
- interpolator = Interpolators.LINEAR
- addUpdateListener {
- if (lightRevealMigration()) return@addUpdateListener
- if (lightRevealScrim.revealEffect !is CircleReveal) {
- lightRevealScrim.revealAmount = it.animatedValue as Float
- }
- if (lightRevealScrim.isScrimAlmostOccludes &&
- interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) {
- // ends the instrument when the scrim almost occludes the screen.
- // because the following janky frames might not be perceptible.
- interactionJankMonitor.end(CUJ_SCREEN_OFF)
- }
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationCancel(animation: Animator) {
- if (lightRevealMigration()) return
+ private val lightRevealAnimator =
+ ValueAnimator.ofFloat(1f, 0f).apply {
+ duration = LIGHT_REVEAL_ANIMATION_DURATION
+ interpolator = Interpolators.LINEAR
+ addUpdateListener {
+ if (lightRevealMigration()) return@addUpdateListener
if (lightRevealScrim.revealEffect !is CircleReveal) {
- lightRevealScrim.revealAmount = 1f
+ lightRevealScrim.revealAmount = it.animatedValue as Float
+ }
+ if (
+ lightRevealScrim.isScrimAlmostOccludes &&
+ interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)
+ ) {
+ // ends the instrument when the scrim almost occludes the screen.
+ // because the following janky frames might not be perceptible.
+ interactionJankMonitor.end(CUJ_SCREEN_OFF)
}
}
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationCancel(animation: Animator) {
+ if (lightRevealMigration()) return
+ if (lightRevealScrim.revealEffect !is CircleReveal) {
+ lightRevealScrim.revealAmount = 1f
+ }
+ }
- override fun onAnimationEnd(animation: Animator) {
- lightRevealAnimationPlaying = false
- interactionJankMonitor.end(CUJ_SCREEN_OFF)
- }
+ override fun onAnimationEnd(animation: Animator) {
+ lightRevealAnimationPlaying = false
+ interactionJankMonitor.end(CUJ_SCREEN_OFF)
+ }
- override fun onAnimationStart(animation: Animator) {
- interactionJankMonitor.begin(
- notifShadeWindowControllerLazy.get().windowRootView, CUJ_SCREEN_OFF)
- }
- })
- }
+ override fun onAnimationStart(animation: Animator) {
+ interactionJankMonitor.begin(
+ notifShadeWindowControllerLazy.get().windowRootView,
+ CUJ_SCREEN_OFF
+ )
+ }
+ }
+ )
+ }
// FrameCallback used to delay starting the light reveal animation until the next frame
- private val startLightRevealCallback = namedRunnable("startLightReveal") {
- lightRevealAnimationPlaying = true
- lightRevealAnimator.start()
- }
-
- private val animatorDurationScaleObserver = object : ContentObserver(null) {
- override fun onChange(selfChange: Boolean) {
- updateAnimatorDurationScale()
+ private val startLightRevealCallback =
+ namedRunnable("startLightReveal") {
+ lightRevealAnimationPlaying = true
+ lightRevealAnimator.start()
}
- }
+
+ private val animatorDurationScaleObserver =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ updateAnimatorDurationScale()
+ }
+ }
override fun initialize(
centralSurfaces: CentralSurfaces,
@@ -150,26 +160,24 @@
this.initialized = true
this.lightRevealScrim = lightRevealScrim
this.centralSurfaces = centralSurfaces
- this.shadeViewController = shadeViewController
updateAnimatorDurationScale()
globalSettings.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
- /* notify for descendants */ false,
- animatorDurationScaleObserver)
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+ /* notify for descendants */ false,
+ animatorDurationScaleObserver
+ )
wakefulnessLifecycle.addObserver(this)
}
fun updateAnimatorDurationScale() {
- animatorDurationScale = fixScale(
- globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f))
+ animatorDurationScale =
+ fixScale(globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f))
}
- override fun shouldDelayKeyguardShow(): Boolean =
- shouldPlayAnimation()
+ override fun shouldDelayKeyguardShow(): Boolean = shouldPlayAnimation()
- override fun isKeyguardShowDelayed(): Boolean =
- isAnimationPlaying()
+ override fun isKeyguardShowDelayed(): Boolean = isAnimationPlaying()
/**
* Animates in the provided keyguard view, ending in the same position that it will be in on
@@ -190,15 +198,21 @@
// We animate the Y properly separately using the PropertyAnimator, as the panel
// view also needs to update the end position.
PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.Y)
- PropertyAnimator.setProperty(keyguardView, AnimatableProperty.Y, currentY,
- AnimationProperties().setDuration(duration.toLong()),
- true /* animate */)
+ PropertyAnimator.setProperty(
+ keyguardView,
+ AnimatableProperty.Y,
+ currentY,
+ AnimationProperties().setDuration(duration.toLong()),
+ true /* animate */
+ )
// Cancel any existing CUJs before starting the animation
interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.ALPHA)
PropertyAnimator.setProperty(
- keyguardView, AnimatableProperty.ALPHA, 1f,
+ keyguardView,
+ AnimatableProperty.ALPHA,
+ 1f,
AnimationProperties()
.setDelay(0)
.setDuration(duration.toLong())
@@ -230,13 +244,14 @@
interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
}
.setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_SLOW_IN),
- true /* animate */)
- val builder = InteractionJankMonitor.Configuration.Builder
- .withView(
+ true /* animate */
+ )
+ val builder =
+ InteractionJankMonitor.Configuration.Builder.withView(
InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD,
checkNotNull(notifShadeWindowControllerLazy.get().windowRootView)
- )
- .setTag(statusBarStateControllerImpl.getClockId())
+ )
+ .setTag(statusBarStateControllerImpl.getClockId())
interactionJankMonitor.begin(builder)
}
@@ -284,25 +299,34 @@
// chance of missing the first frame, so to mitigate this we should start the animation
// on the next frame.
DejankUtils.postAfterTraversal(startLightRevealCallback)
- handler.postDelayed({
- // Only run this callback if the device is sleeping (not interactive). This callback
- // is removed in onStartedWakingUp, but since that event is asynchronously
- // dispatched, a race condition could make it possible for this callback to be run
- // as the device is waking up. That results in the AOD UI being shown while we wake
- // up, with unpredictable consequences.
- if (!powerManager.isInteractive(Display.DEFAULT_DISPLAY) &&
- shouldAnimateInKeyguard) {
- if (!migrateClocksToBlueprint()) {
- // Tracking this state should no longer be relevant, as the isInteractive
- // check covers it
- aodUiAnimationPlaying = true
- }
+ handler.postDelayed(
+ {
+ // Only run this callback if the device is sleeping (not interactive). This
+ // callback
+ // is removed in onStartedWakingUp, but since that event is asynchronously
+ // dispatched, a race condition could make it possible for this callback to be
+ // run
+ // as the device is waking up. That results in the AOD UI being shown while we
+ // wake
+ // up, with unpredictable consequences.
+ if (
+ !powerManager.isInteractive(Display.DEFAULT_DISPLAY) &&
+ shouldAnimateInKeyguard
+ ) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
+ // Tracking this state should no longer be relevant, as the
+ // isInteractive
+ // check covers it
+ aodUiAnimationPlaying = true
+ }
- // Show AOD. That'll cause the KeyguardVisibilityHelper to call
- // #animateInKeyguard.
- shadeViewController.showAodUi()
- }
- }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong())
+ // Show AOD. That'll cause the KeyguardVisibilityHelper to call
+ // #animateInKeyguard.
+ shadeLockscreenInteractorLazy.get().showAodUi()
+ }
+ },
+ (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()
+ )
return true
} else {
@@ -335,8 +359,12 @@
}
// If animations are disabled system-wide, don't play this one either.
- if (Settings.Global.getString(
- context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) == "0") {
+ if (
+ Settings.Global.getString(
+ context.contentResolver,
+ Settings.Global.ANIMATOR_DURATION_SCALE
+ ) == "0"
+ ) {
return false
}
@@ -360,8 +388,10 @@
// If we're not allowed to rotate the keyguard, it can only be displayed in zero-degree
// portrait. If we're in another orientation, disable the screen off animation so we don't
// animate in the keyguard AOD UI sideways or upside down.
- if (!keyguardStateController.isKeyguardScreenRotationAllowed &&
- context.display?.rotation != Surface.ROTATION_0) {
+ if (
+ !keyguardStateController.isKeyguardScreenRotationAllowed &&
+ context.display?.rotation != Surface.ROTATION_0
+ ) {
return false
}
@@ -380,23 +410,18 @@
return isScreenOffLightRevealAnimationPlaying() || aodUiAnimationPlaying
}
- override fun shouldAnimateInKeyguard(): Boolean =
- shouldAnimateInKeyguard
+ override fun shouldAnimateInKeyguard(): Boolean = shouldAnimateInKeyguard
- override fun shouldHideScrimOnWakeUp(): Boolean =
- isScreenOffLightRevealAnimationPlaying()
+ override fun shouldHideScrimOnWakeUp(): Boolean = isScreenOffLightRevealAnimationPlaying()
override fun overrideNotificationsDozeAmount(): Boolean =
shouldPlayUnlockedScreenOffAnimation() && isAnimationPlaying()
- override fun shouldShowAodIconsWhenShade(): Boolean =
- isAnimationPlaying()
+ override fun shouldShowAodIconsWhenShade(): Boolean = isAnimationPlaying()
- override fun shouldAnimateAodIcons(): Boolean =
- shouldPlayUnlockedScreenOffAnimation()
+ override fun shouldAnimateAodIcons(): Boolean = shouldPlayUnlockedScreenOffAnimation()
- override fun shouldPlayAnimation(): Boolean =
- shouldPlayUnlockedScreenOffAnimation()
+ override fun shouldPlayAnimation(): Boolean = shouldPlayUnlockedScreenOffAnimation()
/**
* Whether the light reveal animation is playing. The second part of the screen off animation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 60b8599..b085d80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -301,7 +301,7 @@
.flatMapLatest { it.networkName }
.logDiffsForTable(
tableLogBuffer,
- columnPrefix = "",
+ columnPrefix = "intent",
initialValue = activeRepo.value.networkName.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
@@ -311,7 +311,7 @@
.flatMapLatest { it.carrierName }
.logDiffsForTable(
tableLogBuffer,
- columnPrefix = "",
+ columnPrefix = "sub",
initialValue = activeRepo.value.carrierName.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
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 f01ac0e..5ab2ae8 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
@@ -358,7 +358,13 @@
}
.stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId)
- /** BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here */
+ /**
+ * BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here. Note that we
+ * now use the [SharingStarted.Eagerly] strategy, because there have been cases where the sticky
+ * broadcast does not represent the correct state.
+ *
+ * See b/322432056 for context.
+ */
@SuppressLint("RegisterReceiverViaContext")
override val networkName: StateFlow<NetworkNameModel> =
conflatedCallbackFlow {
@@ -388,7 +394,7 @@
awaitClose { context.unregisterReceiver(receiver) }
}
.flowOn(bgDispatcher)
- .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+ .stateIn(scope, SharingStarted.Eagerly, defaultNetworkName)
override val dataEnabled = run {
val initial = telephonyManager.isDataConnectionAllowed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 50de3cb..20a82a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -39,6 +39,7 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.settings.GlobalSettings;
@@ -162,11 +163,7 @@
*/
@Override
public void showNotification(@NonNull NotificationEntry entry) {
- HeadsUpEntry headsUpEntry = createHeadsUpEntry();
-
- // Attach NotificationEntry for AvalancheController to log key and
- // record mPostTime for AvalancheController sorting
- headsUpEntry.setEntry(entry);
+ HeadsUpEntry headsUpEntry = createHeadsUpEntry(entry);
Runnable runnable = () -> {
// TODO(b/315362456) log outside runnable too
@@ -175,6 +172,7 @@
// Add new entry and begin managing it
mHeadsUpEntryMap.put(entry.getKey(), headsUpEntry);
onEntryAdded(headsUpEntry);
+ // TODO(b/328390331) move accessibility events to the view layer
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
entry.setIsHeadsUpEntry(true);
@@ -235,7 +233,7 @@
// with the groupmanager
return;
}
-
+ // TODO(b/328390331) move accessibility events to the view layer
headsUpEntry.mEntry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
if (shouldHeadsUpAgain) {
@@ -335,15 +333,15 @@
if (!isPinned) {
headsUpEntry.mWasUnpinned = true;
}
- if (headsUpEntry.isPinned() != isPinned) {
- headsUpEntry.setPinned(isPinned);
+ if (headsUpEntry.isRowPinned() != isPinned) {
+ headsUpEntry.setRowPinned(isPinned);
updatePinnedMode();
if (isPinned && entry.getSbn() != null) {
mUiEventLogger.logWithInstanceId(
NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(),
entry.getSbn().getPackageName(), entry.getSbn().getInstanceId());
}
- // TODO(b/325936094) convert these listeners to collecting a flow
+ // TODO(b/325936094) use the isPinned Flow instead
for (OnHeadsUpChangedListener listener : mListeners) {
if (isPinned) {
listener.onHeadsUpPinned(entry);
@@ -362,7 +360,7 @@
* Manager-specific logic that should occur when an entry is added.
* @param headsUpEntry entry added
*/
- void onEntryAdded(HeadsUpEntry headsUpEntry) {
+ protected void onEntryAdded(HeadsUpEntry headsUpEntry) {
NotificationEntry entry = headsUpEntry.mEntry;
entry.setHeadsUp(true);
@@ -375,7 +373,7 @@
}
/**
- * Remove a notification and reset the entry.
+ * Remove a notification from the alerting entries.
* @param key key of notification to remove
*/
protected final void removeEntry(@NonNull String key) {
@@ -394,8 +392,13 @@
entry.demoteStickyHun();
mHeadsUpEntryMap.remove(key);
onEntryRemoved(headsUpEntry);
+ // TODO(b/328390331) move accessibility events to the view layer
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- headsUpEntry.reset();
+ if (NotificationsHeadsUpRefactor.isEnabled()) {
+ headsUpEntry.cancelAutoRemovalCallbacks("removeEntry");
+ } else {
+ headsUpEntry.reset();
+ }
};
mAvalancheController.delete(headsUpEntry, runnable, "removeEntry");
}
@@ -415,7 +418,16 @@
}
}
- private void updatePinnedMode() {
+ /**
+ * Manager-specific logic, that should occur, when the entry is updated, and its posted time has
+ * changed.
+ *
+ * @param headsUpEntry entry updated
+ */
+ protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
+ }
+
+ protected void updatePinnedMode() {
boolean hasPinnedNotification = hasPinnedNotificationInternal();
if (hasPinnedNotification == mHasPinnedNotification) {
return;
@@ -470,7 +482,7 @@
@Nullable
protected HeadsUpEntry getHeadsUpEntry(@NonNull String key) {
// TODO(b/315362456) See if callers need to check AvalancheController
- return (HeadsUpEntry) mHeadsUpEntryMap.get(key);
+ return mHeadsUpEntryMap.get(key);
}
/**
@@ -490,7 +502,7 @@
HeadsUpEntry topEntry = null;
for (HeadsUpEntry entry: mHeadsUpEntryMap.values()) {
if (topEntry == null || entry.compareTo(topEntry) < 0) {
- topEntry = (HeadsUpEntry) entry;
+ topEntry = entry;
}
}
return topEntry;
@@ -657,8 +669,8 @@
}
@NonNull
- protected HeadsUpEntry createHeadsUpEntry() {
- return new HeadsUpEntry();
+ protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
+ return new HeadsUpEntry(entry);
}
/**
@@ -694,11 +706,23 @@
@Nullable private Runnable mCancelRemoveRunnable;
- public void setEntry(@NonNull final NotificationEntry entry) {
- setEntry(entry, () -> removeEntry(entry.getKey()));
+ public HeadsUpEntry() {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
}
- public void setEntry(@NonNull final NotificationEntry entry,
+ public HeadsUpEntry(NotificationEntry entry) {
+ // Attach NotificationEntry for AvalancheController to log key and
+ // record mPostTime for AvalancheController sorting
+ setEntry(entry, createRemoveRunnable(entry));
+ }
+
+ /** Attach a NotificationEntry. */
+ public void setEntry(@NonNull final NotificationEntry entry) {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
+ setEntry(entry, createRemoveRunnable(entry));
+ }
+
+ private void setEntry(@NonNull final NotificationEntry entry,
@Nullable Runnable removeRunnable) {
mEntry = entry;
mRemoveRunnable = removeRunnable;
@@ -707,11 +731,11 @@
updateEntry(true /* updatePostTime */, "setEntry");
}
- public boolean isPinned() {
+ protected boolean isRowPinned() {
return mEntry != null && mEntry.isRowPinned();
}
- public void setPinned(boolean pinned) {
+ protected void setRowPinned(boolean pinned) {
if (mEntry != null) mEntry.setRowPinned(pinned);
}
@@ -751,6 +775,9 @@
return timeLeft;
};
scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");
+
+ // Notify the manager, that the posted time has changed.
+ onEntryUpdated(this);
}
/**
@@ -847,6 +874,7 @@
}
public void reset() {
+ NotificationsHeadsUpRefactor.assertInLegacyMode();
cancelAutoRemovalCallbacks("reset()");
mEntry = null;
mRemoveRunnable = null;
@@ -919,6 +947,11 @@
}
}
+ /** Creates a runnable to remove this notification from the alerting entries. */
+ protected Runnable createRemoveRunnable(NotificationEntry entry) {
+ return () -> removeEntry(entry.getKey());
+ }
+
/**
* Calculate what the post time of a notification is at some current time.
* @return the post time
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
index 420701f..52a2e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
@@ -196,6 +196,7 @@
* Called when a heads up notification is 'going away' or no longer 'going away'. See
* [HeadsUpManager.setHeadsUpGoingAway].
*/
+ // TODO(b/325936094) delete this callback, and listen to the flow instead
fun onHeadsUpGoingAwayStateChanged(headsUpGoingAway: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
index 087e100..7a57027 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
@@ -42,6 +42,10 @@
import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileDataInteractor
import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.qs.tiles.impl.work.domain.interactor.WorkModeTileDataInteractor
+import com.android.systemui.qs.tiles.impl.work.domain.interactor.WorkModeTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.qs.tiles.impl.work.ui.WorkModeTileMapper
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
@@ -69,6 +73,7 @@
const val LOCATION_TILE_SPEC = "location"
const val ALARM_TILE_SPEC = "alarm"
const val UIMODENIGHT_TILE_SPEC = "dark"
+ const val WORK_MODE_TILE_SPEC = "work"
/** Inject flashlight config */
@Provides
@@ -197,6 +202,38 @@
stateInteractor,
mapper,
)
+
+ /** Inject work mode tile config */
+ @Provides
+ @IntoMap
+ @StringKey(WORK_MODE_TILE_SPEC)
+ fun provideWorkModeTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(WORK_MODE_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = com.android.internal.R.drawable.stat_sys_managed_profile_status,
+ labelRes = R.string.quick_settings_work_mode_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject work mode into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(WORK_MODE_TILE_SPEC)
+ fun provideWorkModeTileViewModel(
+ factory: QSTileViewModelFactory.Static<WorkModeTileModel>,
+ mapper: WorkModeTileMapper,
+ stateInteractor: WorkModeTileDataInteractor,
+ userActionInteractor: WorkModeTileUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(WORK_MODE_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
}
/** Inject FlashlightTile into tileMap in QSModule */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 18ec68b..068e0a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import static android.permission.flags.Flags.sensitiveNotificationAppProtection;
import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
import static com.android.server.notification.Flags.screenshareNotificationHiding;
@@ -23,6 +24,7 @@
import android.annotation.MainThread;
import android.app.IActivityManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.ExecutorContentObserver;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
@@ -33,7 +35,11 @@
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -42,6 +48,7 @@
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.settings.GlobalSettings;
+import java.util.Random;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -52,11 +59,29 @@
implements SensitiveNotificationProtectionController {
private static final String LOG_TAG = "SNPC";
private final SensitiveNotificationProtectionControllerLogger mLogger;
+ private final PackageManager mPackageManager;
private final ArraySet<String> mExemptPackages = new ArraySet<>();
private final ListenerSet<Runnable> mListeners = new ListenerSet<>();
private volatile MediaProjectionInfo mProjection;
+ private SensitiveNotificatioMediaProjectionSession mActiveMediaProjectionSession;
boolean mDisableScreenShareProtections = false;
+
+ private static class SensitiveNotificatioMediaProjectionSession {
+ final long mSessionId;
+ final int mProjectionAppUid;
+ final boolean mExempt;
+
+ SensitiveNotificatioMediaProjectionSession(
+ long sessionId,
+ int projectionAppUid,
+ boolean exempt) {
+ this.mSessionId = sessionId;
+ this.mProjectionAppUid = projectionAppUid;
+ this.mExempt = exempt;
+ }
+ }
+
@VisibleForTesting
final MediaProjectionManager.Callback mMediaProjectionCallback =
new MediaProjectionManager.Callback() {
@@ -64,18 +89,20 @@
public void onStart(MediaProjectionInfo info) {
Trace.beginSection("SNPC.onProjectionStart");
try {
- if (mDisableScreenShareProtections) {
- Log.w(LOG_TAG,
- "Screen share protections disabled, ignoring projectionstart");
- mLogger.logProjectionStart(false, info.getPackageName());
- return;
- }
-
- // Only enable sensitive content protection if sharing full screen
- // Launch cookie only set (non-null) if sharing single app/task
- updateProjectionStateAndNotifyListeners(
- (info.getLaunchCookie() == null) ? info : null);
+ updateProjectionStateAndNotifyListeners(info);
mLogger.logProjectionStart(isSensitiveStateActive(), info.getPackageName());
+
+ int packageUid;
+ try {
+ packageUid = mPackageManager.getPackageUid(info.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(LOG_TAG, "Package " + info.getPackageName() + " not found");
+ packageUid = -1;
+ }
+ // TODO(b/329665707): MediaProjectionSessionIdGenerator instead of random
+ // long
+ logSensitiveContentProtectionSessionStart(
+ new Random().nextLong(), packageUid, !isSensitiveStateActive());
} finally {
Trace.endSection();
}
@@ -86,6 +113,7 @@
Trace.beginSection("SNPC.onProjectionStop");
try {
mLogger.logProjectionStop();
+ logSensitiveContentProtectionSessionStop();
updateProjectionStateAndNotifyListeners(null);
} finally {
Trace.endSection();
@@ -93,16 +121,48 @@
}
};
+ private void logSensitiveContentProtectionSessionStart(
+ long sessionId, int projectionAppUid, boolean exempt) {
+ mActiveMediaProjectionSession =
+ new SensitiveNotificatioMediaProjectionSession(sessionId, projectionAppUid, exempt);
+ logSensitiveContentProtectionSession(
+ mActiveMediaProjectionSession,
+ FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START);
+ }
+
+ private void logSensitiveContentProtectionSessionStop() {
+ if (mActiveMediaProjectionSession == null) {
+ return;
+ }
+ logSensitiveContentProtectionSession(
+ mActiveMediaProjectionSession,
+ FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP);
+ mActiveMediaProjectionSession = null;
+ }
+
+ private void logSensitiveContentProtectionSession(
+ SensitiveNotificatioMediaProjectionSession session, int state) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION,
+ session.mSessionId,
+ session.mProjectionAppUid,
+ session.mExempt,
+ state,
+ FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI);
+ }
+
@Inject
public SensitiveNotificationProtectionControllerImpl(
Context context,
GlobalSettings settings,
MediaProjectionManager mediaProjectionManager,
IActivityManager activityManager,
+ PackageManager packageManager,
@Main Handler mainHandler,
@Background Executor bgExecutor,
SensitiveNotificationProtectionControllerLogger logger) {
mLogger = logger;
+ mPackageManager = packageManager;
if (!screenshareNotificationHiding()) {
return;
@@ -168,7 +228,7 @@
mExemptPackages.addAll(exemptPackages);
if (mProjection != null) {
- mListeners.forEach(Runnable::run);
+ updateProjectionStateAndNotifyListeners(mProjection);
}
}
@@ -177,13 +237,13 @@
* listeners
*/
@MainThread
- private void updateProjectionStateAndNotifyListeners(MediaProjectionInfo info) {
+ private void updateProjectionStateAndNotifyListeners(@Nullable MediaProjectionInfo info) {
Assert.isMainThread();
// capture previous state
boolean wasSensitive = isSensitiveStateActive();
// update internal state
- mProjection = info;
+ mProjection = getNonExemptProjectionInfo(info);
// if either previous or new state is sensitive, notify listeners.
if (wasSensitive || isSensitiveStateActive()) {
@@ -191,6 +251,36 @@
}
}
+ private MediaProjectionInfo getNonExemptProjectionInfo(@Nullable MediaProjectionInfo info) {
+ if (mDisableScreenShareProtections) {
+ Log.w(LOG_TAG, "Screen share protections disabled");
+ return null;
+ } else if (info != null && mExemptPackages.contains(info.getPackageName())) {
+ Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName());
+ return null;
+ } else if (info != null && canRecordSensitiveContent(info.getPackageName())) {
+ Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName()
+ + " via permission");
+ return null;
+ } else if (info != null && info.getLaunchCookie() != null) {
+ // Only enable sensitive content protection if sharing full screen
+ // Launch cookie only set (non-null) if sharing single app/task
+ Log.w(LOG_TAG, "Screen share protections exempt for single app screenshare");
+ return null;
+ }
+ return info;
+ }
+
+ private boolean canRecordSensitiveContent(@NonNull String packageName) {
+ // RECORD_SENSITIVE_CONTENT is flagged api on sensitiveNotificationAppProtection
+ if (sensitiveNotificationAppProtection()) {
+ return mPackageManager.checkPermission(
+ android.Manifest.permission.RECORD_SENSITIVE_CONTENT, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+ return false;
+ }
+
@Override
public void registerSensitiveStateListener(Runnable onSensitiveStateChanged) {
mListeners.addIfAbsent(onSensitiveStateChanged);
@@ -201,15 +291,9 @@
mListeners.remove(onSensitiveStateChanged);
}
- // TODO(b/323396693): opportunity for optimization
@Override
public boolean isSensitiveStateActive() {
- MediaProjectionInfo projection = mProjection;
- if (projection == null) {
- return false;
- }
-
- return !mExemptPackages.contains(projection.getPackageName());
+ return mProjection != null;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/DisposableHandles.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/DisposableHandles.kt
new file mode 100644
index 0000000..de036ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/DisposableHandles.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.util.kotlin
+
+import kotlinx.coroutines.DisposableHandle
+
+/** A mutable collection of [DisposableHandle] objects that is itself a [DisposableHandle] */
+class DisposableHandles : DisposableHandle {
+ private val handles = mutableListOf<DisposableHandle>()
+
+ /** Add the provided handles to this collection. */
+ fun add(vararg handles: DisposableHandle) {
+ this.handles.addAll(handles)
+ }
+
+ /** Same as [add] */
+ operator fun plusAssign(handle: DisposableHandle) {
+ this.handles.add(handle)
+ }
+
+ /** Same as [add] */
+ operator fun plusAssign(handles: Iterable<DisposableHandle>) {
+ this.handles.addAll(handles)
+ }
+
+ /** [dispose] the current contents, then [add] the provided [handles] */
+ fun replaceAll(vararg handles: DisposableHandle) {
+ dispose()
+ add(*handles)
+ }
+
+ /** Dispose of all added handles and empty this collection. */
+ override fun dispose() {
+ handles.forEach { it.dispose() }
+ handles.clear()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt
new file mode 100644
index 0000000..7a2f9b2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/ManagedProfileControllerExt.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.util.kotlin
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.phone.ManagedProfileController
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+val ManagedProfileController.hasActiveWorkProfile: Flow<Boolean>
+ get() = conflatedCallbackFlow {
+ val callback =
+ object : ManagedProfileController.Callback {
+ override fun onManagedProfileChanged() {
+ trySend(hasActiveProfile())
+ }
+ override fun onManagedProfileRemoved() {
+ // no-op, because the other callback will also be called.
+ }
+ }
+ addCallback(callback) // calls onManagedProfileChanged
+ awaitClose { removeCallback(callback) }
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
index d134e60..155102c9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/MediaDevicesModule.kt
@@ -21,7 +21,6 @@
import com.android.settingslib.volume.data.repository.LocalMediaRepository
import com.android.settingslib.volume.data.repository.MediaControllerRepository
import com.android.settingslib.volume.data.repository.MediaControllerRepositoryImpl
-import com.android.settingslib.volume.domain.interactor.LocalMediaInteractor
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -52,13 +51,6 @@
@Provides
@SysUISingleton
- fun provideLocalMediaInteractor(
- repository: LocalMediaRepository,
- @Application scope: CoroutineScope,
- ): LocalMediaInteractor = LocalMediaInteractor(repository, scope)
-
- @Provides
- @SysUISingleton
fun provideMediaDeviceSessionRepository(
intentsReceiver: AudioManagerEventsReceiver,
mediaSessionManager: MediaSessionManager,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
index 46ea382..0207d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
@@ -36,11 +36,10 @@
}
fun onSettingsClicked() {
- volumePanelViewModel.dismissPanel()
activityStarter.startActivity(
Intent(Settings.ACTION_SOUND_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
true,
- )
+ ) { volumePanelViewModel.dismissPanel() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/data/repository/LocalMediaRepositoryFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/data/repository/LocalMediaRepositoryFactory.kt
index 11b4690..e052f24 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/data/repository/LocalMediaRepositoryFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/data/repository/LocalMediaRepositoryFactory.kt
@@ -15,15 +15,12 @@
*/
package com.android.systemui.volume.panel.component.mediaoutput.data.repository
-import android.media.MediaRouter2Manager
import com.android.settingslib.volume.data.repository.LocalMediaRepository
import com.android.settingslib.volume.data.repository.LocalMediaRepositoryImpl
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.media.controls.util.LocalMediaManagerFactory
import javax.inject.Inject
-import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
interface LocalMediaRepositoryFactory {
@@ -35,18 +32,14 @@
@Inject
constructor(
private val eventsReceiver: AudioManagerEventsReceiver,
- private val mediaRouter2Manager: MediaRouter2Manager,
private val localMediaManagerFactory: LocalMediaManagerFactory,
@Application private val coroutineScope: CoroutineScope,
- @Background private val backgroundCoroutineContext: CoroutineContext,
) : LocalMediaRepositoryFactory {
override fun create(packageName: String?): LocalMediaRepository =
LocalMediaRepositoryImpl(
eventsReceiver,
localMediaManagerFactory.create(packageName),
- mediaRouter2Manager,
coroutineScope,
- backgroundCoroutineContext,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
new file mode 100644
index 0000000..b0c8a4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.volume.panel.component.mediaoutput.domain.interactor
+
+import android.media.session.MediaController
+import android.media.session.PlaybackState
+import android.os.Handler
+import com.android.settingslib.volume.data.repository.MediaControllerChange
+import com.android.settingslib.volume.data.repository.MediaControllerRepository
+import com.android.settingslib.volume.data.repository.stateChanges
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.FlowCollector
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Allows to observe and change [MediaDeviceSession] state. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@VolumePanelScope
+class MediaDeviceSessionInteractor
+@Inject
+constructor(
+ @Background private val backgroundCoroutineContext: CoroutineContext,
+ @Background private val backgroundHandler: Handler,
+ private val mediaControllerRepository: MediaControllerRepository,
+) {
+
+ /** [PlaybackState] changes for the [MediaDeviceSession]. */
+ fun playbackState(session: MediaDeviceSession): Flow<PlaybackState?> {
+ return stateChanges(session) {
+ emit(MediaControllerChange.PlaybackStateChanged(it.playbackState))
+ }
+ .filterIsInstance(MediaControllerChange.PlaybackStateChanged::class)
+ .map { it.state }
+ }
+
+ /** [MediaController.PlaybackInfo] changes for the [MediaDeviceSession]. */
+ fun playbackInfo(session: MediaDeviceSession): Flow<MediaController.PlaybackInfo?> {
+ return stateChanges(session) {
+ emit(MediaControllerChange.AudioInfoChanged(it.playbackInfo))
+ }
+ .filterIsInstance(MediaControllerChange.AudioInfoChanged::class)
+ .map { it.info }
+ }
+
+ private fun stateChanges(
+ session: MediaDeviceSession,
+ onStart: suspend FlowCollector<MediaControllerChange>.(controller: MediaController) -> Unit,
+ ): Flow<MediaControllerChange?> =
+ mediaControllerRepository.activeSessions
+ .flatMapLatest { controllers ->
+ val controller: MediaController =
+ findControllerForSession(controllers, session)
+ ?: return@flatMapLatest flowOf(null)
+ controller.stateChanges(backgroundHandler).onStart { onStart(controller) }
+ }
+ .flowOn(backgroundCoroutineContext)
+
+ /** Set [MediaDeviceSession] volume to [volume]. */
+ suspend fun setSessionVolume(mediaDeviceSession: MediaDeviceSession, volume: Int): Boolean {
+ if (!mediaDeviceSession.canAdjustVolume) {
+ return false
+ }
+ return withContext(backgroundCoroutineContext) {
+ val controller =
+ findControllerForSession(
+ mediaControllerRepository.activeSessions.value,
+ mediaDeviceSession,
+ )
+ if (controller == null) {
+ false
+ } else {
+ controller.setVolumeTo(volume, 0)
+ true
+ }
+ }
+ }
+
+ private fun findControllerForSession(
+ controllers: Collection<MediaController>,
+ mediaDeviceSession: MediaDeviceSession,
+ ): MediaController? =
+ controllers.firstOrNull { it.sessionToken == mediaDeviceSession.sessionToken }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
index cb16abe..ea4c082 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputActionsInteractor.kt
@@ -33,23 +33,15 @@
private val mediaOutputDialogManager: MediaOutputDialogManager,
) {
- fun onBarClick(session: MediaDeviceSession, expandable: Expandable) {
- when (session) {
- is MediaDeviceSession.Active -> {
- mediaOutputDialogManager.createAndShowWithController(
- session.packageName,
- false,
- expandable.dialogController()
- )
- }
- is MediaDeviceSession.Inactive -> {
- mediaOutputDialogManager.createAndShowForSystemRouting(
- expandable.dialogController()
- )
- }
- else -> {
- /* do nothing */
- }
+ fun onBarClick(session: MediaDeviceSession, isPlaybackActive: Boolean, expandable: Expandable) {
+ if (isPlaybackActive) {
+ mediaOutputDialogManager.createAndShowWithController(
+ session.packageName,
+ false,
+ expandable.dialogController()
+ )
+ } else {
+ mediaOutputDialogManager.createAndShowForSystemRouting(expandable.dialogController())
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index 0f53437..e60139e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -17,17 +17,16 @@
package com.android.systemui.volume.panel.component.mediaoutput.domain.interactor
import android.content.pm.PackageManager
+import android.media.VolumeProvider
import android.media.session.MediaController
-import android.os.Handler
import android.util.Log
import com.android.settingslib.media.MediaDevice
import com.android.settingslib.volume.data.repository.LocalMediaRepository
-import com.android.settingslib.volume.data.repository.MediaControllerChange
import com.android.settingslib.volume.data.repository.MediaControllerRepository
-import com.android.settingslib.volume.data.repository.stateChanges
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -38,12 +37,9 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -58,35 +54,40 @@
private val packageManager: PackageManager,
@VolumePanelScope private val coroutineScope: CoroutineScope,
@Background private val backgroundCoroutineContext: CoroutineContext,
- @Background private val backgroundHandler: Handler,
- mediaControllerRepository: MediaControllerRepository
+ mediaControllerRepository: MediaControllerRepository,
) {
- /** Current [MediaDeviceSession]. Emits when the session playback changes. */
- val mediaDeviceSession: StateFlow<MediaDeviceSession> =
- mediaControllerRepository.activeLocalMediaController
- .flatMapLatest { it?.mediaDeviceSession() ?: flowOf(MediaDeviceSession.Inactive) }
- .flowOn(backgroundCoroutineContext)
- .stateIn(coroutineScope, SharingStarted.Eagerly, MediaDeviceSession.Inactive)
+ private val activeMediaControllers: Flow<MediaControllers> =
+ mediaControllerRepository.activeSessions
+ .map { getMediaControllers(it) }
+ .shareIn(coroutineScope, SharingStarted.Eagerly, replay = 1)
- private fun MediaController.mediaDeviceSession(): Flow<MediaDeviceSession> {
- return stateChanges(backgroundHandler)
- .onStart { emit(MediaControllerChange.PlaybackStateChanged(playbackState)) }
- .filterIsInstance<MediaControllerChange.PlaybackStateChanged>()
+ /** [MediaDeviceSessions] that contains currently active sessions. */
+ val activeMediaDeviceSessions: Flow<MediaDeviceSessions> =
+ activeMediaControllers.map {
+ MediaDeviceSessions(
+ local = it.local?.mediaDeviceSession(),
+ remote = it.remote?.mediaDeviceSession()
+ )
+ }
+
+ /** Returns the default [MediaDeviceSession] from [activeMediaDeviceSessions] */
+ val defaultActiveMediaSession: StateFlow<MediaDeviceSession?> =
+ activeMediaControllers
.map {
- MediaDeviceSession.Active(
- appLabel = getApplicationLabel(packageName)
- ?: return@map MediaDeviceSession.Inactive,
- packageName = packageName,
- sessionToken = sessionToken,
- playbackState = playbackState,
- )
+ when {
+ it.local?.playbackState?.isActive == true -> it.local.mediaDeviceSession()
+ it.remote?.playbackState?.isActive == true -> it.remote.mediaDeviceSession()
+ it.local != null -> it.local.mediaDeviceSession()
+ else -> null
+ }
}
- }
+ .flowOn(backgroundCoroutineContext)
+ .stateIn(coroutineScope, SharingStarted.Eagerly, null)
private val localMediaRepository: SharedFlow<LocalMediaRepository> =
- mediaDeviceSession
- .map { (it as? MediaDeviceSession.Active)?.packageName }
+ defaultActiveMediaSession
+ .map { it?.packageName }
.distinctUntilChanged()
.map { localMediaRepositoryFactory.create(it) }
.shareIn(coroutineScope, SharingStarted.Eagerly, replay = 1)
@@ -111,6 +112,54 @@
}
}
+ /** Finds local and remote media controllers. */
+ private fun getMediaControllers(
+ controllers: Collection<MediaController>,
+ ): MediaControllers {
+ var localController: MediaController? = null
+ var remoteController: MediaController? = null
+ val remoteMediaSessions: MutableSet<String> = mutableSetOf()
+ for (controller in controllers) {
+ val playbackInfo: MediaController.PlaybackInfo = controller.playbackInfo ?: continue
+ when (playbackInfo.playbackType) {
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE -> {
+ // MediaController can't be local if there is a remote one for the same package
+ if (localController?.packageName.equals(controller.packageName)) {
+ localController = null
+ }
+ if (!remoteMediaSessions.contains(controller.packageName)) {
+ remoteMediaSessions.add(controller.packageName)
+ if (remoteController == null) {
+ remoteController = controller
+ }
+ }
+ }
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL -> {
+ if (controller.packageName in remoteMediaSessions) continue
+ if (localController != null) continue
+ localController = controller
+ }
+ }
+ }
+ return MediaControllers(local = localController, remote = remoteController)
+ }
+
+ private suspend fun MediaController.mediaDeviceSession(): MediaDeviceSession? {
+ return MediaDeviceSession(
+ packageName = packageName,
+ sessionToken = sessionToken,
+ canAdjustVolume =
+ playbackInfo != null &&
+ playbackInfo?.volumeControl != VolumeProvider.VOLUME_CONTROL_FIXED,
+ appLabel = getApplicationLabel(packageName) ?: return null
+ )
+ }
+
+ private data class MediaControllers(
+ val local: MediaController?,
+ val remote: MediaController?,
+ )
+
private companion object {
const val TAG = "MediaOutputInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt
index 1bceee9..2a2ce79 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSession.kt
@@ -17,26 +17,15 @@
package com.android.systemui.volume.panel.component.mediaoutput.domain.model
import android.media.session.MediaSession
-import android.media.session.PlaybackState
/** Represents media playing on the connected device. */
-sealed interface MediaDeviceSession {
+data class MediaDeviceSession(
+ val appLabel: CharSequence,
+ val packageName: String,
+ val sessionToken: MediaSession.Token,
+ val canAdjustVolume: Boolean,
+)
- /** Media is playing. */
- data class Active(
- val appLabel: CharSequence,
- val packageName: String,
- val sessionToken: MediaSession.Token,
- val playbackState: PlaybackState?,
- ) : MediaDeviceSession
-
- /** Media is not playing. */
- data object Inactive : MediaDeviceSession
-
- /** Current media state is unknown yet. */
- data object Unknown : MediaDeviceSession
-}
-
-/** Returns true when the audio is playing for the [MediaDeviceSession]. */
-fun MediaDeviceSession.isPlaying(): Boolean =
- this is MediaDeviceSession.Active && playbackState?.isActive == true
+/** Returns true when [other] controls the same sessions as [this]. */
+fun MediaDeviceSession.isTheSameSession(other: MediaDeviceSession?): Boolean =
+ sessionToken == other?.sessionToken
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt
new file mode 100644
index 0000000..ddc0784
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaDeviceSessions.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.volume.panel.component.mediaoutput.domain.model
+
+/** Models a pair of local and remote [MediaDeviceSession]s. */
+data class MediaDeviceSessions(
+ val local: MediaDeviceSession?,
+ val remote: MediaDeviceSession?,
+) {
+
+ companion object {
+ /** Returns [MediaDeviceSessions.local]. */
+ val Local: (MediaDeviceSessions) -> MediaDeviceSession? = { it.local }
+ /** Returns [MediaDeviceSessions.remote]. */
+ val Remote: (MediaDeviceSessions) -> MediaDeviceSession? = { it.remote }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
index d49cb1e..2530a3a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
@@ -17,24 +17,30 @@
package com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel
import android.content.Context
+import android.media.session.PlaybackState
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Color
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputActionsInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.isPlaying
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Models the UI of the Media Output Volume Panel component. */
+@OptIn(ExperimentalCoroutinesApi::class)
@VolumePanelScope
class MediaOutputViewModel
@Inject
@@ -43,25 +49,36 @@
@VolumePanelScope private val coroutineScope: CoroutineScope,
private val volumePanelViewModel: VolumePanelViewModel,
private val actionsInteractor: MediaOutputActionsInteractor,
+ private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
interactor: MediaOutputInteractor,
) {
- private val mediaDeviceSession: StateFlow<MediaDeviceSession> =
- interactor.mediaDeviceSession.stateIn(
- coroutineScope,
- SharingStarted.Eagerly,
- MediaDeviceSession.Unknown,
- )
+ private val sessionWithPlayback: StateFlow<SessionWithPlayback?> =
+ interactor.defaultActiveMediaSession
+ .flatMapLatest { session ->
+ if (session == null) {
+ flowOf(null)
+ } else {
+ mediaDeviceSessionInteractor.playbackState(session).map { playback ->
+ playback?.let { SessionWithPlayback(session, it) }
+ }
+ }
+ }
+ .stateIn(
+ coroutineScope,
+ SharingStarted.Eagerly,
+ null,
+ )
val connectedDeviceViewModel: StateFlow<ConnectedDeviceViewModel?> =
- combine(mediaDeviceSession, interactor.currentConnectedDevice) {
+ combine(sessionWithPlayback, interactor.currentConnectedDevice) {
mediaDeviceSession,
currentConnectedDevice ->
ConnectedDeviceViewModel(
- if (mediaDeviceSession.isPlaying()) {
+ if (mediaDeviceSession?.playback?.isActive == true) {
context.getString(
R.string.media_output_label_title,
- (mediaDeviceSession as MediaDeviceSession.Active).appLabel
+ mediaDeviceSession.session.appLabel
)
} else {
context.getString(R.string.media_output_title_without_playing)
@@ -76,10 +93,10 @@
)
val deviceIconViewModel: StateFlow<DeviceIconViewModel?> =
- combine(mediaDeviceSession, interactor.currentConnectedDevice) {
+ combine(sessionWithPlayback, interactor.currentConnectedDevice) {
mediaDeviceSession,
currentConnectedDevice ->
- if (mediaDeviceSession.isPlaying()) {
+ if (mediaDeviceSession?.playback?.isActive == true) {
val icon =
currentConnectedDevice?.icon?.let { Icon.Loaded(it, null) }
?: Icon.Resource(
@@ -112,7 +129,14 @@
)
fun onBarClick(expandable: Expandable) {
- actionsInteractor.onBarClick(mediaDeviceSession.value, expandable)
+ sessionWithPlayback.value?.let {
+ actionsInteractor.onBarClick(it.session, it.playback.isActive, expandable)
+ }
volumePanelViewModel.dismissPanel()
}
+
+ private data class SessionWithPlayback(
+ val session: MediaDeviceSession,
+ val playback: PlaybackState,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
index 30715d1..ceb769e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
@@ -50,13 +50,17 @@
val spatialAudioButton: StateFlow<ButtonViewModel?> =
interactor.isEnabled
- .map { it.toViewModel(true).toButtonViewModel() }
+ .map {
+ it.toViewModel(true)
+ .toButtonViewModel()
+ .copy(label = context.getString(R.string.volume_panel_spatial_audio_title))
+ }
.stateIn(scope, SharingStarted.Eagerly, null)
val isAvailable: StateFlow<Boolean> =
availabilityCriteria.isAvailable().stateIn(scope, SharingStarted.Eagerly, true)
- val spatialAudioButtonByEnabled: StateFlow<List<SpatialAudioButtonViewModel>> =
+ val spatialAudioButtons: StateFlow<List<SpatialAudioButtonViewModel>> =
combine(interactor.isEnabled, interactor.isAvailable) { currentIsEnabled, isAvailable ->
SpatialAudioEnabledModel.values
.filter {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/CastVolumeInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/CastVolumeInteractor.kt
deleted file mode 100644
index 6b62074..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/CastVolumeInteractor.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.volume.panel.component.volume.domain.interactor
-
-import com.android.settingslib.volume.domain.interactor.LocalMediaInteractor
-import com.android.settingslib.volume.domain.model.RoutingSession
-import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
-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
-
-/** Provides a remote media casting state. */
-@VolumePanelScope
-class CastVolumeInteractor
-@Inject
-constructor(
- @VolumePanelScope private val coroutineScope: CoroutineScope,
- private val localMediaInteractor: LocalMediaInteractor,
-) {
-
- /** Returns a list of [RoutingSession] to show in the UI. */
- val remoteRoutingSessions: StateFlow<List<RoutingSession>> =
- localMediaInteractor.remoteRoutingSessions
- .map { it.filter { routingSession -> routingSession.isVolumeSeekBarEnabled } }
- .stateIn(coroutineScope, SharingStarted.Eagerly, emptyList())
-
- /** Sets [routingSession] volume to [volume]. */
- suspend fun setVolume(routingSession: RoutingSession, volume: Int) {
- localMediaInteractor.adjustSessionVolume(routingSession.routingSessionInfo.id, volume)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index 1b73208..3242c28 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -80,7 +80,7 @@
) { model, isEnabled, ringerMode ->
model.toState(isEnabled, ringerMode)
}
- .stateIn(coroutineScope, SharingStarted.Eagerly, EmptyState)
+ .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
override fun onValueChanged(state: SliderState, newValue: Float) {
val audioViewModel = state as? State
@@ -116,6 +116,7 @@
isEnabled = isEnabled,
a11yStep = volumeRange.step,
audioStreamModel = this,
+ isMutable = audioVolumeInteractor.isMutable(audioStream),
)
}
@@ -160,20 +161,10 @@
override val disabledMessage: String?,
override val isEnabled: Boolean,
override val a11yStep: Int,
+ override val isMutable: Boolean,
val audioStreamModel: AudioStreamModel,
) : SliderState
- private data object EmptyState : SliderState {
- override val value: Float = 0f
- override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f
- override val icon: Icon? = null
- override val valueText: String = ""
- override val label: String = ""
- override val disabledMessage: String? = null
- override val a11yStep: Int = 0
- override val isEnabled: Boolean = true
- }
-
@AssistedFactory
interface Factory {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
index 86b2d73..73c8bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
@@ -17,11 +17,11 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.content.Context
-import com.android.settingslib.volume.domain.model.RoutingSession
+import android.media.session.MediaController.PlaybackInfo
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
-import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
-import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -30,30 +30,29 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class CastVolumeSliderViewModel
@AssistedInject
constructor(
- @Assisted private val routingSession: RoutingSession,
+ @Assisted private val session: MediaDeviceSession,
@Assisted private val coroutineScope: CoroutineScope,
private val context: Context,
- mediaOutputInteractor: MediaOutputInteractor,
+ private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val volumeSliderInteractor: VolumeSliderInteractor,
- private val castVolumeInteractor: CastVolumeInteractor,
) : SliderViewModel {
- private val volumeRange = 0..routingSession.routingSessionInfo.volumeMax
-
override val slider: StateFlow<SliderState> =
- combine(mediaOutputInteractor.currentConnectedDevice) { _ -> getCurrentState() }
- .stateIn(coroutineScope, SharingStarted.Eagerly, getCurrentState())
+ mediaDeviceSessionInteractor
+ .playbackInfo(session)
+ .mapNotNull { it?.getCurrentState() }
+ .stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
override fun onValueChanged(state: SliderState, newValue: Float) {
coroutineScope.launch {
- castVolumeInteractor.setVolume(routingSession, newValue.roundToInt())
+ mediaDeviceSessionInteractor.setSessionVolume(session, newValue.roundToInt())
}
}
@@ -61,15 +60,16 @@
// do nothing because this action isn't supported for Cast sliders.
}
- private fun getCurrentState(): State =
- State(
- value = routingSession.routingSessionInfo.volume.toFloat(),
+ private fun PlaybackInfo.getCurrentState(): State {
+ val volumeRange = 0..maxVolume
+ return State(
+ value = currentVolume.toFloat(),
valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
icon = Icon.Resource(R.drawable.ic_cast, null),
valueText =
SliderViewModel.formatValue(
volumeSliderInteractor.processVolumeToValue(
- volume = routingSession.routingSessionInfo.volume,
+ volume = currentVolume,
volumeRange = volumeRange,
)
),
@@ -77,6 +77,7 @@
isEnabled = true,
a11yStep = 1
)
+ }
private data class State(
override val value: Float,
@@ -89,13 +90,15 @@
) : SliderState {
override val disabledMessage: String?
get() = null
+ override val isMutable: Boolean
+ get() = false
}
@AssistedFactory
interface Factory {
fun create(
- routingSession: RoutingSession,
+ session: MediaDeviceSession,
coroutineScope: CoroutineScope,
): CastVolumeSliderViewModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
index b87d0a7..8eb0b89 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
@@ -36,4 +36,17 @@
*/
val a11yStep: Int
val disabledMessage: String?
+ val isMutable: Boolean
+
+ data object Empty : SliderState {
+ override val value: Float = 0f
+ override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f
+ override val icon: Icon? = null
+ override val valueText: String = ""
+ override val label: String = ""
+ override val disabledMessage: String? = null
+ override val a11yStep: Int = 0
+ override val isEnabled: Boolean = true
+ override val isMutable: Boolean = false
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
index aaee24b..4e9a456 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -18,9 +18,10 @@
import android.media.AudioManager
import com.android.settingslib.volume.shared.model.AudioStream
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.model.isPlaying
-import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSession
+import com.android.systemui.volume.panel.component.mediaoutput.domain.model.isTheSameSession
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
@@ -29,17 +30,15 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.combineTransform
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
/**
@@ -52,50 +51,34 @@
@Inject
constructor(
@VolumePanelScope private val scope: CoroutineScope,
- castVolumeInteractor: CastVolumeInteractor,
mediaOutputInteractor: MediaOutputInteractor,
+ private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory,
private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory,
) {
- private val remoteSessionsViewModels: Flow<List<SliderViewModel>> =
- castVolumeInteractor.remoteRoutingSessions.transformLatest { routingSessions ->
- coroutineScope {
- emit(
- routingSessions.map { routingSession ->
- castVolumeSliderViewModelFactory.create(routingSession, this)
- }
- )
- }
- }
- private val streamViewModels: Flow<List<SliderViewModel>> =
- flowOf(
- listOf(
- AudioStream(AudioManager.STREAM_MUSIC),
- AudioStream(AudioManager.STREAM_VOICE_CALL),
- AudioStream(AudioManager.STREAM_RING),
- AudioStream(AudioManager.STREAM_NOTIFICATION),
- AudioStream(AudioManager.STREAM_ALARM),
- )
- )
- .transformLatest { streams ->
- coroutineScope {
- emit(
- streams.map { stream ->
- streamSliderViewModelFactory.create(
- AudioStreamSliderViewModel.FactoryAudioStreamWrapper(stream),
- this,
- )
- }
- )
- }
- }
-
val sliderViewModels: StateFlow<List<SliderViewModel>> =
- combine(remoteSessionsViewModels, streamViewModels) {
- remoteSessionsViewModels,
- streamViewModels ->
- remoteSessionsViewModels + streamViewModels
+ combineTransform(
+ mediaOutputInteractor.activeMediaDeviceSessions,
+ mediaOutputInteractor.defaultActiveMediaSession,
+ ) { activeSessions, defaultSession ->
+ coroutineScope {
+ val viewModels = buildList {
+ if (defaultSession?.isTheSameSession(activeSessions.remote) == true) {
+ addRemoteViewModelIfNeeded(this, activeSessions.remote)
+ addStreamViewModel(this, AudioManager.STREAM_MUSIC)
+ } else {
+ addStreamViewModel(this, AudioManager.STREAM_MUSIC)
+ addRemoteViewModelIfNeeded(this, activeSessions.remote)
+ }
+
+ addStreamViewModel(this, AudioManager.STREAM_VOICE_CALL)
+ addStreamViewModel(this, AudioManager.STREAM_RING)
+ addStreamViewModel(this, AudioManager.STREAM_NOTIFICATION)
+ addStreamViewModel(this, AudioManager.STREAM_ALARM)
+ }
+ emit(viewModels)
+ }
}
.stateIn(scope, SharingStarted.Eagerly, emptyList())
@@ -103,12 +86,41 @@
val isExpanded: StateFlow<Boolean> =
merge(
- mutableIsExpanded.onStart { emit(false) },
- mediaOutputInteractor.mediaDeviceSession.map { !it.isPlaying() },
+ mutableIsExpanded,
+ mediaOutputInteractor.defaultActiveMediaSession.flatMapLatest {
+ if (it == null) flowOf(true)
+ else mediaDeviceSessionInteractor.playbackState(it).map { it?.isActive != true }
+ },
)
.stateIn(scope, SharingStarted.Eagerly, false)
fun onExpandedChanged(isExpanded: Boolean) {
scope.launch { mutableIsExpanded.emit(isExpanded) }
}
+
+ private fun CoroutineScope.addRemoteViewModelIfNeeded(
+ list: MutableList<SliderViewModel>,
+ remoteMediaDeviceSession: MediaDeviceSession?
+ ) {
+ if (remoteMediaDeviceSession?.canAdjustVolume == true) {
+ val viewModel =
+ castVolumeSliderViewModelFactory.create(
+ remoteMediaDeviceSession,
+ this,
+ )
+ list.add(viewModel)
+ }
+ }
+
+ private fun CoroutineScope.addStreamViewModel(
+ list: MutableList<SliderViewModel>,
+ stream: Int,
+ ) {
+ val viewModel =
+ streamSliderViewModelFactory.create(
+ AudioStreamSliderViewModel.FactoryAudioStreamWrapper(AudioStream(stream)),
+ this,
+ )
+ list.add(viewModel)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
index d430e65..c728fef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
@@ -42,7 +42,6 @@
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
-
volumePanelFlag.assertNewVolumePanel()
setContent { VolumePanelRoot(viewModel = viewModel, onDismiss = ::finish) }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 7931fab..e48b639 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -363,8 +363,8 @@
}, mSysUiMainExecutor);
mCommandQueue.addCallback(new CommandQueue.Callbacks() {
@Override
- public void enterDesktop(int displayId) {
- desktopMode.enterDesktop(displayId);
+ public void moveFocusedTaskToDesktop(int displayId) {
+ desktopMode.moveFocusedTaskToDesktop(displayId);
}
@Override
public void moveFocusedTaskToFullscreen(int displayId) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
index b73e4e6..9182e4101 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
@@ -36,6 +36,7 @@
import org.mockito.Mockito.any
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -44,8 +45,8 @@
private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator
private val attachedViews = mutableSetOf<View>()
- val interactionJankMonitor = Kosmos().interactionJankMonitor
- @get:Rule val rule = MockitoJUnit.rule()
+ private val interactionJankMonitor = Kosmos().interactionJankMonitor
+ @get:Rule val rule: MockitoRule = MockitoJUnit.rule()
@Before
fun setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 072569d..33a6010 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -20,6 +20,8 @@
import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import android.hardware.face.FaceSensorPropertiesInternal
@@ -35,6 +37,7 @@
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.ScrollView
+import androidx.constraintlayout.widget.ConstraintLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.InteractionJankMonitor
@@ -82,6 +85,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+
private const val OP_PACKAGE_NAME = "biometric.testapp"
@RunWith(AndroidJUnit4::class)
@@ -386,10 +390,38 @@
}
@Test
+ fun testShowBiometricUI_ContentViewWithMoreOptionsButton() {
+ mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+ var isButtonClicked = false
+ val contentView =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(
+ fakeExecutor) { _, _ -> isButtonClicked = true }
+ .build()
+
+ val container =
+ initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
+
+ waitForIdleSync()
+
+ assertThat(container.hasCredentialView()).isFalse()
+ assertThat(container.hasConstraintBiometricPrompt()).isTrue()
+
+ // TODO(b/328843028): Use button.performClick() instead of calling
+ // onContentViewMoreOptionsButtonPressed() directly, and check |isButtonClicked| is true.
+ container.mBiometricCallback.onContentViewMoreOptionsButtonPressed()
+ waitForIdleSync()
+ // container is gone
+ assertThat(container.mContainerState).isEqualTo(5)
+ }
+
+ @Test
fun testShowCredentialUI_withDescription() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -397,14 +429,44 @@
}
@Test
- @Ignore("b/302735104")
- fun testShowCredentialUI_withCustomBp() {
- mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
- isUsingContentView = true
- )
- checkBpShowsForCredentialAndGoToCredential(container)
+ fun testShowCredentialUI_withVerticalListContentView() {
+ mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ verticalListContentView = PromptVerticalListContentView.Builder().build()
+ )
+ // Two-step credential view should show -
+ // 1. biometric prompt without sensor 2. credential view ui
+ waitForIdleSync()
+ assertThat(container.hasConstraintBiometricPrompt()).isTrue()
+ assertThat(container.hasCredentialView()).isFalse()
+
+ container.animateToCredentialUI(false)
+ waitForIdleSync()
+ // TODO(b/302735104): Check the reason why hasConstraintBiometricPrompt() is still true
+ // assertThat(container.hasConstraintBiometricPrompt()).isFalse()
+ assertThat(container.hasCredentialView()).isTrue()
+ }
+
+ @Test
+ fun testShowCredentialUI_withContentViewWithMoreOptionsButton() {
+ mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+ val contentView =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
+ .build()
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ contentViewWithMoreOptionsButton = contentView
+ )
+ waitForIdleSync()
+
+ assertThat(container.hasCredentialView()).isTrue()
+ assertThat(container.hasBiometricPrompt()).isFalse()
}
@Test
@@ -509,12 +571,13 @@
private fun initializeFingerprintContainer(
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
addToView: Boolean = true,
- isUsingContentView: Boolean = false,
+ verticalListContentView: PromptVerticalListContentView? = null,
+ contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
) = initializeContainer(
TestAuthContainerView(
authenticators = authenticators,
fingerprintProps = fingerprintSensorPropertiesInternal(),
- isUsingContentView = isUsingContentView,
+ verticalListContentView = verticalListContentView,
),
addToView
)
@@ -548,7 +611,8 @@
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
fingerprintProps: List<FingerprintSensorPropertiesInternal> = listOf(),
faceProps: List<FaceSensorPropertiesInternal> = listOf(),
- isUsingContentView: Boolean = false,
+ verticalListContentView: PromptVerticalListContentView? = null,
+ contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
) : AuthContainerView(
Config().apply {
mContext = this@AuthContainerViewTest.context
@@ -558,8 +622,10 @@
mSkipAnimation = true
mPromptInfo = PromptInfo().apply {
this.authenticators = authenticators
- if (isUsingContentView) {
- this.contentView = PromptVerticalListContentView.Builder().build()
+ if (verticalListContentView != null) {
+ this.contentView = verticalListContentView
+ } else if (contentViewWithMoreOptionsButton != null) {
+ this.contentView = contentViewWithMoreOptionsButton
}
}
mOpPackageName = OP_PACKAGE_NAME
@@ -616,19 +682,11 @@
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.systemBars()) == 0).isTrue()
}
-
- private fun checkBpShowsForCredentialAndGoToCredential(container: TestAuthContainerView) {
- waitForIdleSync()
- assertThat(container.hasBiometricPrompt()).isTrue()
- assertThat(container.hasCredentialView()).isFalse()
-
- container.animateToCredentialUI(false)
- waitForIdleSync()
- assertThat(container.hasBiometricPrompt()).isFalse()
- assertThat(container.hasCredentialView()).isTrue()
- }
}
+private fun AuthContainerView.hasConstraintBiometricPrompt() =
+ (findViewById<ConstraintLayout>(R.id.biometric_prompt_constraint_layout)?.childCount ?: 0) > 0
+
private fun AuthContainerView.hasBiometricPrompt() =
(findViewById<ScrollView>(R.id.biometric_scrollview)?.childCount ?: 0) > 0
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
index 81d4e83..df0e5a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
@@ -18,6 +18,7 @@
import android.hardware.biometrics.BiometricManager
import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import androidx.test.filters.SmallTest
@@ -26,8 +27,10 @@
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
@@ -58,6 +61,7 @@
private val testScope = TestScope()
private val faceSettings = FakeFaceSettingsRepository()
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
@Mock private lateinit var authController: AuthController
@@ -135,7 +139,7 @@
}
@Test
- fun showBpWithoutIconForCredential_withCustomBp() =
+ fun showBpWithoutIconForCredential_withVerticalListContentView() =
testScope.runTest {
mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP)
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
@@ -161,8 +165,37 @@
}
@Test
+ fun showBpWithoutIconForCredential_withContentViewWithMoreOptionsButton() =
+ testScope.runTest {
+ mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP)
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+ val promptInfo =
+ PromptInfo().apply {
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ contentView =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
+ .build()
+ }
+ for (case in
+ listOf(
+ PromptKind.Biometric(),
+ PromptKind.Pin,
+ PromptKind.Password,
+ PromptKind.Pattern
+ )) {
+ repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME)
+ repository.setShouldShowBpWithoutIconForCredential(promptInfo)
+
+ assertThat(repository.showBpWithoutIconForCredential.value).isFalse()
+ }
+ }
+
+ @Test
fun showBpWithoutIconForCredential_withDescription() =
testScope.runTest {
+ mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP)
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
for (case in
listOf(
PromptKind.Biometric(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
index 8a46c0c..2172bc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
@@ -1,6 +1,8 @@
package com.android.systemui.biometrics.domain.interactor
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
+import android.hardware.biometrics.PromptVerticalListContentView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.Utils
@@ -10,6 +12,8 @@
import com.android.systemui.biometrics.promptInfo
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
@@ -43,6 +47,7 @@
private val testScope = TestScope(testDispatcher)
private val biometricPromptRepository = FakePromptRepository()
private val credentialInteractor = FakeCredentialInteractor()
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
private lateinit var interactor: PromptCredentialInteractor
@@ -90,6 +95,82 @@
assertThat(prompt).isNull()
}
+ @Test
+ fun testShowTitleOnlyValue_description() =
+ testScope.runTest {
+ val title = "what a prompt"
+ val subtitle = "s"
+ val description = "something to see"
+
+ val showTitleOnly by collectLastValue(interactor.showTitleOnly)
+
+ interactor.useCredentialsForAuthentication(
+ PromptInfo().also {
+ it.title = title
+ it.description = description
+ it.subtitle = subtitle
+ },
+ kind = Utils.CREDENTIAL_PIN,
+ userId = USER_ID,
+ challenge = OPERATION_ID,
+ opPackageName = OP_PACKAGE_NAME
+ )
+ assertThat(showTitleOnly).isFalse()
+ }
+
+ @Test
+ fun testShowTitleOnlyValue_verticalListContentView() =
+ testScope.runTest {
+ val title = "what a prompt"
+ val subtitle = "s"
+ val description = "something to see"
+ val contentView = PromptVerticalListContentView.Builder().build()
+
+ val showTitleOnly by collectLastValue(interactor.showTitleOnly)
+
+ interactor.useCredentialsForAuthentication(
+ PromptInfo().also {
+ it.title = title
+ it.description = description
+ it.subtitle = subtitle
+ it.contentView = contentView
+ },
+ kind = Utils.CREDENTIAL_PIN,
+ userId = USER_ID,
+ challenge = OPERATION_ID,
+ opPackageName = OP_PACKAGE_NAME
+ )
+ assertThat(showTitleOnly).isTrue()
+ }
+
+ @Test
+ fun testShowTitleOnlyValue_ContentViewWithButton() =
+ testScope.runTest {
+ val title = "what a prompt"
+ val subtitle = "s"
+ val description = "something to see"
+ val contentView =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
+ .build()
+
+ val showTitleOnly by collectLastValue(interactor.showTitleOnly)
+
+ interactor.useCredentialsForAuthentication(
+ PromptInfo().also {
+ it.title = title
+ it.description = description
+ it.subtitle = subtitle
+ it.contentView = contentView
+ },
+ kind = Utils.CREDENTIAL_PIN,
+ userId = USER_ID,
+ challenge = OPERATION_ID,
+ opPackageName = OP_PACKAGE_NAME
+ )
+ assertThat(showTitleOnly).isFalse()
+ }
+
@Test fun usePinCredentialForPrompt() = useCredentialForPrompt(Utils.CREDENTIAL_PIN)
@Test fun usePasswordCredentialForPrompt() = useCredentialForPrompt(Utils.CREDENTIAL_PASSWORD)
@@ -106,12 +187,14 @@
val title = "what a prompt"
val subtitle = "s"
val description = "something to see"
+ val contentView = PromptVerticalListContentView.Builder().build()
interactor.useCredentialsForAuthentication(
PromptInfo().also {
it.title = title
it.description = description
it.subtitle = subtitle
+ it.contentView = contentView
},
kind = kind,
userId = USER_ID,
@@ -122,6 +205,7 @@
assertThat(prompt?.title).isEqualTo(title)
assertThat(prompt?.subtitle).isEqualTo(subtitle)
assertThat(prompt?.description).isEqualTo(description)
+ assertThat(prompt?.contentView).isEqualTo(contentView)
assertThat(prompt?.userInfo).isEqualTo(BiometricUserInfo(USER_ID))
assertThat(prompt?.operationInfo).isEqualTo(BiometricOperationInfo(OPERATION_ID))
assertThat(prompt)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
index 8fab233..d10b935 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
@@ -2,6 +2,7 @@
import android.graphics.Bitmap
import android.hardware.biometrics.PromptContentItemBulletedText
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptVerticalListContentView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -11,6 +12,7 @@
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -59,7 +61,7 @@
assertThat(request.title).isEqualTo(title)
assertThat(request.subtitle).isEqualTo(subtitle)
assertThat(request.description).isEqualTo(description)
- assertThat(request.contentView).isEqualTo(contentView)
+ assertThat(request.contentView).isSameInstanceAs(contentView)
assertThat(request.userInfo).isEqualTo(BiometricUserInfo(USER_ID))
assertThat(request.operationInfo).isEqualTo(BiometricOperationInfo(OPERATION_ID))
assertThat(request.modalities)
@@ -67,6 +69,29 @@
}
@Test
+ fun biometricRequestContentViewWithMoreOptionsButtonFromPromptInfo() {
+ val title = "what"
+ val description = "request"
+ val executor = MoreExecutors.directExecutor()
+ val contentView =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setDescription("test")
+ .setMoreOptionsButtonListener(executor) { _, _ -> }
+ .build()
+
+ val fpPros = fingerprintSensorPropertiesInternal().first()
+ val request =
+ BiometricPromptRequest.Biometric(
+ promptInfo(title = title, description = description, contentView = contentView),
+ BiometricUserInfo(USER_ID),
+ BiometricOperationInfo(OPERATION_ID),
+ BiometricModalities(fingerprintProperties = fpPros),
+ OP_PACKAGE_NAME,
+ )
+ assertThat(request.contentView).isSameInstanceAs(contentView)
+ }
+
+ @Test
fun biometricRequestLogoBitmapFromPromptInfo() {
val logoBitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)
val fpPros = fingerprintSensorPropertiesInternal().first()
@@ -89,6 +114,12 @@
val subtitle = "a"
val description = "request"
val stealth = true
+ val contentView =
+ PromptVerticalListContentView.Builder()
+ .setDescription("content description")
+ .addListItem(PromptContentItemBulletedText("content item 1"))
+ .addListItem(PromptContentItemBulletedText("content item 2"), 1)
+ .build()
val toCheck =
listOf(
@@ -97,6 +128,7 @@
title = title,
subtitle = subtitle,
description = description,
+ contentView = contentView,
credentialTitle = null,
credentialSubtitle = null,
credentialDescription = null,
@@ -106,6 +138,7 @@
),
BiometricPromptRequest.Credential.Password(
promptInfo(
+ contentView = contentView,
credentialTitle = title,
credentialSubtitle = subtitle,
credentialDescription = description,
@@ -117,6 +150,7 @@
promptInfo(
subtitle = subtitle,
description = description,
+ contentView = contentView,
credentialTitle = title,
credentialSubtitle = null,
credentialDescription = null,
@@ -131,6 +165,7 @@
assertThat(request.title).isEqualTo(title)
assertThat(request.subtitle).isEqualTo(subtitle)
assertThat(request.description).isEqualTo(description)
+ assertThat(request.contentView).isEqualTo(contentView)
assertThat(request.userInfo).isEqualTo(BiometricUserInfo(USER_ID))
assertThat(request.operationInfo).isEqualTo(BiometricOperationInfo(OPERATION_ID))
if (request is BiometricPromptRequest.Credential.Pattern) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 7db4ca9..5b0df5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -25,6 +25,7 @@
import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
import android.hardware.biometrics.PromptContentItemBulletedText
import android.hardware.biometrics.PromptContentView
+import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import android.hardware.face.FaceSensorPropertiesInternal
@@ -122,6 +123,8 @@
private lateinit var viewModel: PromptViewModel
private lateinit var iconViewModel: PromptIconViewModel
private lateinit var promptContentView: PromptContentView
+ private lateinit var promptContentViewWithMoreOptionsButton:
+ PromptContentViewWithMoreOptionsButton
@Before
fun setup() {
@@ -163,6 +166,12 @@
.addListItem(PromptContentItemBulletedText("content item 2"), 1)
.build()
+ promptContentViewWithMoreOptionsButton =
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setDescription("test")
+ .setMoreOptionsButtonListener(fakeExecutor, { _, _ -> })
+ .build()
+
viewModel =
PromptViewModel(
displayStateInteractor,
@@ -1254,7 +1263,7 @@
}
@Test
- fun descriptionOverriddenByContentView() =
+ fun descriptionOverriddenByVerticalListContentView() =
runGenericTest(contentView = promptContentView, description = "test description") {
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
@@ -1266,6 +1275,21 @@
}
@Test
+ fun descriptionOverriddenByContentViewWithMoreOptionsButton() =
+ runGenericTest(
+ contentView = promptContentViewWithMoreOptionsButton,
+ description = "test description"
+ ) {
+ mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+ mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
+ val contentView by collectLastValue(viewModel.contentView)
+ val description by collectLastValue(viewModel.description)
+
+ assertThat(description).isEqualTo("")
+ assertThat(contentView).isEqualTo(promptContentViewWithMoreOptionsButton)
+ }
+
+ @Test
fun descriptionWithoutContentView() =
runGenericTest(description = "test description") {
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
index 890b9ae..ae77d1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
@@ -24,6 +24,9 @@
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.ControlsProviderService
@@ -176,6 +179,64 @@
assertNull(wrapper.intent)
}
+ @Test
+ fun testClassNotFoundExceptionComponent_noCrash() {
+ val bundle = Bundle().apply {
+ putParcelable(Intent.EXTRA_COMPONENT_NAME, PrivateParcelable())
+ putParcelable(ControlsProviderService.EXTRA_CONTROL, control)
+ }
+ val parcel = Parcel.obtain()
+ bundle.writeToParcel(parcel, 0)
+
+ parcel.setDataPosition(0)
+
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ parcel.readBundle()?.let { putExtras(it) }
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testClassNotFoundExceptionControl_noCrash() {
+ val bundle = Bundle().apply {
+ putParcelable(Intent.EXTRA_COMPONENT_NAME, componentName)
+ putParcelable(ControlsProviderService.EXTRA_CONTROL, PrivateParcelable())
+ }
+ val parcel = Parcel.obtain()
+ bundle.writeToParcel(parcel, 0)
+
+ parcel.setDataPosition(0)
+
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ parcel.readBundle()?.let { putExtras(it) }
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testMissingComponentName_noCrash() {
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ putExtra(ControlsProviderService.EXTRA_CONTROL, control)
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testMissingControl_noCrash() {
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
class MyWrapper(context: Context) : ContextWrapper(context) {
var intent: Intent? = null
@@ -189,4 +250,20 @@
this.intent = intent
}
}
+
+ class PrivateParcelable : Parcelable {
+ override fun describeContents() = 0
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {}
+
+ companion object CREATOR : Parcelable.Creator<PrivateParcelable?> {
+ override fun createFromParcel(source: Parcel?): PrivateParcelable {
+ return PrivateParcelable()
+ }
+
+ override fun newArray(size: Int): Array<PrivateParcelable?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index f36f032..4684b80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -221,8 +221,42 @@
assertThat(message).isNull()
}
+ @Test
+ fun noMessage_fpErrorsWhileDozing() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+
+ givenOnOccludingApp(true)
+ givenFingerprintAllowed(true)
+ keyguardRepository.setIsDozing(true)
+ runCurrent()
+
+ // ERROR message
+ fingerprintAuthRepository.setAuthenticationStatus(
+ ErrorFingerprintAuthenticationStatus(
+ FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ "testError",
+ )
+ )
+ assertThat(message).isNull()
+
+ // HELP message
+ fingerprintAuthRepository.setAuthenticationStatus(
+ HelpFingerprintAuthenticationStatus(
+ FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL,
+ "testHelp",
+ )
+ )
+ assertThat(message).isNull()
+
+ // FAIL message
+ fingerprintAuthRepository.setAuthenticationStatus(FailFingerprintAuthenticationStatus)
+ assertThat(message).isNull()
+ }
+
private fun givenOnOccludingApp(isOnOccludingApp: Boolean) {
powerRepository.setInteractive(true)
+ keyguardRepository.setIsDozing(false)
keyguardRepository.setKeyguardOccluded(isOnOccludingApp)
keyguardRepository.setKeyguardShowing(isOnOccludingApp)
keyguardRepository.setDreaming(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
index 5dd37ae..66aa572 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
@@ -131,7 +131,6 @@
whenever(clock.smallClock).thenReturn(smallClock)
whenever(largeClock.layout).thenReturn(largeClockFaceLayout)
whenever(smallClock.layout).thenReturn(smallClockFaceLayout)
- whenever(clockViewModel.clock).thenReturn(clock)
currentClock.value = clock
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt
index 59eb7bb..e56a253 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt
@@ -66,7 +66,7 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
-class MediaDataFilterTest : SysuiTestCase() {
+class LegacyMediaDataFilterImplTest : SysuiTestCase() {
@Mock private lateinit var listener: MediaDataManager.Listener
@Mock private lateinit var userTracker: UserTracker
@@ -80,7 +80,7 @@
@Mock private lateinit var mediaFlags: MediaFlags
@Mock private lateinit var cardAction: SmartspaceAction
- private lateinit var mediaDataFilter: MediaDataFilter
+ private lateinit var mediaDataFilter: LegacyMediaDataFilterImpl
private lateinit var dataMain: MediaData
private lateinit var dataGuest: MediaData
private lateinit var dataPrivateProfile: MediaData
@@ -92,7 +92,7 @@
MediaPlayerData.clear()
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
mediaDataFilter =
- MediaDataFilter(
+ LegacyMediaDataFilterImpl(
context,
userTracker,
broadcastSender,
@@ -370,7 +370,7 @@
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
mediaDataFilter.onSwipeToDismiss()
- verify(mediaDataManager).setTimedOut(eq(KEY), eq(true), eq(true))
+ verify(mediaDataManager).setInactive(eq(KEY), eq(true), eq(true))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
index 61bfdb5..5a2d22d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
@@ -114,7 +114,7 @@
@SmallTest
@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
-class MediaDataManagerTest : SysuiTestCase() {
+class LegacyMediaDataManagerImplTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Mock lateinit var mediaControllerFactory: MediaControllerFactory
@@ -133,7 +133,7 @@
@Mock lateinit var mediaSessionBasedFilter: MediaSessionBasedFilter
@Mock lateinit var mediaDeviceManager: MediaDeviceManager
@Mock lateinit var mediaDataCombineLatest: MediaDataCombineLatest
- @Mock lateinit var mediaDataFilter: MediaDataFilter
+ @Mock lateinit var mediaDataFilter: LegacyMediaDataFilterImpl
@Mock lateinit var listener: MediaDataManager.Listener
@Mock lateinit var pendingIntent: PendingIntent
@Mock lateinit var activityStarter: ActivityStarter
@@ -146,7 +146,7 @@
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
@Mock private lateinit var mediaFlags: MediaFlags
@Mock private lateinit var logger: MediaUiEventLogger
- lateinit var mediaDataManager: MediaDataManager
+ lateinit var mediaDataManager: LegacyMediaDataManagerImpl
lateinit var mediaNotification: StatusBarNotification
lateinit var remoteCastNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
@@ -189,7 +189,7 @@
1
)
mediaDataManager =
- MediaDataManager(
+ LegacyMediaDataManagerImpl(
context = context,
backgroundExecutor = backgroundExecutor,
uiExecutor = uiExecutor,
@@ -304,13 +304,13 @@
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
assertThat(data.active).isFalse()
verify(logger).logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
- fun testSetTimedOut_resume_dismissesMedia() {
+ fun testsetInactive_resume_dismissesMedia() {
// WHEN resume controls are present, and time out
val desc =
MediaDescription.Builder().run {
@@ -339,7 +339,7 @@
eq(false)
)
- mediaDataManager.setTimedOut(PACKAGE_NAME, timedOut = true)
+ mediaDataManager.setInactive(PACKAGE_NAME, timedOut = true)
verify(logger)
.logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(mediaDataCaptor.value.instanceId))
@@ -1485,7 +1485,7 @@
// WHEN the notification times out
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
- mediaDataManager.setTimedOut(KEY, true, true)
+ mediaDataManager.setInactive(KEY, true, true)
// THEN the last active time is changed
verify(listener)
@@ -1602,7 +1602,7 @@
eq(false)
)
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size)
- .isEqualTo(MediaDataManager.MAX_COMPACT_ACTIONS)
+ .isEqualTo(LegacyMediaDataManagerImpl.MAX_COMPACT_ACTIONS)
}
@Test
@@ -1615,7 +1615,7 @@
modifyNotification(context).also {
it.setSmallIcon(android.R.drawable.ic_media_pause)
it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
- for (i in 0..MediaDataManager.MAX_NOTIFICATION_ACTIONS) {
+ for (i in 0..LegacyMediaDataManagerImpl.MAX_NOTIFICATION_ACTIONS) {
it.addAction(action)
}
}
@@ -1638,7 +1638,7 @@
eq(false)
)
assertThat(mediaDataCaptor.value.actions.size)
- .isEqualTo(MediaDataManager.MAX_NOTIFICATION_ACTIONS)
+ .isEqualTo(LegacyMediaDataManagerImpl.MAX_NOTIFICATION_ACTIONS)
}
@Test
@@ -2040,7 +2040,7 @@
// When a media control based on notification is added, times out, and then removed
addNotificationAndLoad()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
assertThat(mediaDataCaptor.value.active).isFalse()
mediaDataManager.onNotificationRemoved(KEY)
@@ -2070,7 +2070,7 @@
// When a media control based on notification is added and times out
addNotificationAndLoad()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
assertThat(mediaDataCaptor.value.active).isFalse()
// and then the session is destroyed
@@ -2142,7 +2142,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
mediaDataManager.onNotificationRemoved(KEY)
// It remains as a regular player
@@ -2162,7 +2162,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
sessionCallbackCaptor.value.invoke(KEY)
// It is converted to a resume player
@@ -2249,7 +2249,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataManager.setInactive(KEY, timedOut = true)
sessionCallbackCaptor.value.invoke(KEY)
// It is fully removed.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
new file mode 100644
index 0000000..564bdc3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
@@ -0,0 +1,931 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.app.smartspace.SmartspaceAction
+import android.os.Bundle
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.media.controls.MediaTestUtils
+import com.android.systemui.media.controls.data.repository.MediaFilterRepository
+import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
+import com.android.systemui.media.controls.ui.controller.MediaPlayerData
+import com.android.systemui.media.controls.util.MediaFlags
+import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+private const val KEY = "TEST_KEY"
+private const val KEY_ALT = "TEST_KEY_2"
+private const val USER_MAIN = 0
+private const val USER_GUEST = 10
+private const val PRIVATE_PROFILE = 12
+private const val PACKAGE = "PKG"
+private val INSTANCE_ID = InstanceId.fakeInstanceId(123)!!
+private const val APP_UID = 99
+private const val SMARTSPACE_KEY = "SMARTSPACE_KEY"
+private const val SMARTSPACE_PACKAGE = "SMARTSPACE_PKG"
+private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!!
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaDataFilterImplTest : SysuiTestCase() {
+
+ @Mock private lateinit var listener: MediaDataManager.Listener
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var broadcastSender: BroadcastSender
+ @Mock private lateinit var mediaDataManager: MediaDataManager
+ @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
+ @Mock private lateinit var executor: Executor
+ @Mock private lateinit var smartspaceData: SmartspaceMediaData
+ @Mock private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction
+ @Mock private lateinit var logger: MediaUiEventLogger
+ @Mock private lateinit var mediaFlags: MediaFlags
+ @Mock private lateinit var cardAction: SmartspaceAction
+
+ private lateinit var mediaDataFilter: MediaDataFilterImpl
+ private lateinit var mediaFilterRepository: MediaFilterRepository
+ private lateinit var testScope: TestScope
+ private lateinit var dataMain: MediaData
+ private lateinit var dataGuest: MediaData
+ private lateinit var dataPrivateProfile: MediaData
+ private val clock = FakeSystemClock()
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ MediaPlayerData.clear()
+ whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
+ testScope = TestScope()
+ mediaFilterRepository = MediaFilterRepository()
+ mediaDataFilter =
+ MediaDataFilterImpl(
+ context,
+ userTracker,
+ broadcastSender,
+ lockscreenUserManager,
+ executor,
+ clock,
+ logger,
+ mediaFlags,
+ mediaFilterRepository,
+ )
+ mediaDataFilter.mediaDataManager = mediaDataManager
+ mediaDataFilter.addListener(listener)
+
+ // Start all tests as main user
+ setUser(USER_MAIN)
+
+ // Set up test media data
+ dataMain =
+ MediaTestUtils.emptyMediaData.copy(
+ userId = USER_MAIN,
+ packageName = PACKAGE,
+ instanceId = INSTANCE_ID,
+ appUid = APP_UID
+ )
+ dataGuest = dataMain.copy(userId = USER_GUEST)
+ dataPrivateProfile = dataMain.copy(userId = PRIVATE_PROFILE)
+
+ whenever(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
+ whenever(smartspaceData.isActive).thenReturn(true)
+ whenever(smartspaceData.isValid()).thenReturn(true)
+ whenever(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE)
+ whenever(smartspaceData.recommendations)
+ .thenReturn(listOf(smartspaceMediaRecommendationItem))
+ whenever(smartspaceData.headphoneConnectionTimeMillis)
+ .thenReturn(clock.currentTimeMillis() - 100)
+ whenever(smartspaceData.instanceId).thenReturn(SMARTSPACE_INSTANCE_ID)
+ whenever(smartspaceData.cardAction).thenReturn(cardAction)
+ }
+
+ private fun setUser(id: Int) {
+ whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false)
+ whenever(lockscreenUserManager.isProfileAvailable(anyInt())).thenReturn(false)
+ whenever(lockscreenUserManager.isCurrentProfile(eq(id))).thenReturn(true)
+ whenever(lockscreenUserManager.isProfileAvailable(eq(id))).thenReturn(true)
+ whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(true)
+ mediaDataFilter.handleUserSwitched()
+ }
+
+ private fun setPrivateProfileUnavailable() {
+ whenever(lockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false)
+ whenever(lockscreenUserManager.isCurrentProfile(eq(USER_MAIN))).thenReturn(true)
+ whenever(lockscreenUserManager.isCurrentProfile(eq(PRIVATE_PROFILE))).thenReturn(true)
+ whenever(lockscreenUserManager.isProfileAvailable(eq(PRIVATE_PROFILE))).thenReturn(false)
+ mediaDataFilter.handleProfileChanged()
+ }
+
+ @Test
+ fun testOnDataLoadedForCurrentUser_callsListener() {
+ // GIVEN a media for main user
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+
+ // THEN we should tell the listener
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false))
+ }
+
+ @Test
+ fun testOnDataLoadedForGuest_doesNotCallListener() {
+ // GIVEN a media for guest user
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
+
+ // THEN we should NOT tell the listener
+ verify(listener, never())
+ .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testOnRemovedForCurrent_callsListener() {
+ // GIVEN a media was removed for main user
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+ mediaDataFilter.onMediaDataRemoved(KEY)
+
+ // THEN we should tell the listener
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
+ @Test
+ fun testOnRemovedForGuest_doesNotCallListener() {
+ // GIVEN a media was removed for guest user
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
+ mediaDataFilter.onMediaDataRemoved(KEY)
+
+ // THEN we should NOT tell the listener
+ verify(listener, never()).onMediaDataRemoved(eq(KEY))
+ }
+
+ @Test
+ fun testOnUserSwitched_removesOldUserControls() {
+ // GIVEN that we have a media loaded for main user
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+
+ // and we switch to guest user
+ setUser(USER_GUEST)
+
+ // THEN we should remove the main user's media
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
+ @Test
+ fun testOnUserSwitched_addsNewUserControls() {
+ // GIVEN that we had some media for both users
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+ mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataGuest)
+ reset(listener)
+
+ // and we switch to guest user
+ setUser(USER_GUEST)
+
+ // THEN we should add back the guest user media
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), eq(0), eq(false))
+
+ // but not the main user's
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testOnProfileChanged_profileUnavailable_loadControls() {
+ // GIVEN that we had some media for both profiles
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+ mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataPrivateProfile)
+ reset(listener)
+
+ // and we change profile status
+ setPrivateProfileUnavailable()
+
+ // THEN we should add the private profile media
+ verify(listener).onMediaDataRemoved(eq(KEY_ALT))
+ }
+
+ @Test
+ fun hasAnyMedia_mediaSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
+
+ assertThat(hasAnyMedia(selectedUserEntries)).isTrue()
+ }
+
+ @Test
+ fun hasAnyMedia_recommendationSet_returnsFalse() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ assertThat(hasAnyMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun hasAnyMediaOrRecommendation_mediaSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
+
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isTrue()
+ }
+
+ @Test
+ fun hasAnyMediaOrRecommendation_recommendationSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isTrue()
+ }
+
+ @Test
+ fun hasActiveMedia_inactiveMediaSet_returnsFalse() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+
+ val data = dataMain.copy(active = false)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
+
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun hasActiveMedia_activeMediaSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val data = dataMain.copy(active = true)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
+
+ assertThat(hasActiveMedia(selectedUserEntries)).isTrue()
+ }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalse() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ val data = dataMain.copy(active = false)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
+
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_activeMediaSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ val data = dataMain.copy(active = true)
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
+
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalse() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(smartspaceData.isActive).thenReturn(false)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalse() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(smartspaceData.isValid()).thenReturn(false)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTrue() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(smartspaceData.isActive).thenReturn(true)
+ whenever(smartspaceData.isValid()).thenReturn(true)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ }
+
+ @Test
+ fun testHasAnyMediaOrRecommendation_onlyCurrentUser() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isFalse()
+
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataGuest)
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isFalse()
+ assertThat(hasAnyMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun testHasActiveMediaOrRecommendation_onlyCurrentUser() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ val data = dataGuest.copy(active = true)
+
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasAnyMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun testOnNotificationRemoved_doesNotHaveMedia() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+
+ mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
+ mediaDataFilter.onMediaDataRemoved(KEY)
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isFalse()
+ assertThat(hasAnyMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun testOnSwipeToDismiss_setsTimedOut() {
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
+ mediaDataFilter.onSwipeToDismiss()
+
+ verify(mediaDataManager).setInactive(eq(KEY), eq(true), eq(true))
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspace() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
+ verify(logger, never()).logRecommendationActivated(any(), any(), any())
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothing() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+
+ whenever(smartspaceData.isActive).thenReturn(false)
+
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener, never())
+ .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ verify(logger, never()).logRecommendationAdded(any(), any())
+ verify(logger, never()).logRecommendationActivated(any(), any(), any())
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspace() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
+ clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
+ verify(logger, never()).logRecommendationActivated(any(), any(), any())
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothing() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(smartspaceData.isActive).thenReturn(false)
+
+ val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
+ clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ verify(logger, never()).logRecommendationAdded(any(), any())
+ verify(logger, never()).logRecommendationActivated(any(), any(), any())
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothing() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+
+ whenever(smartspaceData.isActive).thenReturn(false)
+
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // AND we get a smartspace signal
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN we should tell listeners to treat the media as not active instead
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), anyInt(), anyBoolean())
+ verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ verify(logger, never()).logRecommendationAdded(any(), any())
+ verify(logger, never()).logRecommendationActivated(any(), any(), any())
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(smartspaceData.isValid()).thenReturn(false)
+
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // AND we get a smartspace signal
+ runCurrent()
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN we should tell listeners to treat the media as active instead
+ val dataCurrentAndActive = dataCurrent.copy(active = true)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ // Smartspace update shouldn't be propagated for the empty rec list.
+ verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
+ verify(logger, never()).logRecommendationAdded(any(), any())
+ verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBoth() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // AND we get a smartspace signal
+ runCurrent()
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN we should tell listeners to treat the media as active instead
+ val dataCurrentAndActive = dataCurrent.copy(active = true)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ // Smartspace update should also be propagated but not prioritized.
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
+ verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+ mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+
+ verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ runCurrent()
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ val dataCurrentAndActive = dataCurrent.copy(active = true)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
+
+ mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+
+ verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasActiveMedia(selectedUserEntries)).isFalse()
+ }
+
+ @Test
+ fun testOnSmartspaceLoaded_persistentEnabled_isInactive_notifiesListeners() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)
+ whenever(smartspaceData.isActive).thenReturn(false)
+
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isTrue()
+ }
+
+ @Test
+ fun testOnSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactive() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+
+ whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)
+ whenever(smartspaceData.isActive).thenReturn(false)
+
+ // If there is media that was recently played but inactive
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // And an inactive recommendation is loaded
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // Smartspace is loaded but the media stays inactive
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ verify(listener, never())
+ .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isFalse()
+ assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))
+ .isTrue()
+ }
+
+ @Test
+ fun testOnSwipeToDismiss_persistentEnabled_recommendationSetInactive() {
+ whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)
+
+ val data =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = SMARTSPACE_KEY,
+ isActive = true,
+ packageName = SMARTSPACE_PACKAGE,
+ recommendations = listOf(smartspaceMediaRecommendationItem),
+ )
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, data)
+ mediaDataFilter.onSwipeToDismiss()
+
+ verify(mediaDataManager).setRecommendationInactive(eq(SMARTSPACE_KEY))
+ verify(mediaDataManager, never())
+ .dismissSmartspaceRecommendation(eq(SMARTSPACE_KEY), anyLong())
+ }
+
+ @Test
+ fun testSmartspaceLoaded_shouldTriggerResume_doesTrigger() =
+ testScope.runTest {
+ val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries)
+ val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData)
+ val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedKey)
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // AND we get a smartspace signal with extra to trigger resume
+ runCurrent()
+ val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, true) }
+ whenever(cardAction.extras).thenReturn(extras)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN we should tell listeners to treat the media as active instead
+ val dataCurrentAndActive = dataCurrent.copy(active = true)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
+ assertThat(
+ hasActiveMediaOrRecommendation(
+ selectedUserEntries,
+ smartspaceMediaData,
+ reactivatedKey
+ )
+ )
+ .isTrue()
+ // And send the smartspace data, but not prioritized
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ }
+
+ @Test
+ fun testSmartspaceLoaded_notShouldTriggerResume_doesNotTrigger() {
+ // WHEN we have media that was recently played, but not currently active
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
+ mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
+
+ // AND we get a smartspace signal with extra to not trigger resume
+ val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) }
+ whenever(cardAction.extras).thenReturn(extras)
+ mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
+
+ // THEN listeners are not updated to show media
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), eq(KEY), any(), eq(true), eq(100), eq(true))
+ // But the smartspace update is still propagated
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ }
+
+ private fun hasActiveMediaOrRecommendation(
+ entries: Map<String, MediaData>?,
+ smartspaceMediaData: SmartspaceMediaData?,
+ reactivatedKey: String?
+ ): Boolean {
+ if (entries == null || smartspaceMediaData == null) {
+ return false
+ }
+ return entries.any { it.value.active } ||
+ (smartspaceMediaData.isActive &&
+ (smartspaceMediaData.isValid() || reactivatedKey != null))
+ }
+
+ private fun hasActiveMedia(entries: Map<String, MediaData>?): Boolean {
+ return entries?.any { it.value.active } ?: false
+ }
+
+ private fun hasAnyMediaOrRecommendation(
+ entries: Map<String, MediaData>?,
+ smartspaceMediaData: SmartspaceMediaData?
+ ): Boolean {
+ if (entries == null || smartspaceMediaData == null) {
+ return false
+ }
+ return entries.isNotEmpty() ||
+ (if (mediaFlags.isPersistentSsCardEnabled()) {
+ smartspaceMediaData.isValid()
+ } else {
+ smartspaceMediaData.isActive && smartspaceMediaData.isValid()
+ })
+ }
+
+ private fun hasAnyMedia(entries: Map<String, MediaData>?): Boolean {
+ return entries?.isNotEmpty() ?: false
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
similarity index 91%
copy from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt
copy to packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
index 61bfdb5..5c275b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.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.
@@ -41,6 +41,7 @@
import android.provider.Settings
import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
@@ -51,6 +52,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.controls.data.repository.MediaDataRepository
+import com.android.systemui.media.controls.data.repository.MediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.resume.MediaResumeListener
import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
@@ -64,13 +68,19 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.SbnBuilder
-import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -87,7 +97,6 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoSession
import org.mockito.junit.MockitoJUnit
import org.mockito.quality.Strictness
@@ -111,10 +120,11 @@
return Mockito.anyObject<T>()
}
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
-class MediaDataManagerTest : SysuiTestCase() {
+class MediaDataProcessorTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Mock lateinit var mediaControllerFactory: MediaControllerFactory
@@ -122,9 +132,9 @@
@Mock lateinit var transportControls: MediaController.TransportControls
@Mock lateinit var playbackInfo: MediaController.PlaybackInfo
lateinit var session: MediaSession
- lateinit var metadataBuilder: MediaMetadata.Builder
+ private lateinit var metadataBuilder: MediaMetadata.Builder
lateinit var backgroundExecutor: FakeExecutor
- lateinit var foregroundExecutor: FakeExecutor
+ private lateinit var foregroundExecutor: FakeExecutor
lateinit var uiExecutor: FakeExecutor
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var broadcastDispatcher: BroadcastDispatcher
@@ -133,32 +143,38 @@
@Mock lateinit var mediaSessionBasedFilter: MediaSessionBasedFilter
@Mock lateinit var mediaDeviceManager: MediaDeviceManager
@Mock lateinit var mediaDataCombineLatest: MediaDataCombineLatest
- @Mock lateinit var mediaDataFilter: MediaDataFilter
+ @Mock lateinit var mediaDataFilter: MediaDataFilterImpl
@Mock lateinit var listener: MediaDataManager.Listener
@Mock lateinit var pendingIntent: PendingIntent
@Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var smartspaceManager: SmartspaceManager
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
+ private lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
- lateinit var validRecommendationList: List<SmartspaceAction>
+ private lateinit var validRecommendationList: List<SmartspaceAction>
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
@Mock private lateinit var mediaFlags: MediaFlags
@Mock private lateinit var logger: MediaUiEventLogger
- lateinit var mediaDataManager: MediaDataManager
- lateinit var mediaNotification: StatusBarNotification
- lateinit var remoteCastNotification: StatusBarNotification
+ private lateinit var mediaCarouselInteractor: MediaCarouselInteractor
+ private lateinit var mediaDataProcessor: MediaDataProcessor
+ private lateinit var mediaNotification: StatusBarNotification
+ private lateinit var remoteCastNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
private val clock = FakeSystemClock()
- @Mock private lateinit var tunerService: TunerService
- @Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable>
@Captor lateinit var stateCallbackCaptor: ArgumentCaptor<(String, PlaybackState) -> Unit>
@Captor lateinit var sessionCallbackCaptor: ArgumentCaptor<(String) -> Unit>
@Captor lateinit var smartSpaceConfigBuilderCaptor: ArgumentCaptor<SmartspaceConfig>
@Mock private lateinit var ugm: IUriGrantsManager
@Mock private lateinit var imageSource: ImageDecoder.Source
+ private lateinit var mediaDataRepository: MediaDataRepository
+ private lateinit var mediaFilterRepository: MediaFilterRepository
+ private lateinit var testScope: TestScope
+ private lateinit var testDispatcher: TestDispatcher
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fakeHandler: FakeHandler
+ private val settings = FakeSettings()
private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)
private val originalSmartspaceSetting =
@@ -172,6 +188,8 @@
@Before
fun setup() {
+ whenever(mediaFlags.isMediaControlsRefactorEnabled()).thenReturn(true)
+
staticMockSession =
ExtendedMockito.mockitoSession()
.mockStatic<UriGrantsManager>(UriGrantsManager::class.java)
@@ -182,43 +200,61 @@
foregroundExecutor = FakeExecutor(clock)
backgroundExecutor = FakeExecutor(clock)
uiExecutor = FakeExecutor(clock)
+ testableLooper = TestableLooper.get(this)
+ fakeHandler = FakeHandler(testableLooper.looper)
smartspaceMediaDataProvider = SmartspaceMediaDataProvider()
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
1
)
- mediaDataManager =
- MediaDataManager(
+ testDispatcher = UnconfinedTestDispatcher()
+ testScope = TestScope(testDispatcher)
+ mediaFilterRepository = MediaFilterRepository()
+ mediaDataRepository = MediaDataRepository(mediaFlags, dumpManager)
+ mediaDataProcessor =
+ MediaDataProcessor(
context = context,
+ applicationScope = testScope,
+ backgroundDispatcher = testDispatcher,
backgroundExecutor = backgroundExecutor,
uiExecutor = uiExecutor,
foregroundExecutor = foregroundExecutor,
+ handler = fakeHandler,
mediaControllerFactory = mediaControllerFactory,
broadcastDispatcher = broadcastDispatcher,
dumpManager = dumpManager,
+ activityStarter = activityStarter,
+ smartspaceMediaDataProvider = smartspaceMediaDataProvider,
+ useMediaResumption = true,
+ useQsMediaPlayer = true,
+ systemClock = clock,
+ secureSettings = settings,
+ mediaFlags = mediaFlags,
+ logger = logger,
+ smartspaceManager = smartspaceManager,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ mediaDataRepository = mediaDataRepository,
+ )
+ mediaDataProcessor.start()
+ mediaCarouselInteractor =
+ MediaCarouselInteractor(
+ applicationScope = testScope.backgroundScope,
+ mediaDataRepository = mediaDataRepository,
+ mediaDataProcessor = mediaDataProcessor,
mediaTimeoutListener = mediaTimeoutListener,
mediaResumeListener = mediaResumeListener,
mediaSessionBasedFilter = mediaSessionBasedFilter,
mediaDeviceManager = mediaDeviceManager,
mediaDataCombineLatest = mediaDataCombineLatest,
mediaDataFilter = mediaDataFilter,
- activityStarter = activityStarter,
- smartspaceMediaDataProvider = smartspaceMediaDataProvider,
- useMediaResumption = true,
- useQsMediaPlayer = true,
- systemClock = clock,
- tunerService = tunerService,
- mediaFlags = mediaFlags,
- logger = logger,
- smartspaceManager = smartspaceManager,
- keyguardUpdateMonitor = keyguardUpdateMonitor,
+ mediaFilterRepository = mediaFilterRepository,
+ mediaFlags = mediaFlags
)
- verify(tunerService)
- .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
+ mediaCarouselInteractor.start()
verify(mediaTimeoutListener).stateCallback = capture(stateCallbackCaptor)
verify(mediaTimeoutListener).sessionCallback = capture(sessionCallbackCaptor)
- session = MediaSession(context, "MediaDataManagerTestSession")
+ session = MediaSession(context, "MediaDataProcessorTestSession")
mediaNotification =
SbnBuilder().run {
setPkg(PACKAGE_NAME)
@@ -290,7 +326,7 @@
fun tearDown() {
staticMockSession.finishMocking()
session.release()
- mediaDataManager.destroy()
+ mediaDataProcessor.destroy()
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
@@ -299,25 +335,25 @@
}
@Test
- fun testSetTimedOut_active_deactivatesMedia() {
+ fun testsetInactive_active_deactivatesMedia() {
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
assertThat(data.active).isFalse()
verify(logger).logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@Test
- fun testSetTimedOut_resume_dismissesMedia() {
+ fun testsetInactive_resume_dismissesMedia() {
// WHEN resume controls are present, and time out
val desc =
MediaDescription.Builder().run {
setTitle(SESSION_TITLE)
build()
}
- mediaDataManager.addResumptionControls(
+ mediaDataProcessor.addResumptionControls(
USER_ID,
desc,
Runnable {},
@@ -339,7 +375,7 @@
eq(false)
)
- mediaDataManager.setTimedOut(PACKAGE_NAME, timedOut = true)
+ mediaDataProcessor.setInactive(PACKAGE_NAME, timedOut = true)
verify(logger)
.logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(mediaDataCaptor.value.instanceId))
@@ -351,7 +387,7 @@
@Test
fun testLoadsMetadataOnBackground() {
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.numPending()).isEqualTo(1)
}
@@ -367,8 +403,7 @@
.build()
)
- mediaDataManager.addListener(listener)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
@@ -386,8 +421,7 @@
@Test
fun testOnMetaDataLoaded_withoutExplicitIndicator() {
- mediaDataManager.addListener(listener)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
@@ -418,8 +452,7 @@
@Test
fun testOnMetaDataLoaded_conservesActiveFlag() {
whenever(mediaControllerFactory.create(anyObject())).thenReturn(controller)
- mediaDataManager.addListener(listener)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
@@ -464,7 +497,7 @@
build()
}
- mediaDataManager.onNotificationAdded(KEY, notif)
+ mediaDataProcessor.onNotificationAdded(KEY, notif)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
@@ -498,7 +531,7 @@
build()
}
- mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
+ mediaDataProcessor.loadMediaDataInBg(KEY, rcn, null)
// no crash even though the data structure is incorrect
}
@@ -523,7 +556,7 @@
build()
}
- mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
+ mediaDataProcessor.loadMediaDataInBg(KEY, rcn, null)
// no crash even though the data structure is incorrect
}
@@ -531,7 +564,7 @@
fun testOnNotificationRemoved_callsListener() {
addNotificationAndLoad()
val data = mediaDataCaptor.value
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
verify(listener).onMediaDataRemoved(eq(KEY))
verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
}
@@ -549,7 +582,7 @@
.putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
.build()
)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
// Then a media control is created with a placeholder title string
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -580,7 +613,7 @@
.putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
.build()
)
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
// Then a media control is created with a placeholder title string
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -622,7 +655,7 @@
}
build()
}
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
// Then the media control is added using the notification's title
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -646,7 +679,7 @@
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(
+ mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {})
@@ -654,7 +687,7 @@
// WHEN the notification is removed
reset(listener)
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN active media is not converted to resume.
verify(listener, never())
@@ -679,7 +712,7 @@
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(
+ mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {})
@@ -687,7 +720,7 @@
// WHEN the notification is removed
reset(listener)
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN active media is not converted to resume.
verify(listener, never())
@@ -711,9 +744,9 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the media data indicates that it is for resumption
verify(listener)
.onMediaDataLoaded(
@@ -732,8 +765,8 @@
@Test
fun testOnNotificationRemoved_twoWithResumption() {
// GIVEN that the manager has two notifications with resume actions
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
- mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY_2, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
@@ -761,11 +794,11 @@
val data2 = mediaDataCaptor.value
assertThat(data2.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
- mediaDataManager.onMediaDataLoaded(KEY_2, null, data2.copy(resumeAction = Runnable {}))
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+ mediaDataProcessor.onMediaDataLoaded(KEY_2, null, data2.copy(resumeAction = Runnable {}))
reset(listener)
// WHEN the first is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the data is for resumption and the key is migrated to the package name
verify(listener)
.onMediaDataLoaded(
@@ -779,7 +812,7 @@
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY))
// WHEN the second is removed
- mediaDataManager.onNotificationRemoved(KEY_2)
+ mediaDataProcessor.onNotificationRemoved(KEY_2)
// THEN the data is for resumption and the second key is removed
verify(listener)
.onMediaDataLoaded(
@@ -803,7 +836,7 @@
val data = mediaDataCaptor.value
val dataRemoteWithResume =
data.copy(resumeAction = Runnable {}, playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
- mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
verify(logger)
.logActiveMediaAdded(
anyInt(),
@@ -813,7 +846,7 @@
)
// WHEN the notification is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the media data is removed
verify(listener).onMediaDataRemoved(eq(KEY))
@@ -832,10 +865,10 @@
val data = mediaDataCaptor.value
val dataRemoteWithResume =
data.copy(resumeAction = Runnable {}, playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
- mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
// WHEN the notification is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the media data is converted to a resume state
verify(listener)
@@ -860,10 +893,10 @@
val data = mediaDataCaptor.value
assertThat(data.playbackLocation).isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
val dataRemoteWithResume = data.copy(resumeAction = Runnable {})
- mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
// WHEN the RCN is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the media data is removed
verify(listener).onMediaDataRemoved(eq(KEY))
@@ -886,10 +919,10 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// When the notification is removed
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// Then it is converted to resumption
verify(listener)
@@ -913,7 +946,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
verify(listener, never()).onMediaDataRemoved(eq(KEY))
verify(logger, never())
@@ -1076,7 +1109,7 @@
setTitle(SESSION_EMPTY_TITLE)
build()
}
- mediaDataManager.addResumptionControls(
+ mediaDataProcessor.addResumptionControls(
USER_ID,
desc,
Runnable {},
@@ -1110,7 +1143,7 @@
setTitle(SESSION_BLANK_TITLE)
build()
}
- mediaDataManager.addResumptionControls(
+ mediaDataProcessor.addResumptionControls(
USER_ID,
desc,
Runnable {},
@@ -1145,7 +1178,7 @@
addResumeControlAndLoad(desc)
val data = mediaDataCaptor.value
- mediaDataManager.setMediaResumptionEnabled(false)
+ mediaDataProcessor.setMediaResumptionEnabled(false)
// THEN the resume controls are dismissed
verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME))
@@ -1156,7 +1189,7 @@
fun testDismissMedia_listenerCalled() {
addNotificationAndLoad()
val data = mediaDataCaptor.value
- val removed = mediaDataManager.dismissMediaData(KEY, 0L)
+ val removed = mediaDataProcessor.dismissMediaData(KEY, 0L)
assertThat(removed).isTrue()
foregroundExecutor.advanceClockToLast()
@@ -1168,7 +1201,7 @@
@Test
fun testDismissMedia_keyDoesNotExist_returnsFalse() {
- val removed = mediaDataManager.dismissMediaData(KEY, 0L)
+ val removed = mediaDataProcessor.dismissMediaData(KEY, 0L)
assertThat(removed).isFalse()
}
@@ -1186,7 +1219,7 @@
}
build()
}
- mediaDataManager.onNotificationAdded(KEY, notif)
+ mediaDataProcessor.onNotificationAdded(KEY, notif)
// THEN it still loads
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -1239,7 +1272,7 @@
.onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE),
eq(
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ SmartspaceMediaData(
targetId = KEY_MEDIA_SMARTSPACE,
isActive = true,
dismissIntent = DISMISS_INTENT,
@@ -1271,7 +1304,7 @@
.onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE),
eq(
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ SmartspaceMediaData(
targetId = KEY_MEDIA_SMARTSPACE,
isActive = true,
dismissIntent = null,
@@ -1404,7 +1437,7 @@
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
val instanceId = instanceIdSequence.lastInstanceId
- mediaDataManager.setRecommendationInactive(KEY_MEDIA_SMARTSPACE)
+ mediaDataProcessor.setRecommendationInactive(KEY_MEDIA_SMARTSPACE)
uiExecutor.advanceClockToLast()
uiExecutor.runAllReady()
@@ -1431,12 +1464,7 @@
@Test
fun testOnSmartspaceMediaDataLoaded_settingDisabled_doesNothing() {
// WHEN media recommendation setting is off
- Settings.Secure.putInt(
- context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 0
- )
- tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 0)
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
@@ -1453,12 +1481,7 @@
.onSmartspaceMediaDataLoaded(eq(KEY_MEDIA_SMARTSPACE), anyObject(), anyBoolean())
// WHEN the media recommendation setting is turned off
- Settings.Secure.putInt(
- context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 0
- )
- tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 0)
// THEN listeners are notified
uiExecutor.advanceClockToLast()
@@ -1478,14 +1501,14 @@
@Test
fun testOnMediaDataTimedOut_updatesLastActiveTime() {
// GIVEN that the manager has a notification
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// WHEN the notification times out
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
- mediaDataManager.setTimedOut(KEY, true, true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true, forceUpdate = true)
// THEN the last active time is changed
verify(listener)
@@ -1507,12 +1530,12 @@
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the last active time is changed
verify(listener)
@@ -1539,7 +1562,7 @@
val data = mediaDataCaptor.value
val instanceId = data.instanceId
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(
+ mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
data.copy(resumeAction = Runnable {}, active = false)
@@ -1548,7 +1571,7 @@
// WHEN the notification is removed
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// THEN the last active time is not changed
verify(listener)
@@ -1587,7 +1610,7 @@
}
// WHEN the notification is loaded
- mediaDataManager.onNotificationAdded(KEY, notif)
+ mediaDataProcessor.onNotificationAdded(KEY, notif)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
@@ -1602,7 +1625,7 @@
eq(false)
)
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size)
- .isEqualTo(MediaDataManager.MAX_COMPACT_ACTIONS)
+ .isEqualTo(MediaDataProcessor.MAX_COMPACT_ACTIONS)
}
@Test
@@ -1615,7 +1638,7 @@
modifyNotification(context).also {
it.setSmallIcon(android.R.drawable.ic_media_pause)
it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
- for (i in 0..MediaDataManager.MAX_NOTIFICATION_ACTIONS) {
+ for (i in 0..MediaDataProcessor.MAX_NOTIFICATION_ACTIONS) {
it.addAction(action)
}
}
@@ -1623,7 +1646,7 @@
}
// WHEN the notification is loaded
- mediaDataManager.onNotificationAdded(KEY, notif)
+ mediaDataProcessor.onNotificationAdded(KEY, notif)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
@@ -1638,7 +1661,7 @@
eq(false)
)
assertThat(mediaDataCaptor.value.actions.size)
- .isEqualTo(MediaDataManager.MAX_NOTIFICATION_ACTIONS)
+ .isEqualTo(MediaDataProcessor.MAX_NOTIFICATION_ACTIONS)
}
@Test
@@ -1657,7 +1680,7 @@
}
build()
}
- mediaDataManager.onNotificationAdded(KEY, notifWithAction)
+ mediaDataProcessor.onNotificationAdded(KEY, notifWithAction)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
@@ -1850,7 +1873,7 @@
)
// update to remote cast
- mediaDataManager.onNotificationAdded(KEY, remoteCastNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, remoteCastNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(logger)
@@ -1901,7 +1924,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
- mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(token = null))
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, data.copy(token = null))
// And then get a state update
val state = PlaybackState.Builder().build()
@@ -1949,7 +1972,7 @@
// Add resumption controls in order to have semantic actions.
// To make sure that they are not null after changing state.
- mediaDataManager.addResumptionControls(
+ mediaDataProcessor.addResumptionControls(
USER_ID,
desc,
Runnable {},
@@ -2040,9 +2063,9 @@
// When a media control based on notification is added, times out, and then removed
addNotificationAndLoad()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
assertThat(mediaDataCaptor.value.active).isFalse()
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// It is converted to a resume player
verify(listener)
@@ -2070,7 +2093,7 @@
// When a media control based on notification is added and times out
addNotificationAndLoad()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
assertThat(mediaDataCaptor.value.active).isFalse()
// and then the session is destroyed
@@ -2090,7 +2113,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// It is fully removed
verify(listener).onMediaDataRemoved(eq(KEY))
@@ -2106,10 +2129,10 @@
// When a media control that supports resumption is added
addNotificationAndLoad()
val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
- mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataResumable)
// And then removed while still active
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// It is converted to a resume player
verify(listener)
@@ -2142,8 +2165,8 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// It remains as a regular player
verify(listener, never()).onMediaDataRemoved(eq(KEY))
@@ -2162,7 +2185,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
sessionCallbackCaptor.value.invoke(KEY)
// It is converted to a resume player
@@ -2214,7 +2237,7 @@
// When a media control using session actions and that does allow resumption is added,
addNotificationAndLoad()
val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
- mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataResumable)
// And then the session is destroyed without timing out first
sessionCallbackCaptor.value.invoke(KEY)
@@ -2249,7 +2272,7 @@
addNotificationAndLoad()
val data = mediaDataCaptor.value
assertThat(data.active).isTrue()
- mediaDataManager.setTimedOut(KEY, timedOut = true)
+ mediaDataProcessor.setInactive(KEY, timedOut = true)
sessionCallbackCaptor.value.invoke(KEY)
// It is fully removed.
@@ -2293,7 +2316,7 @@
// When a media control using session actions and that does allow resumption is added,
addNotificationAndLoad()
val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
- mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+ mediaDataProcessor.onMediaDataLoaded(KEY, null, dataResumable)
// And then the session is destroyed without timing out first
sessionCallbackCaptor.value.invoke(KEY)
@@ -2324,9 +2347,9 @@
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
// When a notiifcation is added and then removed before it is fully processed
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
backgroundExecutor.runAllReady()
- mediaDataManager.onNotificationRemoved(KEY)
+ mediaDataProcessor.onNotificationRemoved(KEY)
// We still make sure to remove it
verify(listener).onMediaDataRemoved(eq(KEY))
@@ -2399,7 +2422,7 @@
/** Helper function to add the given notification and capture the resulting MediaData */
private fun addNotificationAndLoad(sbn: StatusBarNotification) {
- mediaDataManager.onNotificationAdded(KEY, sbn)
+ mediaDataProcessor.onNotificationAdded(KEY, sbn)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
@@ -2426,7 +2449,7 @@
desc: MediaDescription,
packageName: String = PACKAGE_NAME
) {
- mediaDataManager.addResumptionControls(
+ mediaDataProcessor.addResumptionControls(
USER_ID,
desc,
Runnable {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
index 7f3d79f..a447e44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
@@ -41,7 +41,6 @@
import com.android.settingslib.media.MediaDevice
import com.android.settingslib.media.PhoneMediaDevice
import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
@@ -98,7 +97,6 @@
@Mock private lateinit var muteAwaitManager: MediaMuteAwaitConnectionManager
private lateinit var fakeFgExecutor: FakeExecutor
private lateinit var fakeBgExecutor: FakeExecutor
- @Mock private lateinit var dumpster: DumpManager
@Mock private lateinit var listener: MediaDeviceManager.Listener
@Mock private lateinit var device: MediaDevice
@Mock private lateinit var icon: Drawable
@@ -133,7 +131,6 @@
{ localBluetoothManager },
fakeFgExecutor,
fakeBgExecutor,
- dumpster,
)
manager.addListener(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
index 9f5260c..37dea11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media.controls.ui.controller
-import android.provider.Settings
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -37,8 +36,6 @@
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.FakeSettings
-import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import org.junit.Before
@@ -65,10 +62,7 @@
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
private val hostView = UniqueObjectHostView(context)
- private val settings = FakeSettings()
private lateinit var keyguardMediaController: KeyguardMediaController
- private lateinit var testableLooper: TestableLooper
- private lateinit var fakeHandler: FakeHandler
private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@Before
@@ -84,16 +78,12 @@
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(mediaHost.hostView).thenReturn(hostView)
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
- testableLooper = TestableLooper.get(this)
- fakeHandler = FakeHandler(testableLooper.looper)
keyguardMediaController =
KeyguardMediaController(
mediaHost,
bypassController,
statusBarStateController,
context,
- settings,
- fakeHandler,
configurationController,
ResourcesSplitShadeStateController(),
mock<KeyguardMediaControllerLogger>(),
@@ -126,24 +116,6 @@
}
@Test
- fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
-
- keyguardMediaController.refreshMediaPosition(TEST_REASON)
-
- assertThat(mediaContainerView.visibility).isEqualTo(GONE)
- }
-
- @Test
- fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
-
- keyguardMediaController.refreshMediaPosition(TEST_REASON)
-
- assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
- }
-
- @Test
fun testActivatesSplitShadeContainerInSplitShadeMode() {
val splitShadeContainer = FrameLayout(context)
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
index f755199..c3daf84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
@@ -34,14 +34,13 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.domain.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaData
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
import com.android.systemui.media.controls.ui.view.MediaHostState
import com.android.systemui.media.controls.ui.view.MediaScrollView
@@ -60,7 +59,9 @@
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.settings.FakeSettings
import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.time.FakeSystemClock
import java.util.Locale
import javax.inject.Provider
@@ -68,6 +69,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -111,13 +113,12 @@
@Mock lateinit var logger: MediaUiEventLogger
@Mock lateinit var debugLogger: MediaCarouselControllerLogger
@Mock lateinit var mediaViewController: MediaViewController
- @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
@Mock lateinit var mediaCarousel: MediaScrollView
@Mock lateinit var pageIndicator: PageIndicator
@Mock lateinit var mediaFlags: MediaFlags
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock lateinit var globalSettings: GlobalSettings
+ private lateinit var secureSettings: SecureSettings
private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor
@@ -129,13 +130,16 @@
private val clock = FakeSystemClock()
private lateinit var bgExecutor: FakeExecutor
+ private lateinit var testDispatcher: TestDispatcher
private lateinit var mediaCarouselController: MediaCarouselController
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ secureSettings = FakeSettings()
context.resources.configuration.setLocales(LocaleList(Locale.US, Locale.UK))
bgExecutor = FakeExecutor(clock)
+ testDispatcher = UnconfinedTestDispatcher()
mediaCarouselController =
MediaCarouselController(
context,
@@ -146,6 +150,7 @@
clock,
executor,
bgExecutor,
+ testDispatcher,
mediaDataManager,
configurationController,
falsingManager,
@@ -155,7 +160,8 @@
mediaFlags,
keyguardUpdateMonitor,
kosmos.keyguardTransitionInteractor,
- globalSettings
+ globalSettings,
+ secureSettings,
)
verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener))
@@ -165,7 +171,6 @@
verify(mediaHostStatesManager).addCallback(capture(hostStateCallback))
whenever(mediaControlPanelFactory.get()).thenReturn(panel)
whenever(panel.mediaViewController).thenReturn(mediaViewController)
- whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
MediaPlayerData.clear()
verify(globalSettings)
@@ -810,7 +815,9 @@
@ExperimentalCoroutinesApi
@Test
fun testKeyguardGone_showMediaCarousel() =
- runTest(UnconfinedTestDispatcher()) {
+ kosmos.testScope.runTest {
+ var updatedVisibility = false
+ mediaCarouselController.updateHostVisibility = { updatedVisibility = true }
mediaCarouselController.mediaCarousel = mediaCarousel
val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this)
@@ -821,10 +828,64 @@
)
verify(mediaCarousel).visibility = View.VISIBLE
+ assertEquals(true, updatedVisibility)
+ assertEquals(false, mediaCarouselController.isLockedAndHidden())
job.cancel()
}
+ @ExperimentalCoroutinesApi
+ @Test
+ fun keyguardShowing_notAllowedOnLockscreen_updateVisibility() {
+ kosmos.testScope.runTest {
+ var updatedVisibility = false
+ mediaCarouselController.updateHostVisibility = { updatedVisibility = true }
+ mediaCarouselController.mediaCarousel = mediaCarousel
+
+ val settingsJob = mediaCarouselController.listenForLockscreenSettingChanges(this)
+ secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
+
+ val keyguardJob = mediaCarouselController.listenForAnyStateToLockscreenTransition(this)
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.GONE,
+ to = KeyguardState.LOCKSCREEN,
+ this
+ )
+
+ assertEquals(true, updatedVisibility)
+ assertEquals(true, mediaCarouselController.isLockedAndHidden())
+
+ settingsJob.cancel()
+ keyguardJob.cancel()
+ }
+ }
+
+ @ExperimentalCoroutinesApi
+ @Test
+ fun keyguardShowing_allowedOnLockscreen_updateVisibility() {
+ kosmos.testScope.runTest {
+ var updatedVisibility = false
+ mediaCarouselController.updateHostVisibility = { updatedVisibility = true }
+ mediaCarouselController.mediaCarousel = mediaCarousel
+
+ val settingsJob = mediaCarouselController.listenForLockscreenSettingChanges(this)
+ secureSettings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true)
+
+ val keyguardJob = mediaCarouselController.listenForAnyStateToLockscreenTransition(this)
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.GONE,
+ to = KeyguardState.LOCKSCREEN,
+ this
+ )
+
+ assertEquals(true, updatedVisibility)
+ assertEquals(false, mediaCarouselController.isLockedAndHidden())
+
+ settingsJob.cancel()
+ keyguardJob.cancel()
+ }
+ }
+
@Test
fun testInvisibleToUserAndExpanded_playersNotListening() {
// Add players to carousel.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
index aa54565..6e0919f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
@@ -28,9 +28,10 @@
import android.view.ViewConfiguration
import android.view.WindowManager
import androidx.test.filters.SmallTest
-import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
+import com.android.systemui.jank.interactionJankMonitor
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.NavigationEdgeBackPlugin
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -41,10 +42,8 @@
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
-import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -62,16 +61,13 @@
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var latencyTracker: LatencyTracker
- @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor
+ private val interactionJankMonitor = Kosmos().interactionJankMonitor
@Mock private lateinit var layoutParams: WindowManager.LayoutParams
@Mock private lateinit var backCallback: NavigationEdgeBackPlugin.BackCallback
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- `when`(interactionJankMonitor.begin(any(), anyInt())).thenReturn(true)
- `when`(interactionJankMonitor.end(anyInt())).thenReturn(true)
- `when`(interactionJankMonitor.cancel(anyInt())).thenReturn(true)
mBackPanelController =
BackPanelController(
context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index 761c411..37654d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.recordissue.IssueRecordingState
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.res.R
import com.android.systemui.settings.UserContextProvider
@@ -74,6 +75,7 @@
@Mock private lateinit var dialog: SystemUIDialog
private lateinit var testableLooper: TestableLooper
+ private val issueRecordingState = IssueRecordingState()
private lateinit var tile: RecordIssueTile
@Before
@@ -100,13 +102,14 @@
dialogLauncherAnimator,
panelInteractor,
userContextProvider,
+ issueRecordingState,
delegateFactory,
)
}
@Test
fun qsTileUi_shouldLookCorrect_whenInactive() {
- tile.isRecording = false
+ issueRecordingState.isRecording = false
val testState = tile.newTileState()
tile.handleUpdateState(testState, null)
@@ -118,8 +121,7 @@
@Test
fun qsTileUi_shouldLookCorrect_whenRecording() {
- tile.isRecording = true
-
+ issueRecordingState.isRecording = true
val testState = tile.newTileState()
tile.handleUpdateState(testState, null)
@@ -130,7 +132,7 @@
@Test
fun inActiveQsTile_switchesToActive_whenClicked() {
- tile.isRecording = false
+ issueRecordingState.isRecording = false
val testState = tile.newTileState()
tile.handleUpdateState(testState, null)
@@ -140,7 +142,7 @@
@Test
fun activeQsTile_switchesToInActive_whenClicked() {
- tile.isRecording = true
+ issueRecordingState.isRecording = true
val testState = tile.newTileState()
tile.handleUpdateState(testState, null)
@@ -150,7 +152,8 @@
@Test
fun showPrompt_shouldUseKeyguardDismissUtil_ToShowDialog() {
- tile.isRecording = false
+ issueRecordingState.isRecording = false
+
tile.handleClick(null)
testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
index 3710713..036d3c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
@@ -16,22 +16,25 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
-import android.content.pm.UserInfo
+import android.bluetooth.BluetoothAdapter
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.settings.FakeSettings
-import com.google.common.truth.Truth
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import kotlin.test.Test
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -41,8 +44,17 @@
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
- private var secureSettings: FakeSettings = FakeSettings()
- private val userRepository: FakeUserRepository = FakeUserRepository()
+ private val bluetoothAdapter =
+ mock<BluetoothAdapter> {
+ var autoOn = false
+ whenever(isAutoOnEnabled).thenAnswer { autoOn }
+
+ whenever(setAutoOnEnabled(anyBoolean())).thenAnswer { invocation ->
+ autoOn = invocation.getArgument(0) as Boolean
+ autoOn
+ }
+ }
+ @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor
@Before
@@ -50,49 +62,35 @@
bluetoothAutoOnInteractor =
BluetoothAutoOnInteractor(
BluetoothAutoOnRepository(
- secureSettings,
- userRepository,
+ localBluetoothManager,
+ bluetoothAdapter,
testScope.backgroundScope,
- testDispatcher
+ testDispatcher,
)
)
}
@Test
- fun testSet_bluetoothAutoOnUnset_doNothing() {
+ fun testSetEnabled_bluetoothAutoOnUnsupported_doNothing() {
testScope.runTest {
+ whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(false)
+
bluetoothAutoOnInteractor.setEnabled(true)
-
- val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
-
runCurrent()
- Truth.assertThat(actualValue).isEqualTo(false)
+ assertFalse(bluetoothAdapter.isAutoOnEnabled)
}
}
@Test
- fun testSet_bluetoothAutoOnSet_setNewValue() {
+ fun testSetEnabled_bluetoothAutoOnSupported_setNewValue() {
testScope.runTest {
- userRepository.setUserInfos(listOf(SYSTEM_USER))
- secureSettings.putIntForUser(
- BluetoothAutoOnRepository.SETTING_NAME,
- BluetoothAutoOnInteractor.DISABLED,
- SYSTEM_USER_ID
- )
+ whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+
bluetoothAutoOnInteractor.setEnabled(true)
-
- val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
-
runCurrent()
- Truth.assertThat(actualValue).isEqualTo(true)
+ assertTrue(bluetoothAdapter.isAutoOnEnabled)
}
}
-
- companion object {
- private const val SYSTEM_USER_ID = 0
- private val SYSTEM_USER =
- UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
index cd1452a..3119284 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
@@ -16,18 +16,14 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
-import android.content.pm.UserInfo
-import android.os.UserHandle
+import android.bluetooth.BluetoothAdapter
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.BluetoothEventManager
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.DISABLED
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.ENABLED
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.SETTING_NAME
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.UNSET
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -37,6 +33,7 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -46,83 +43,57 @@
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
- private var secureSettings: FakeSettings = FakeSettings()
- private val userRepository: FakeUserRepository = FakeUserRepository()
+ @Mock private lateinit var bluetoothAdapter: BluetoothAdapter
+ @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+ @Mock private lateinit var eventManager: BluetoothEventManager
private lateinit var bluetoothAutoOnRepository: BluetoothAutoOnRepository
@Before
fun setUp() {
+ whenever(localBluetoothManager.eventManager).thenReturn(eventManager)
bluetoothAutoOnRepository =
BluetoothAutoOnRepository(
- secureSettings,
- userRepository,
+ localBluetoothManager,
+ bluetoothAdapter,
testScope.backgroundScope,
- testDispatcher
+ testDispatcher,
)
-
- userRepository.setUserInfos(listOf(SECONDARY_USER, SYSTEM_USER))
}
@Test
- fun testGetValue_valueUnset() {
+ fun testIsAutoOn_returnFalse() {
testScope.runTest {
- userRepository.setSelectedUserInfo(SYSTEM_USER)
+ whenever(bluetoothAdapter.isAutoOnEnabled).thenReturn(false)
val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
runCurrent()
- assertThat(actualValue).isEqualTo(UNSET)
- assertThat(bluetoothAutoOnRepository.isValuePresent()).isFalse()
+ assertThat(actualValue).isEqualTo(false)
}
}
@Test
- fun testGetValue_valueFalse() {
+ fun testIsAutoOn_returnTrue() {
testScope.runTest {
- userRepository.setSelectedUserInfo(SYSTEM_USER)
+ whenever(bluetoothAdapter.isAutoOnEnabled).thenReturn(true)
val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
- secureSettings.putIntForUser(SETTING_NAME, DISABLED, UserHandle.USER_SYSTEM)
runCurrent()
- assertThat(actualValue).isEqualTo(DISABLED)
+ assertThat(actualValue).isEqualTo(true)
}
}
@Test
- fun testGetValue_valueTrue() {
+ fun testIsAutoOnSupported_returnTrue() {
testScope.runTest {
- userRepository.setSelectedUserInfo(SYSTEM_USER)
- val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
+ whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+ val actualValue = bluetoothAutoOnRepository.isAutoOnSupported()
- secureSettings.putIntForUser(SETTING_NAME, ENABLED, UserHandle.USER_SYSTEM)
runCurrent()
- assertThat(actualValue).isEqualTo(ENABLED)
+ assertThat(actualValue).isEqualTo(true)
}
}
-
- @Test
- fun testGetValue_valueTrue_secondaryUser_returnTrue() {
- testScope.runTest {
- userRepository.setSelectedUserInfo(SECONDARY_USER)
- val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
-
- secureSettings.putIntForUser(SETTING_NAME, DISABLED, SYSTEM_USER_ID)
- secureSettings.putIntForUser(SETTING_NAME, ENABLED, SECONDARY_USER_ID)
- runCurrent()
-
- assertThat(actualValue).isEqualTo(ENABLED)
- }
- }
-
- companion object {
- private const val SYSTEM_USER_ID = 0
- private const val SECONDARY_USER_ID = 1
- private val SYSTEM_USER =
- UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
- private val SECONDARY_USER =
- UserInfo(/* id= */ SECONDARY_USER_ID, /* name= */ "secondary user", /* flags= */ 0)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
index 8ecb953..17b6127 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
@@ -109,7 +109,6 @@
mBluetoothTileDialogDelegate =
BluetoothTileDialogDelegate(
- mContext,
uiProperties,
CONTENT_HEIGHT,
ENABLED,
@@ -119,14 +118,12 @@
fakeSystemClock,
uiEventLogger,
logger,
- sysuiDialogFactory,
- LayoutInflater.from(mContext)
+ sysuiDialogFactory
)
whenever(
sysuiDialogFactory.create(
- any(SystemUIDialog.Delegate::class.java),
- any(Context::class.java)
+ any(SystemUIDialog.Delegate::class.java)
)
)
.thenAnswer {
@@ -216,7 +213,6 @@
LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
val viewHolder =
BluetoothTileDialogDelegate(
- mContext,
uiProperties,
CONTENT_HEIGHT,
ENABLED,
@@ -227,7 +223,6 @@
uiEventLogger,
logger,
sysuiDialogFactory,
- LayoutInflater.from(mContext)
)
.Adapter(bluetoothTileDialogCallback)
.DeviceItemViewHolder(view)
@@ -273,7 +268,6 @@
val cachedHeight = Int.MAX_VALUE
val dialog =
BluetoothTileDialogDelegate(
- mContext,
BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
cachedHeight,
ENABLED,
@@ -284,7 +278,6 @@
uiEventLogger,
logger,
sysuiDialogFactory,
- LayoutInflater.from(mContext)
)
.createDialog()
dialog.show()
@@ -298,7 +291,6 @@
testScope.runTest {
val dialog =
BluetoothTileDialogDelegate(
- mContext,
BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
MATCH_PARENT,
ENABLED,
@@ -309,7 +301,6 @@
uiEventLogger,
logger,
sysuiDialogFactory,
- LayoutInflater.from(mContext)
)
.createDialog()
dialog.show()
@@ -323,7 +314,6 @@
testScope.runTest {
val dialog =
BluetoothTileDialogDelegate(
- mContext,
BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
MATCH_PARENT,
ENABLED,
@@ -334,7 +324,6 @@
uiEventLogger,
logger,
sysuiDialogFactory,
- LayoutInflater.from(mContext)
)
.createDialog()
dialog.show()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index 39e2413..c8a2aa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
-import android.content.pm.UserInfo
+import android.bluetooth.BluetoothAdapter
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -26,19 +26,18 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.flags.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.kotlin.getMutableStateFlow
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineDispatcher
@@ -75,6 +74,8 @@
@Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor
+ @Mock private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor
+
@Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
@Mock private lateinit var activityStarter: ActivityStarter
@@ -87,6 +88,10 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var bluetoothAdapter: BluetoothAdapter
+
+ @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+
@Mock
private lateinit var mBluetoothTileDialogDelegateDelegateFactory:
BluetoothTileDialogDelegate.Factory
@@ -100,8 +105,6 @@
private lateinit var scheduler: TestCoroutineScheduler
private lateinit var dispatcher: CoroutineDispatcher
private lateinit var testScope: TestScope
- private lateinit var secureSettings: FakeSettings
- private lateinit var userRepository: FakeUserRepository
@Before
fun setUp() {
@@ -109,14 +112,6 @@
scheduler = TestCoroutineScheduler()
dispatcher = UnconfinedTestDispatcher(scheduler)
testScope = TestScope(dispatcher)
- secureSettings = FakeSettings()
- userRepository = FakeUserRepository()
- userRepository.setUserInfos(listOf(SYSTEM_USER))
- secureSettings.putIntForUser(
- BluetoothAutoOnRepository.SETTING_NAME,
- BluetoothAutoOnInteractor.ENABLED,
- SYSTEM_USER_ID
- )
bluetoothTileDialogViewModel =
BluetoothTileDialogViewModel(
deviceItemInteractor,
@@ -124,8 +119,8 @@
// TODO(b/316822488): Create FakeBluetoothAutoOnInteractor.
BluetoothAutoOnInteractor(
BluetoothAutoOnRepository(
- secureSettings,
- userRepository,
+ localBluetoothManager,
+ bluetoothAdapter,
testScope.backgroundScope,
dispatcher
)
@@ -148,7 +143,6 @@
whenever(
mBluetoothTileDialogDelegateDelegateFactory.create(
any(),
- any(),
anyInt(),
ArgumentMatchers.anyBoolean(),
any(),
@@ -157,6 +151,7 @@
)
.thenReturn(bluetoothTileDialogDelegate)
whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog)
+ whenever(sysuiDialog.context).thenReturn(mContext)
whenever(bluetoothTileDialogDelegate.bluetoothStateToggle)
.thenReturn(getMutableStateFlow(false))
whenever(bluetoothTileDialogDelegate.deviceItemClick)
@@ -169,7 +164,7 @@
@Test
fun testShowDialog_noAnimation() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDialog(context, null)
+ bluetoothTileDialogViewModel.showDialog(null)
verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any())
}
@@ -178,7 +173,7 @@
@Test
fun testShowDialog_animated() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDialog(mContext, LinearLayout(mContext))
+ bluetoothTileDialogViewModel.showDialog(LinearLayout(mContext))
verify(mDialogTransitionAnimator).showFromView(any(), any(), nullable(), anyBoolean())
}
@@ -188,7 +183,7 @@
fun testShowDialog_animated_callInBackgroundThread() {
testScope.runTest {
backgroundExecutor.execute {
- bluetoothTileDialogViewModel.showDialog(mContext, LinearLayout(mContext))
+ bluetoothTileDialogViewModel.showDialog(LinearLayout(mContext))
verify(mDialogTransitionAnimator)
.showFromView(any(), any(), nullable(), anyBoolean())
@@ -199,7 +194,7 @@
@Test
fun testShowDialog_fetchDeviceItem() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDialog(context, null)
+ bluetoothTileDialogViewModel.showDialog(null)
verify(deviceItemInteractor).deviceItemUpdate
}
@@ -208,7 +203,7 @@
@Test
fun testShowDialog_withBluetoothStateValue() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDialog(context, null)
+ bluetoothTileDialogViewModel.showDialog(null)
verify(bluetoothStateInteractor).bluetoothStateUpdate
}
@@ -218,7 +213,7 @@
fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
testScope.runTest {
whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
- bluetoothTileDialogViewModel.showDialog(context, null)
+ bluetoothTileDialogViewModel.showDialog(null)
val clickedView = View(context)
bluetoothTileDialogViewModel.onPairNewDeviceClicked(clickedView)
@@ -265,26 +260,22 @@
}
@Test
- fun testIsAutoOnToggleFeatureAvailable_flagOn_settingValueSet_returnTrue() {
+ fun testIsAutoOnToggleFeatureAvailable_returnTrue() {
testScope.runTest {
+ whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+
val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
assertThat(actual).isTrue()
}
}
@Test
- fun testIsAutoOnToggleFeatureAvailable_flagOff_settingValueSet_returnFalse() {
+ fun testIsAutoOnToggleFeatureAvailable_returnFalse() {
testScope.runTest {
- mSetFlagsRule.disableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
+ whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(false)
val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
assertThat(actual).isFalse()
}
}
-
- companion object {
- private const val SYSTEM_USER_ID = 0
- private val SYSTEM_USER =
- UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt
new file mode 100644
index 0000000..4215b8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.qs.tiles.impl.work.ui
+
+import android.app.admin.DevicePolicyResources
+import android.app.admin.DevicePolicyResourcesManager
+import android.app.admin.devicePolicyManager
+import android.graphics.drawable.TestStubDrawable
+import android.service.quicksettings.Tile
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.work.domain.model.WorkModeTileModel
+import com.android.systemui.qs.tiles.impl.work.qsWorkModeTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import com.android.systemui.util.mockito.any
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WorkModeTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val qsTileConfig = kosmos.qsWorkModeTileConfig
+ private val devicePolicyManager = kosmos.devicePolicyManager
+ private val testLabel = context.getString(R.string.quick_settings_work_mode_label)
+ private val devicePolicyResourceManager = mock<DevicePolicyResourcesManager>()
+ private lateinit var mapper: WorkModeTileMapper
+
+ @Before
+ fun setup() {
+ whenever(devicePolicyManager.resources).thenReturn(devicePolicyResourceManager)
+ whenever(
+ devicePolicyResourceManager.getString(
+ eq(DevicePolicyResources.Strings.SystemUi.QS_WORK_PROFILE_LABEL),
+ any()
+ )
+ )
+ .thenReturn(testLabel)
+ mapper =
+ WorkModeTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(
+ com.android.internal.R.drawable.stat_sys_managed_profile_status,
+ TestStubDrawable()
+ )
+ }
+ .resources,
+ context.theme,
+ devicePolicyManager
+ )
+ }
+
+ @Test
+ fun mapsDisabledDataToInactiveState() {
+ val isEnabled = false
+
+ val actualState: QSTileState =
+ mapper.map(qsTileConfig, WorkModeTileModel.HasActiveProfile(isEnabled))
+
+ val expectedState = createWorkModeTileState(QSTileState.ActivationState.INACTIVE)
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsEnabledDataToActiveState() {
+ val isEnabled = true
+
+ val actualState: QSTileState =
+ mapper.map(qsTileConfig, WorkModeTileModel.HasActiveProfile(isEnabled))
+
+ val expectedState = createWorkModeTileState(QSTileState.ActivationState.ACTIVE)
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsNoActiveProfileDataToUnavailableState() {
+ val actualState: QSTileState = mapper.map(qsTileConfig, WorkModeTileModel.NoActiveProfile)
+
+ val expectedState = createWorkModeTileState(QSTileState.ActivationState.UNAVAILABLE)
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ private fun createWorkModeTileState(
+ activationState: QSTileState.ActivationState,
+ ): QSTileState {
+ val label = testLabel
+ return QSTileState(
+ icon = {
+ Icon.Loaded(
+ context.getDrawable(
+ com.android.internal.R.drawable.stat_sys_managed_profile_status
+ )!!,
+ null
+ )
+ },
+ label = label,
+ activationState = activationState,
+ secondaryLabel =
+ if (activationState == QSTileState.ActivationState.INACTIVE) {
+ context.getString(R.string.quick_settings_work_mode_paused_state)
+ } else if (activationState == QSTileState.ActivationState.UNAVAILABLE) {
+ context.resources
+ .getStringArray(R.array.tile_states_work)[Tile.STATE_UNAVAILABLE]
+ } else {
+ ""
+ },
+ supportedActions =
+ if (activationState == QSTileState.ActivationState.UNAVAILABLE) {
+ setOf()
+ } else {
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ },
+ contentDescription = label,
+ stateDescription = null,
+ sideViewIcon = QSTileState.SideViewIcon.None,
+ enabledState = QSTileState.EnabledState.ENABLED,
+ expandedAccessibilityClassName = Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index 2e8160b..1cfca68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -222,4 +222,9 @@
)
verify(factory, never()).create(any<ScreenCapturePermissionDialogDelegate>())
}
+
+ @Test
+ fun startButton_isDisabled_beforeIssueTypeIsSelected() {
+ assertThat(dialog.getButton(Dialog.BUTTON_POSITIVE).isEnabled).isFalse()
+ }
}
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 43fcdf3..24c9d6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -62,7 +62,6 @@
import androidx.constraintlayout.widget.ConstraintSet;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -299,7 +298,6 @@
@Mock protected RecordingController mRecordingController;
@Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
@Mock protected DumpManager mDumpManager;
- @Mock protected InteractionJankMonitor mInteractionJankMonitor;
@Mock protected NotificationsQSContainerController mNotificationsQSContainerController;
@Mock protected QsFrameTranslateController mQsFrameTranslateController;
@Mock protected StatusBarWindowStateController mStatusBarWindowStateController;
@@ -441,11 +439,12 @@
SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(
mUiEventLogger,
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mJavaAdapter,
() -> mShadeInteractor,
() -> mKosmos.getDeviceUnlockedInteractor(),
- () -> mKosmos.getSceneInteractor());
+ () -> mKosmos.getSceneInteractor(),
+ () -> mKosmos.getKeyguardClockInteractor());
KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
keyguardStatusView.setId(R.id.keyguard_status_view);
@@ -459,7 +458,7 @@
mDozeParameters,
mScreenOffAnimationController,
mKeyguardLogger,
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mKeyguardInteractor,
mDumpManager,
mPowerInteractor));
@@ -611,11 +610,12 @@
mock(HeadsUpManager.class),
new StatusBarStateControllerImpl(
new UiEventLoggerFake(),
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mJavaAdapter,
() -> mShadeInteractor,
() -> mKosmos.getDeviceUnlockedInteractor(),
- () -> mKosmos.getSceneInteractor()),
+ () -> mKosmos.getSceneInteractor(),
+ () -> mKosmos.getKeyguardClockInteractor()),
mKeyguardBypassController,
mDozeParameters,
mScreenOffAnimationController,
@@ -651,10 +651,6 @@
.thenReturn(mKeyguardBottomArea);
when(mNotificationRemoteInputManager.isRemoteInputActive())
.thenReturn(false);
- when(mInteractionJankMonitor.begin(any(), anyInt()))
- .thenReturn(true);
- when(mInteractionJankMonitor.end(anyInt()))
- .thenReturn(true);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -717,7 +713,6 @@
mFragmentService,
mStatusBarService,
mContentResolver,
- mShadeHeaderController,
mScreenOffAnimationController,
mLockscreenGestureLogger,
mShadeExpansionStateManager,
@@ -820,7 +815,7 @@
mAccessibilityManager,
mLockscreenGestureLogger,
mMetricsLogger,
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mShadeLog,
mDumpManager,
mDeviceEntryFaceAuthInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index f489937..433c95a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -111,7 +111,6 @@
ShadeControllerImpl(
commandQueue,
FakeExecutor(FakeSystemClock()),
- touchLog,
windowRootViewVisibilityInteractor,
keyguardStateController,
statusBarStateController,
@@ -119,7 +118,7 @@
statusBarWindowController,
deviceProvisionedController,
notificationShadeWindowController,
- windowManager,
+ 0,
Lazy { npvc },
Lazy { assistManager },
Lazy { gutsManager },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index d35c7dd..a92cf8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -21,7 +21,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
-import com.android.systemui.shade.ShadeLockscreenInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index dcd000a..f9e08fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -23,7 +23,6 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
-import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
@@ -39,6 +38,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -48,7 +48,9 @@
import com.android.systemui.keyguard.domain.interactor.fromGoneTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
@@ -80,15 +82,13 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyFloat
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -101,7 +101,6 @@
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromPrimaryBouncerTransitionInteractor:
FromPrimaryBouncerTransitionInteractor
- private val interactionJankMonitor = mock<InteractionJankMonitor>()
private val mockDarkAnimator = mock<ObjectAnimator>()
private val deviceEntryUdfpsInteractor = mock<DeviceEntryUdfpsInteractor>()
private val largeScreenHeaderHelper = mock<LargeScreenHeaderHelper>()
@@ -112,19 +111,18 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(interactionJankMonitor.begin(any(), anyInt())).thenReturn(true)
- whenever(interactionJankMonitor.end(anyInt())).thenReturn(true)
uiEventLogger = UiEventLoggerFake()
underTest =
object :
StatusBarStateControllerImpl(
uiEventLogger,
- interactionJankMonitor,
+ kosmos.interactionJankMonitor,
JavaAdapter(testScope.backgroundScope),
{ shadeInteractor },
{ kosmos.deviceUnlockedInteractor },
{ kosmos.sceneInteractor },
+ { kosmos.keyguardClockInteractor },
) {
override fun createDarkAnimator(): ObjectAnimator {
return mockDarkAnimator
@@ -343,10 +341,7 @@
assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)
- kosmos.sceneInteractor.changeScene(
- toScene = Scenes.Communal,
- loggingReason = "reason"
- )
+ kosmos.sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason")
runCurrent()
assertThat(currentScene).isEqualTo(Scenes.Communal)
assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
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 419b0fd..118d27a 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
@@ -251,7 +251,7 @@
mCollectionListener.onEntryInit(mEntry);
mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
verify(mNotifInflater).inflateViews(eq(mEntry), mParamsCaptor.capture(), any());
- assertFalse(mParamsCaptor.getValue().isLowPriority());
+ assertFalse(mParamsCaptor.getValue().isMinimized());
mNotifInflater.invokeInflateCallbackForEntry(mEntry);
// WHEN notification moves to a min priority section
@@ -260,7 +260,7 @@
// THEN we rebind it
verify(mNotifInflater).rebindViews(eq(mEntry), mParamsCaptor.capture(), any());
- assertTrue(mParamsCaptor.getValue().isLowPriority());
+ assertTrue(mParamsCaptor.getValue().isMinimized());
// THEN we do not filter it because it's not the first inflation.
assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
@@ -273,7 +273,7 @@
mCollectionListener.onEntryInit(mEntry);
mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
verify(mNotifInflater).inflateViews(eq(mEntry), mParamsCaptor.capture(), any());
- assertTrue(mParamsCaptor.getValue().isLowPriority());
+ assertTrue(mParamsCaptor.getValue().isMinimized());
mNotifInflater.invokeInflateCallbackForEntry(mEntry);
// WHEN notification is moved under a parent
@@ -282,7 +282,7 @@
// THEN we rebind it as not-minimized
verify(mNotifInflater).rebindViews(eq(mEntry), mParamsCaptor.capture(), any());
- assertFalse(mParamsCaptor.getValue().isLowPriority());
+ assertFalse(mParamsCaptor.getValue().isMinimized());
// THEN we do not filter it because it's not the first inflation.
assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index b114e13..0e89d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -741,7 +741,7 @@
when(mockViewWrapper.getIcon()).thenReturn(mockIcon);
NotificationViewWrapper mockLowPriorityViewWrapper = mock(NotificationViewWrapper.class);
- when(mockContainer.getLowPriorityViewWrapper()).thenReturn(mockLowPriorityViewWrapper);
+ when(mockContainer.getMinimizedGroupHeaderWrapper()).thenReturn(mockLowPriorityViewWrapper);
CachingIconView mockLowPriorityIcon = mock(CachingIconView.class);
when(mockLowPriorityViewWrapper.getIcon()).thenReturn(mockLowPriorityIcon);
@@ -845,7 +845,6 @@
}
@Test
- @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATION_ROW_USER_CONTEXT)
public void imageResolver_differentNotificationUser_createsUserContext() throws Exception {
UserHandle user = new UserHandle(33);
Context userContext = new SysuiTestableContext(mContext);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index a0d1075..8c22511 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -231,6 +231,7 @@
NotificationContentInflater.applyRemoteView(
AsyncTask.SERIAL_EXECUTOR,
false /* inflateSynchronously */,
+ /* isMinimized= */ false,
result,
FLAG_CONTENT_VIEW_EXPANDED,
0,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 6549193..fe0d9d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -23,6 +23,7 @@
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static com.android.systemui.concurrency.FakeExecutorKosmosKt.getFakeExecutor;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static junit.framework.Assert.assertNotNull;
@@ -124,12 +125,11 @@
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
- private KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
- private TestScope mTestScope = mKosmos.getTestScope();
- private JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
- private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
- private TestableLooper mTestableLooper;
- private Handler mHandler;
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+ private final TestScope mTestScope = mKosmos.getTestScope();
+ private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
+ private final FakeExecutor mExecutor = mKosmos.getFakeExecutor();
+ private final Handler mHandler = mKosmos.getFakeExecutorHandler();
private NotificationTestHelper mHelper;
private NotificationGutsManager mGutsManager;
@@ -171,10 +171,8 @@
@Before
public void setUp() {
- mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
- mHandler = Handler.createAsync(mTestableLooper.getLooper());
- mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
+ mHelper = new NotificationTestHelper(mContext, mDependency);
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
@@ -248,7 +246,7 @@
assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
assertEquals(View.INVISIBLE, guts.getVisibility());
- mTestableLooper.processAllMessages();
+ mExecutor.runAllReady();
verify(guts).openControls(
anyInt(),
anyInt(),
@@ -261,7 +259,7 @@
verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
verify(row, times(1)).setGutsView(any());
- mTestableLooper.processAllMessages();
+ mExecutor.runAllReady();
verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
}
@@ -352,7 +350,7 @@
when(entry.getGuts()).thenReturn(guts);
assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
- mTestableLooper.processAllMessages();
+ mExecutor.runAllReady();
verify(guts).openControls(
anyInt(),
anyInt(),
@@ -365,7 +363,7 @@
row.onDensityOrFontScaleChanged();
mGutsManager.onDensityOrFontScaleChanged(entry);
- mTestableLooper.processAllMessages();
+ mExecutor.runAllReady();
mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 012ff2e..65a960b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -27,12 +27,11 @@
import android.content.pm.launcherApps
import android.graphics.Color
import android.os.Binder
-import android.os.Handler
+import android.os.fakeExecutorHandler
import android.os.userManager
import android.provider.Settings
import android.service.notification.NotificationListenerService.Ranking
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.util.ArraySet
import android.view.View
@@ -45,6 +44,7 @@
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.statusbar.statusBarService
import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
@@ -71,9 +71,7 @@
import com.android.systemui.statusbar.policy.deviceProvisionedController
import com.android.systemui.statusbar.policy.headsUpManager
import com.android.systemui.testKosmos
-import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.kotlin.JavaAdapter
-import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.wmshell.BubblesManager
import java.util.Optional
import junit.framework.Assert
@@ -106,9 +104,8 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val javaAdapter = JavaAdapter(testScope.backgroundScope)
- private val executor = FakeExecutor(FakeSystemClock())
- private lateinit var testableLooper: TestableLooper
- private lateinit var handler: Handler
+ private val executor = kosmos.fakeExecutor
+ private val handler = kosmos.fakeExecutorHandler
private lateinit var helper: NotificationTestHelper
private lateinit var gutsManager: NotificationGutsManager
private lateinit var windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor
@@ -148,10 +145,8 @@
MockitoAnnotations.initMocks(this)
val sceneContainerFlags = kosmos.fakeSceneContainerFlags
sceneContainerFlags.enabled = true
- testableLooper = TestableLooper.get(this)
allowTestableLooperAsMainThread()
- handler = Handler.createAsync(testableLooper.getLooper())
- helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ helper = NotificationTestHelper(mContext, mDependency)
Mockito.`when`(accessibilityManager.isTouchExplorationEnabled).thenReturn(false)
windowRootViewVisibilityInteractor =
WindowRootViewVisibilityInteractor(
@@ -227,7 +222,7 @@
Mockito.`when`(row.guts).thenReturn(guts)
Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
- testableLooper.processAllMessages()
+ executor.runAllReady()
verify(guts)
.openControls(
ArgumentMatchers.anyInt(),
@@ -247,7 +242,7 @@
ArgumentMatchers.anyBoolean()
)
verify(row, Mockito.times(1)).setGutsView(ArgumentMatchers.any())
- testableLooper.processAllMessages()
+ executor.runAllReady()
verify(headsUpManager).setGutsShown(realRow.entry, false)
}
@@ -343,7 +338,7 @@
Mockito.`when`(entry.row).thenReturn(row)
Mockito.`when`(entry.getGuts()).thenReturn(guts)
Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
- testableLooper.processAllMessages()
+ executor.runAllReady()
verify(guts)
.openControls(
ArgumentMatchers.anyInt(),
@@ -356,7 +351,7 @@
verify(row).setGutsView(ArgumentMatchers.any())
row.onDensityOrFontScaleChanged()
gutsManager.onDensityOrFontScaleChanged(entry)
- testableLooper.processAllMessages()
+ executor.runAllReady()
gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false)
verify(guts)
.closeControls(
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 09a3eb48..954335e 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
@@ -615,10 +615,8 @@
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- if (com.android.systemui.Flags.notificationRowUserContext()) {
- inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock,
- mRowInflaterTaskLogger));
- }
+ inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock,
+ mRowInflaterTaskLogger));
mRow = (ExpandableNotificationRow) inflater.inflate(
R.layout.status_bar_notification_row,
null /* root */,
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 76470db..1534c84 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
@@ -197,7 +197,7 @@
params.clearDirtyContentViews();
// WHEN low priority is set and stage executed.
- params.setUseLowPriority(true);
+ params.setUseMinimized(true);
mRowContentBindStage.executeStage(mEntry, mRow, (en) -> { });
// THEN binder is called with use low priority and contracted/expanded are called to bind.
@@ -210,7 +210,7 @@
anyBoolean(),
any());
BindParams usedParams = bindParamsCaptor.getValue();
- assertTrue(usedParams.isLowPriority);
+ assertTrue(usedParams.isMinimized);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
index 8f88501..a15b4cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -25,8 +25,6 @@
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
@@ -44,7 +42,6 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
-@RunWithLooper
public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
private View mView;
@@ -53,11 +50,7 @@
@Before
public void setup() throws Exception {
- allowTestableLooperAsMainThread();
- NotificationTestHelper helper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
+ NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
mView = LayoutInflater.from(mContext).inflate(
com.android.internal.R.layout.notification_template_material_big_picture, null);
mRow = helper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
index 3fa68bb..fe2971c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
@@ -18,8 +18,6 @@
import android.graphics.drawable.AnimatedImageDrawable
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.R
@@ -41,7 +39,6 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
class NotificationConversationTemplateViewWrapperTest : SysuiTestCase() {
private lateinit var mRow: ExpandableNotificationRow
@@ -49,8 +46,7 @@
@Before
fun setUp() {
- allowTestableLooperAsMainThread()
- helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ helper = NotificationTestHelper(mContext, mDependency)
mRow = helper.createRow()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 45f7c5a..2d72c7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.notification.row.wrapper;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.widget.RemoteViews;
@@ -36,18 +34,13 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
public class NotificationCustomViewWrapperTest extends SysuiTestCase {
private ExpandableNotificationRow mRow;
@Before
public void setUp() throws Exception {
- allowTestableLooperAsMainThread();
- NotificationTestHelper helper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
+ NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
mRow = helper.createRow();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
index c0444b5..f26c18b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
@@ -18,8 +18,6 @@
import android.graphics.drawable.AnimatedImageDrawable
import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.widget.MessagingGroup
@@ -39,7 +37,6 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
class NotificationMessagingTemplateViewWrapperTest : SysuiTestCase() {
private lateinit var mRow: ExpandableNotificationRow
@@ -47,8 +44,7 @@
@Before
fun setUp() {
- allowTestableLooperAsMainThread()
- helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ helper = NotificationTestHelper(mContext, mDependency)
mRow = helper.createRow()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
index f7632aa..54eed26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -69,7 +69,7 @@
TestUiOffloadThread(looper.looper)
)
- helper = NotificationTestHelper(mContext, mDependency, looper)
+ helper = NotificationTestHelper(mContext, mDependency)
row = helper.createRow()
// Some code in the view iterates through parents so we need some extra containers around
// it.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index 93a9e59..e3a77d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -39,7 +39,6 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
-@RunWithLooper
public class NotificationViewWrapperTest extends SysuiTestCase {
private View mView;
@@ -48,13 +47,9 @@
@Before
public void setup() throws Exception {
- allowTestableLooperAsMainThread();
mView = mock(View.class);
when(mView.getContext()).thenReturn(mContext);
- NotificationTestHelper helper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
+ NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
mRow = helper.createRow();
mNotificationViewWrapper = new TestableNotificationViewWrapper(mContext, mView, mRow);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 1f38a73..3b16f14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -67,7 +67,7 @@
@Test
public void testGetMaxAllowedVisibleChildren_lowPriority() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
}
@@ -81,7 +81,7 @@
@Test
public void testGetMaxAllowedVisibleChildren_lowPriority_expandedChildren() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
mChildrenContainer.setChildrenExpanded(true);
Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
@@ -89,7 +89,7 @@
@Test
public void testGetMaxAllowedVisibleChildren_lowPriority_userLocked() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
mChildrenContainer.setUserLocked(true);
Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED);
@@ -118,7 +118,7 @@
@Test
public void testShowingAsLowPriority_lowPriority() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
Assert.assertTrue(mChildrenContainer.showingAsLowPriority());
}
@@ -129,7 +129,7 @@
@Test
public void testShowingAsLowPriority_lowPriority_expanded() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
mGroup.setExpandable(true);
mGroup.setUserExpanded(true, false);
Assert.assertFalse(mChildrenContainer.showingAsLowPriority());
@@ -140,7 +140,7 @@
mGroup.setUserLocked(true);
mGroup.setExpandable(true);
mGroup.setUserExpanded(true);
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
}
@@ -148,14 +148,14 @@
@Test
@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
public void testLowPriorityHeaderCleared() {
- mGroup.setIsLowPriority(true);
+ mGroup.setIsMinimized(true);
NotificationHeaderView lowPriorityHeaderView =
- mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader();
+ mChildrenContainer.getMinimizedGroupHeaderWrapper().getNotificationHeader();
Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent());
- mGroup.setIsLowPriority(false);
+ mGroup.setIsMinimized(false);
assertNull(lowPriorityHeaderView.getParent());
- assertNull(mChildrenContainer.getLowPriorityViewWrapper());
+ assertNull(mChildrenContainer.getMinimizedGroupHeaderWrapper());
}
@Test
@@ -169,7 +169,7 @@
@Test
@EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
public void testSetLowPriorityWithAsyncInflation_noHeaderReInflation() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
assertNull("We don't inflate header from the main thread with Async "
+ "Inflation enabled", mChildrenContainer.getCurrentHeaderView());
}
@@ -179,21 +179,21 @@
public void setLowPriorityBeforeLowPriorityHeaderSet() {
//Given: the children container does not have a low-priority header, and is not low-priority
- assertNull(mChildrenContainer.getLowPriorityViewWrapper());
- mGroup.setIsLowPriority(false);
+ assertNull(mChildrenContainer.getMinimizedGroupHeaderWrapper());
+ mGroup.setIsMinimized(false);
//When: set the children container to be low-priority and set the low-priority header
- mGroup.setIsLowPriority(true);
- mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
+ mGroup.setIsMinimized(true);
+ mGroup.setMinimizedGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
//Then: the low-priority group header should be visible
NotificationHeaderView lowPriorityHeaderView =
- mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader();
+ mChildrenContainer.getMinimizedGroupHeaderWrapper().getNotificationHeader();
Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent());
//When: set the children container to be not low-priority and set the normal header
- mGroup.setIsLowPriority(false);
+ mGroup.setIsMinimized(false);
mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false));
//Then: the low-priority group header should not be visible , normal header should be
@@ -211,9 +211,9 @@
public void changeLowPriorityAfterHeaderSet() {
//Given: the children container does not have headers, and is not low-priority
- assertNull(mChildrenContainer.getLowPriorityViewWrapper());
+ assertNull(mChildrenContainer.getMinimizedGroupHeaderWrapper());
assertNull(mChildrenContainer.getNotificationHeaderWrapper());
- mGroup.setIsLowPriority(false);
+ mGroup.setIsMinimized(false);
//When: set the set the normal header
mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false));
@@ -225,14 +225,14 @@
Assert.assertSame(mChildrenContainer, headerView.getParent());
//When: set the set the row to be low priority, and set the low-priority header
- mGroup.setIsLowPriority(true);
- mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
+ mGroup.setIsMinimized(true);
+ mGroup.setMinimizedGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
//Then: the header view should not be visible, the low-priority group header should be
// visible
Assert.assertEquals(View.INVISIBLE, headerView.getVisibility());
NotificationHeaderView lowPriorityHeaderView =
- mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader();
+ mChildrenContainer.getMinimizedGroupHeaderWrapper().getNotificationHeader();
Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
}
@@ -263,7 +263,7 @@
@Test
@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() {
- mChildrenContainer.setIsLowPriority(true);
+ mChildrenContainer.setIsMinimized(true);
NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
Assert.assertEquals(0f, header.getTopRoundness(), 0.001f);
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 a4f88fb..10d2191 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
@@ -49,7 +49,6 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -63,6 +62,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -130,6 +130,7 @@
@RunWith(AndroidTestingRunner.class)
public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
+ protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock private NotificationGutsManager mNotificationGutsManager;
@Mock private NotificationsController mNotificationsController;
@@ -167,7 +168,6 @@
@Mock private SceneContainerFlags mSceneContainerFlags;
@Mock private Provider<WindowRootView> mWindowRootView;
@Mock private NotificationStackAppearanceInteractor mNotificationStackAppearanceInteractor;
- @Mock private InteractionJankMonitor mJankMonitor;
private final StackStateLogger mStackLogger = new StackStateLogger(logcatLogBuffer(),
logcatLogBuffer());
private final NotificationStackScrollLogger mLogger = new NotificationStackScrollLogger(
@@ -1030,7 +1030,7 @@
mSceneContainerFlags,
mWindowRootView,
mNotificationStackAppearanceInteractor,
- mJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mStackLogger,
mLogger,
mNotificationStackSizeCalculator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index 0a18eb6..c308a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -35,9 +35,13 @@
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.statusbar.data.repository.fakeRemoteInputRepository
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
+import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
+import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
+import com.android.systemui.statusbar.notification.stack.data.repository.setNotifications
import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
import com.android.systemui.statusbar.policy.fakeConfigurationController
@@ -70,6 +74,7 @@
private val fakeRemoteInputRepository = kosmos.fakeRemoteInputRepository
private val fakeShadeRepository = kosmos.fakeShadeRepository
private val fakeUserSetupRepository = kosmos.fakeUserSetupRepository
+ private val headsUpRepository = kosmos.headsUpNotificationRepository
private val zenModeRepository = kosmos.zenModeRepository
val underTest = kosmos.notificationListViewModel
@@ -125,35 +130,35 @@
}
@Test
- fun testShouldShowEmptyShadeView_trueWhenNoNotifs() =
+ fun testShouldIncludeEmptyShadeView_trueWhenNoNotifs() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
runCurrent()
// THEN empty shade is visible
- assertThat(shouldShow).isTrue()
+ assertThat(shouldInclude).isTrue()
}
@Test
- fun testShouldShowEmptyShadeView_falseWhenNotifs() =
+ fun testShouldIncludeEmptyShadeView_falseWhenNotifs() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
runCurrent()
// THEN empty shade is not visible
- assertThat(shouldShow).isFalse()
+ assertThat(shouldInclude).isFalse()
}
@Test
- fun testShouldShowEmptyShadeView_falseWhenQsExpandedDefault() =
+ fun testShouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -162,13 +167,13 @@
runCurrent()
// THEN empty shade is not visible
- assertThat(shouldShow).isFalse()
+ assertThat(shouldInclude).isFalse()
}
@Test
- fun testShouldShowEmptyShadeView_trueWhenQsExpandedInSplitShade() =
+ fun testShouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -180,13 +185,13 @@
runCurrent()
// THEN empty shade is visible
- assertThat(shouldShow).isTrue()
+ assertThat(shouldInclude).isTrue()
}
@Test
- fun testShouldShowEmptyShadeView_trueWhenLockedShade() =
+ fun testShouldIncludeEmptyShadeView_trueWhenLockedShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -195,13 +200,13 @@
runCurrent()
// THEN empty shade is visible
- assertThat(shouldShow).isTrue()
+ assertThat(shouldInclude).isTrue()
}
@Test
- fun testShouldShowEmptyShadeView_falseWhenKeyguard() =
+ fun testShouldIncludeEmptyShadeView_falseWhenKeyguard() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -210,13 +215,13 @@
runCurrent()
// THEN empty shade is not visible
- assertThat(shouldShow).isFalse()
+ assertThat(shouldInclude).isFalse()
}
@Test
- fun testShouldShowEmptyShadeView_falseWhenStartingToSleep() =
+ fun testShouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+ val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
// WHEN has no notifs
activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -227,7 +232,7 @@
runCurrent()
// THEN empty shade is not visible
- assertThat(shouldShow).isFalse()
+ assertThat(shouldInclude).isFalse()
}
@Test
@@ -277,9 +282,9 @@
}
@Test
- fun testShouldShowFooterView_trueWhenShade() =
+ fun testShouldIncludeFooterView_trueWhenShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -289,13 +294,13 @@
runCurrent()
// THEN footer is visible
- assertThat(shouldShow?.value).isTrue()
+ assertThat(shouldInclude?.value).isTrue()
}
@Test
- fun testShouldShowFooterView_trueWhenLockedShade() =
+ fun testShouldIncludeFooterView_trueWhenLockedShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -305,13 +310,13 @@
runCurrent()
// THEN footer is visible
- assertThat(shouldShow?.value).isTrue()
+ assertThat(shouldInclude?.value).isTrue()
}
@Test
- fun testShouldShowFooterView_falseWhenKeyguard() =
+ fun testShouldIncludeFooterView_falseWhenKeyguard() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -320,13 +325,13 @@
runCurrent()
// THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
+ assertThat(shouldInclude?.value).isFalse()
}
@Test
- fun testShouldShowFooterView_falseWhenUserNotSetUp() =
+ fun testShouldIncludeFooterView_falseWhenUserNotSetUp() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -338,13 +343,13 @@
runCurrent()
// THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
+ assertThat(shouldInclude?.value).isFalse()
}
@Test
- fun testShouldShowFooterView_falseWhenStartingToSleep() =
+ fun testShouldIncludeFooterView_falseWhenStartingToSleep() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -356,13 +361,13 @@
runCurrent()
// THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
+ assertThat(shouldInclude?.value).isFalse()
}
@Test
- fun testShouldShowFooterView_falseWhenQsExpandedDefault() =
+ fun testShouldIncludeFooterView_falseWhenQsExpandedDefault() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -375,13 +380,13 @@
runCurrent()
// THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
+ assertThat(shouldInclude?.value).isFalse()
}
@Test
- fun testShouldShowFooterView_trueWhenQsExpandedSplitShade() =
+ fun testShouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -396,13 +401,13 @@
runCurrent()
// THEN footer is visible
- assertThat(shouldShow?.value).isTrue()
+ assertThat(shouldInclude?.value).isTrue()
}
@Test
- fun testShouldShowFooterView_falseWhenRemoteInputActive() =
+ fun testShouldIncludeFooterView_falseWhenRemoteInputActive() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -414,29 +419,13 @@
runCurrent()
// THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
+ assertThat(shouldInclude?.value).isFalse()
}
@Test
- fun testShouldShowFooterView_falseWhenShadeIsClosed() =
+ fun testShouldIncludeFooterView_animatesWhenShade() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
-
- // WHEN has notifs
- activeNotificationListRepository.setActiveNotifs(count = 2)
- // AND shade is closed
- fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
- fakeShadeRepository.setLegacyShadeExpansion(0f)
- runCurrent()
-
- // THEN footer is not visible
- assertThat(shouldShow?.value).isFalse()
- }
-
- @Test
- fun testShouldShowFooterView_animatesWhenShade() =
- testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -446,13 +435,13 @@
runCurrent()
// THEN footer visibility animates
- assertThat(shouldShow?.isAnimating).isTrue()
+ assertThat(shouldInclude?.isAnimating).isTrue()
}
@Test
- fun testShouldShowFooterView_notAnimatingOnKeyguard() =
+ fun testShouldIncludeFooterView_notAnimatingOnKeyguard() =
testScope.runTest {
- val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+ val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
// WHEN has notifs
activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -462,6 +451,150 @@
runCurrent()
// THEN footer visibility does not animate
- assertThat(shouldShow?.isAnimating).isFalse()
+ assertThat(shouldInclude?.isAnimating).isFalse()
+ }
+
+ @Test
+ fun testShouldHideFooterView_trueWhenShadeIsClosed() =
+ testScope.runTest {
+ val shouldHide by collectLastValue(underTest.shouldHideFooterView)
+
+ // WHEN shade is closed
+ fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+ fakeShadeRepository.setLegacyShadeExpansion(0f)
+ runCurrent()
+
+ // THEN footer is hidden
+ assertThat(shouldHide).isTrue()
+ }
+
+ @Test
+ fun testShouldHideFooterView_falseWhenShadeIsOpen() =
+ testScope.runTest {
+ val shouldHide by collectLastValue(underTest.shouldHideFooterView)
+
+ // WHEN shade is open
+ fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+ fakeShadeRepository.setLegacyShadeExpansion(1f)
+ runCurrent()
+
+ // THEN footer is hidden
+ assertThat(shouldHide).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testPinnedHeadsUpRows_filtersForPinnedItems() =
+ testScope.runTest {
+ val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
+
+ // WHEN there are no pinned rows
+ val rows =
+ arrayListOf(
+ fakeHeadsUpRowRepository(key = "0"),
+ fakeHeadsUpRowRepository(key = "1"),
+ fakeHeadsUpRowRepository(key = "2"),
+ )
+ headsUpRepository.setNotifications(
+ rows,
+ )
+ runCurrent()
+
+ // THEN the list is empty
+ assertThat(pinnedHeadsUpRows).isEmpty()
+
+ // WHEN a row gets pinned
+ rows[0].isPinned.value = true
+ runCurrent()
+
+ // THEN it's added to the list
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
+
+ // WHEN more rows are pinned
+ rows[1].isPinned.value = true
+ runCurrent()
+
+ // THEN they are all in the list
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[0], rows[1])
+
+ // WHEN a row gets unpinned
+ rows[0].isPinned.value = false
+ runCurrent()
+
+ // THEN it's removed from the list
+ assertThat(pinnedHeadsUpRows).containsExactly(rows[1])
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testHasPinnedHeadsUpRows_true() =
+ testScope.runTest {
+ val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
+
+ headsUpRepository.setNotifications(
+ fakeHeadsUpRowRepository(key = "0", isPinned = true),
+ fakeHeadsUpRowRepository(key = "1")
+ )
+ runCurrent()
+
+ assertThat(hasPinnedHeadsUpRow).isTrue()
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testHasPinnedHeadsUpRows_false() =
+ testScope.runTest {
+ val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
+
+ headsUpRepository.setNotifications(
+ fakeHeadsUpRowRepository(key = "0"),
+ fakeHeadsUpRowRepository(key = "1"),
+ )
+ runCurrent()
+
+ assertThat(hasPinnedHeadsUpRow).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testTopHeadsUpRow_emptyList_null() =
+ testScope.runTest {
+ val topHeadsUpRow by collectLastValue(underTest.topHeadsUpRow)
+
+ headsUpRepository.setNotifications(emptyList())
+ runCurrent()
+
+ assertThat(topHeadsUpRow).isNull()
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testHeadsUpAnimationsEnabled_true() =
+ testScope.runTest {
+ val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
+
+ fakeShadeRepository.setQsExpansion(0.0f)
+ fakeKeyguardRepository.setKeyguardShowing(false)
+ runCurrent()
+
+ assertThat(animationsEnabled).isTrue()
+ }
+
+ @Test
+ @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
+ fun testHeadsUpAnimationsEnabled_keyguardShowing_false() =
+ testScope.runTest {
+ val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
+
+ fakeShadeRepository.setQsExpansion(0.0f)
+ fakeKeyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ assertThat(animationsEnabled).isFalse()
+ }
+
+ private fun fakeHeadsUpRowRepository(key: String, isPinned: Boolean = false) =
+ FakeHeadsUpRowRepository(key = key, elementKey = Any()).apply {
+ this.isPinned.value = isPinned
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 8e8dd4d..c088609 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -48,6 +48,7 @@
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
@@ -79,6 +80,7 @@
@Mock private QuickSettingsController mQuickSettingsController;
@Mock private ShadeViewController mShadeViewController;
@Mock private PanelExpansionInteractor mPanelExpansionInteractor;
+ @Mock private ShadeHeaderController mShadeHeaderController;
@Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -112,8 +114,8 @@
mScreenPinningRequest,
mShadeController,
mCommandQueue,
- mShadeViewController,
mPanelExpansionInteractor,
+ mShadeHeaderController,
mRemoteInputQuickSettingsDisabler,
mMetricsLogger,
mKeyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 611cf91..dd53474 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -70,7 +70,6 @@
import android.util.SparseArray;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -109,7 +108,6 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.kosmos.KosmosJavaAdapter;
-import com.android.systemui.log.LogBuffer;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
import com.android.systemui.plugins.ActivityStarter;
@@ -423,7 +421,6 @@
mShadeController = spy(new ShadeControllerImpl(
mCommandQueue,
mMainExecutor,
- mock(LogBuffer.class),
mock(WindowRootViewVisibilityInteractor.class),
mKeyguardStateController,
mStatusBarStateController,
@@ -431,7 +428,7 @@
mStatusBarWindowController,
mDeviceProvisionedController,
mNotificationShadeWindowController,
- mContext.getSystemService(WindowManager.class),
+ 0,
() -> mNotificationPanelViewController,
() -> mAssistManager,
() -> mNotificationGutsManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index b0b9bec..054680d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -94,7 +94,7 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeLockscreenInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index de18913..c8ff20b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.StatusBarStateControllerImpl
@@ -68,6 +69,8 @@
@Mock
private lateinit var shadeViewController: ShadeViewController
@Mock
+ private lateinit var shadeLockscreenInteractor: ShadeLockscreenInteractor
+ @Mock
private lateinit var panelExpansionInteractor: PanelExpansionInteractor
@Mock
private lateinit var notifShadeWindowController: NotificationShadeWindowController
@@ -100,6 +103,7 @@
{ notifShadeWindowController },
interactionJankMonitor,
powerManager,
+ { shadeLockscreenInteractor },
{ panelExpansionInteractor },
handler,
)
@@ -133,7 +137,7 @@
callbackCaptor.value.run()
- verify(shadeViewController, times(1)).showAodUi()
+ verify(shadeLockscreenInteractor, times(1)).showAodUi()
}
@Test
@@ -149,7 +153,7 @@
callbackCaptor.value.run()
- verify(shadeViewController, never()).showAodUi()
+ verify(shadeLockscreenInteractor, never()).showAodUi()
}
/**
@@ -171,7 +175,7 @@
verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
callbackCaptor.value.run()
- verify(shadeViewController, never()).showAodUi()
+ verify(shadeLockscreenInteractor, never()).showAodUi()
}
@Test
@@ -186,7 +190,7 @@
verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
callbackCaptor.value.run()
- verify(shadeViewController).showAodUi()
+ verify(shadeLockscreenInteractor).showAodUi()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 9855651..f761bcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -868,6 +868,24 @@
}
@Test
+ fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers() =
+ testScope.runTest {
+ // Use the [StateFlow.value] getter so we can prove that the collection happens
+ // even when there is no [Job]
+
+ // Starts out default
+ assertThat(underTest.networkName.value).isEqualTo(DEFAULT_NAME_MODEL)
+
+ val intent = spnIntent()
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(context).registerReceiver(captor.capture(), any())
+ captor.value!!.onReceive(context, intent)
+
+ // The value is still there despite no active subscribers
+ assertThat(underTest.networkName.value).isEqualTo(intent.toNetworkNameModel(SEP))
+ }
+
+ @Test
fun operatorAlphaShort_tracked() =
testScope.runTest {
var latest: String? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
index 933b5b5..358709f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy
import android.app.IActivityManager
+import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.os.Handler
import android.platform.test.annotations.DisableFlags
@@ -44,6 +45,7 @@
@Mock private lateinit var handler: Handler
@Mock private lateinit var activityManager: IActivityManager
@Mock private lateinit var mediaProjectionManager: MediaProjectionManager
+ @Mock private lateinit var packageManager: PackageManager
private lateinit var controller: SensitiveNotificationProtectionControllerImpl
@Before
@@ -56,6 +58,7 @@
FakeGlobalSettings(),
mediaProjectionManager,
activityManager,
+ packageManager,
handler,
FakeExecutor(FakeSystemClock()),
logger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 4b4e315..867476f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -25,13 +25,21 @@
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
+import android.content.pm.PackageManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
+import android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION
import android.platform.test.annotations.EnableFlags
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
+import com.android.internal.util.FrameworkStatsLog
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -44,35 +52,45 @@
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.settings.FakeGlobalSettings
import com.android.systemui.util.time.FakeSystemClock
+import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@EnableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
+ @get:Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer())
@Mock private lateinit var activityManager: IActivityManager
@Mock private lateinit var mediaProjectionManager: MediaProjectionManager
+ @Mock private lateinit var packageManager: PackageManager
@Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
@Mock private lateinit var listener1: Runnable
@Mock private lateinit var listener2: Runnable
@Mock private lateinit var listener3: Runnable
+ private lateinit var staticMockSession: MockitoSession
private lateinit var executor: FakeExecutor
private lateinit var globalSettings: FakeGlobalSettings
private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
@@ -80,12 +98,29 @@
@Before
fun setUp() {
+ staticMockSession =
+ mockitoSession()
+ .mockStatic(FrameworkStatsLog::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
allowTestableLooperAsMainThread() // for updating exempt packages and notifying listeners
MockitoAnnotations.initMocks(this)
setShareFullScreen()
whenever(activityManager.bugreportWhitelistedPackages)
.thenReturn(listOf(BUGREPORT_PACKAGE_NAME))
+ whenever(packageManager.getPackageUid(TEST_PROJECTION_PACKAGE_NAME, 0))
+ .thenReturn(TEST_PROJECTION_PACKAGE_UID)
+ whenever(packageManager.getPackageUid(BUGREPORT_PACKAGE_NAME, 0))
+ .thenReturn(BUGREPORT_PACKAGE_UID)
+ // SystemUi context package name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding. Setup packagemanager to
+ // return the correct uid in this scenario
+ whenever(packageManager.getPackageUid(mContext.packageName, 0))
+ .thenReturn(mContext.applicationInfo.uid)
+
+ whenever(packageManager.checkPermission(anyString(), anyString()))
+ .thenReturn(PackageManager.PERMISSION_DENIED)
executor = FakeExecutor(FakeSystemClock())
globalSettings = FakeGlobalSettings()
@@ -95,6 +130,7 @@
globalSettings,
mediaProjectionManager,
activityManager,
+ packageManager,
mockExecutorHandler(executor),
executor,
logger
@@ -109,6 +145,11 @@
}
}
+ @After
+ fun tearDown() {
+ staticMockSession.finishMocking()
+ }
+
@Test
fun init_registerMediaProjectionManagerCallback() {
assertNotNull(mediaProjectionCallback)
@@ -228,7 +269,7 @@
@Test
fun isSensitiveStateActive_projectionActive_sysuiExempt_false() {
- // SystemUi context packge name is exempt, but in test scenarios its
+ // SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -237,6 +278,36 @@
}
@Test
+ @RequiresFlagsDisabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+ fun isSensitiveStateActive_projectionActive_permissionExempt_flagDisabled_true() {
+ whenever(
+ packageManager.checkPermission(
+ android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
+ mediaProjectionInfo.packageName
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ assertTrue(controller.isSensitiveStateActive)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+ fun isSensitiveStateActive_projectionActive_permissionExempt_false() {
+ whenever(
+ packageManager.checkPermission(
+ android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
+ mediaProjectionInfo.packageName
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ assertFalse(controller.isSensitiveStateActive)
+ }
+
+ @Test
fun isSensitiveStateActive_projectionActive_bugReportHandlerExempt_false() {
whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -298,7 +369,7 @@
@Test
fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
- // SystemUi context packge name is exempt, but in test scenarios its
+ // SystemUi context package name is exempt, but in test scenarios its
// com.android.systemui.tests so use that instead of hardcoding
whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -309,6 +380,40 @@
}
@Test
+ @RequiresFlagsDisabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+ fun shouldProtectNotification_projectionActive_permissionExempt_flagDisabled_true() {
+ whenever(
+ packageManager.checkPermission(
+ android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
+ mediaProjectionInfo.packageName
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
+
+ assertTrue(controller.shouldProtectNotification(notificationEntry))
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
+ fun shouldProtectNotification_projectionActive_permissionExempt_false() {
+ whenever(
+ packageManager.checkPermission(
+ android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
+ mediaProjectionInfo.packageName
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
+
+ assertFalse(controller.shouldProtectNotification(notificationEntry))
+ }
+
+ @Test
fun shouldProtectNotification_projectionActive_bugReportHandlerExempt_false() {
whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -327,6 +432,7 @@
assertFalse(controller.shouldProtectNotification(notificationEntry))
}
+
@Test
fun shouldProtectNotification_projectionActive_publicNotification_false() {
mediaProjectionCallback.onStart(mediaProjectionInfo)
@@ -347,6 +453,164 @@
assertTrue(controller.shouldProtectNotification(notificationEntry))
}
+ @Test
+ fun logSensitiveContentProtectionSession() {
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(false),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(false),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+ }
+
+ @Test
+ fun logSensitiveContentProtectionSession_exemptViaShareSingleApp() {
+ setShareSingleApp()
+
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+ }
+
+ @Test
+ fun logSensitiveContentProtectionSession_exemptViaDeveloperOption() {
+ setDisabledViaDeveloperOption()
+
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(TEST_PROJECTION_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+ }
+
+ @Test
+ fun logSensitiveContentProtectionSession_exemptViaSystemUi() {
+ // SystemUi context package name is exempt, but in test scenarios its
+ // com.android.systemui.tests so use that instead of hardcoding
+ val testPackageName = mContext.packageName
+ val testUid = mContext.applicationInfo.uid
+ whenever(mediaProjectionInfo.packageName).thenReturn(testPackageName)
+
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(testUid),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(testUid),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+ }
+
+ @Test
+ fun logSensitiveContentProtectionSession_exemptViaBugReportHandler() {
+ // Setup exempt via bugreport handler
+ whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(BUGREPORT_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+
+ mediaProjectionCallback.onStop(mediaProjectionInfo)
+
+ verify {
+ FrameworkStatsLog.write(
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
+ anyLong(),
+ eq(BUGREPORT_PACKAGE_UID),
+ eq(true),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
+ eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
+ )
+ }
+ }
+
private fun setDisabledViaDeveloperOption() {
globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1)
@@ -413,6 +677,8 @@
}
companion object {
+ private const val TEST_PROJECTION_PACKAGE_UID = 23
+ private const val BUGREPORT_PACKAGE_UID = 24
private const val TEST_PROJECTION_PACKAGE_NAME =
"com.android.systemui.statusbar.policy.projectionpackage"
private const val TEST_PACKAGE_NAME = "com.android.systemui.statusbar.policy.testpackage"
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryKosmos.kt
index 6ef7419..ba07a84 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryKosmos.kt
@@ -19,4 +19,5 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-val Kosmos.facePropertyRepository by Fixture { FakeFacePropertyRepository() }
+val Kosmos.fakeFacePropertyRepository by Fixture { FakeFacePropertyRepository() }
+val Kosmos.facePropertyRepository by Fixture { fakeFacePropertyRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
index 27803b2..c065545 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
@@ -16,7 +16,6 @@
package com.android.systemui.bouncer.domain.interactor
-import android.content.applicationContext
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.bouncer.data.repository.bouncerRepository
import com.android.systemui.classifier.domain.interactor.falsingInteractor
@@ -29,12 +28,10 @@
val Kosmos.bouncerInteractor by Fixture {
BouncerInteractor(
applicationScope = testScope.backgroundScope,
- applicationContext = applicationContext,
repository = bouncerRepository,
authenticationInteractor = authenticationInteractor,
deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,
falsingInteractor = falsingInteractor,
powerInteractor = powerInteractor,
- simBouncerInteractor = simBouncerInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractorKosmos.kt
index 8ed9f45..02b79af 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractorKosmos.kt
@@ -38,7 +38,7 @@
telephonyManager = telephonyManager,
resources = mainResources,
keyguardUpdateMonitor = keyguardUpdateMonitor,
- euiccManager = applicationContext.getSystemService(Context.EUICC_SERVICE) as EuiccManager,
+ euiccManager = applicationContext.getSystemService(Context.EUICC_SERVICE) as EuiccManager?,
mobileConnectionsRepository = mobileConnectionsRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt
new file mode 100644
index 0000000..4b64416
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.bouncer.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
+import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.composeBouncerFlags
+import com.android.systemui.deviceentry.domain.interactor.biometricMessageInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel
+import com.android.systemui.util.time.systemClock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.bouncerMessageViewModel by
+ Kosmos.Fixture {
+ BouncerMessageViewModel(
+ applicationContext = applicationContext,
+ applicationScope = testScope.backgroundScope,
+ bouncerInteractor = bouncerInteractor,
+ simBouncerInteractor = simBouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
+ selectedUser = userSwitcherViewModel.selectedUser,
+ clock = systemClock,
+ biometricMessageInteractor = biometricMessageInteractor,
+ faceAuthInteractor = deviceEntryFaceAuthInteractor,
+ deviceEntryInteractor = deviceEntryInteractor,
+ fingerprintInteractor = deviceEntryFingerprintAuthInteractor,
+ flags = composeBouncerFlags,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
index 6d97238..0f6c7cf 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.bouncer.ui.viewmodel
import android.content.applicationContext
@@ -30,7 +32,7 @@
import com.android.systemui.user.domain.interactor.selectedUserInteractor
import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.time.systemClock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.bouncerViewModel by Fixture {
BouncerViewModel(
@@ -47,7 +49,7 @@
users = userSwitcherViewModel.users,
userSwitcherMenu = userSwitcherViewModel.menu,
actionButton = bouncerActionButtonInteractor.actionButton,
- clock = systemClock,
devicePolicyManager = mock(),
+ bouncerMessageViewModel = bouncerMessageViewModel,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 5b642ea..eba5a11 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -45,15 +45,9 @@
private val _currentClock: MutableStateFlow<ClockController?> = MutableStateFlow(null)
override val currentClock = _currentClock
- private val _previewClockPair =
- MutableStateFlow(
- Pair(
- Mockito.mock(ClockController::class.java),
- Mockito.mock(ClockController::class.java)
- )
- )
- override val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
- _previewClockPair
+ private val _previewClock = MutableStateFlow(Mockito.mock(ClockController::class.java))
+ override val previewClock: Flow<ClockController>
+ get() = _previewClock
override val clockEventController: ClockEventController
get() = mock()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index dcbd577..de6bfb2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -18,7 +18,6 @@
package com.android.systemui.keyguard.data.repository
import android.annotation.FloatRange
-import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
@@ -48,21 +47,8 @@
override val transitions: SharedFlow<TransitionStep> = _transitions
init {
- _transitions.tryEmit(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- from = KeyguardState.OFF,
- to = KeyguardState.LOCKSCREEN,
- )
- )
-
- _transitions.tryEmit(
- TransitionStep(
- transitionState = TransitionState.FINISHED,
- from = KeyguardState.OFF,
- to = KeyguardState.LOCKSCREEN,
- )
- )
+ // Seed the fake repository with the same initial steps the actual repository uses.
+ KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) }
}
/**
@@ -207,16 +193,15 @@
suspend fun sendTransitionSteps(
steps: List<TransitionStep>,
testScope: TestScope,
- validateStep: Boolean = true
+ validateSteps: Boolean = true
) {
steps.forEach {
- sendTransitionStep(step = it, validateStep = validateStep)
+ sendTransitionStep(step = it, validateStep = validateSteps)
testScope.testScheduler.runCurrent()
}
}
override fun startTransition(info: TransitionInfo): UUID? {
- Log.i("TEST", "Start transition: ", Exception())
return if (info.animator == null) UUID.randomUUID() else null
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
index 73fd999..709f864 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
@@ -25,6 +25,7 @@
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.shared.flag.sceneContainerFlags
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
@@ -50,5 +51,6 @@
keyguardViewController = { statusBarKeyguardViewManager },
deviceEntryInteractor = deviceEntryInteractor,
deviceEntrySourceInteractor = deviceEntrySourceInteractor,
+ scope = testScope.backgroundScope,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt
new file mode 100644
index 0000000..1b6fa06
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+var Kosmos.goneToLockscreenTransitionViewModel by Fixture {
+ GoneToLockscreenTransitionViewModel(
+ animationFlow = keyguardTransitionAnimationFlow,
+ )
+}
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 a84899e..b91aafe 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
@@ -52,6 +52,7 @@
goneToAodTransitionViewModel = goneToAodTransitionViewModel,
goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
goneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel,
+ goneToLockscreenTransitionViewModel = goneToLockscreenTransitionViewModel,
lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel,
lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt
index 8566251..370afc3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt
@@ -18,7 +18,6 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
@@ -26,7 +25,6 @@
val Kosmos.primaryBouncerToLockscreenTransitionViewModel by Fixture {
PrimaryBouncerToLockscreenTransitionViewModel(
- deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
animationFlow = keyguardTransitionAnimationFlow,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index e861892..67d08f8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -19,6 +19,7 @@
package com.android.systemui.kosmos
import android.content.applicationContext
+import android.os.fakeExecutorHandler
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.bouncerRepository
import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
@@ -27,6 +28,7 @@
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -37,6 +39,7 @@
import com.android.systemui.keyguard.domain.interactor.fromGoneTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.fromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.plugins.statusbar.statusBarStateController
@@ -65,6 +68,8 @@
val testScope by lazy { kosmos.testScope }
val fakeFeatureFlags by lazy { kosmos.fakeFeatureFlagsClassic }
val fakeSceneContainerFlags by lazy { kosmos.fakeSceneContainerFlags }
+ val fakeExecutor by lazy { kosmos.fakeExecutor }
+ val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }
val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
val configurationInteractor by lazy { kosmos.configurationInteractor }
val bouncerRepository by lazy { kosmos.bouncerRepository }
@@ -96,6 +101,7 @@
val fromGoneTransitionInteractor by lazy { kosmos.fromGoneTransitionInteractor }
val globalActionsInteractor by lazy { kosmos.globalActionsInteractor }
val sceneDataSource by lazy { kosmos.sceneDataSource }
+ val keyguardClockInteractor by lazy { kosmos.keyguardClockInteractor }
init {
kosmos.applicationContext = testCase.context
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryKosmos.kt
new file mode 100644
index 0000000..5c17cb9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaDataRepositoryKosmos.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.media.controls.data.repository
+
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.media.controls.util.mediaFlags
+
+val Kosmos.mediaDataRepository by Fixture {
+ MediaDataRepository(mediaFlags = mediaFlags, dumpManager = dumpManager)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
new file mode 100644
index 0000000..7ce810e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.media.controls.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaFilterRepository by Kosmos.Fixture { MediaFilterRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestKosmos.kt
new file mode 100644
index 0000000..12a6325
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaDataCombineLatest by Kosmos.Fixture { MediaDataCombineLatest() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt
new file mode 100644
index 0000000..d56222e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterKosmos.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.content.applicationContext
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.util.mediaFlags
+import com.android.systemui.media.controls.util.mediaUiEventLogger
+import com.android.systemui.settings.userTracker
+import com.android.systemui.statusbar.notificationLockscreenUserManager
+import com.android.systemui.util.time.systemClock
+import com.android.systemui.util.wakelock.WakeLockFake
+
+val Kosmos.mediaDataFilter by
+ Kosmos.Fixture {
+ MediaDataFilterImpl(
+ context = applicationContext,
+ userTracker = userTracker,
+ broadcastSender =
+ BroadcastSender(
+ applicationContext,
+ WakeLockFake.Builder(applicationContext),
+ fakeExecutor
+ ),
+ lockscreenUserManager = notificationLockscreenUserManager,
+ executor = fakeExecutor,
+ systemClock = systemClock,
+ logger = mediaUiEventLogger,
+ mediaFlags = mediaFlags,
+ mediaFilterRepository = mediaFilterRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt
new file mode 100644
index 0000000..cc1ad1f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.app.smartspace.SmartspaceManager
+import android.content.applicationContext
+import android.os.fakeExecutorHandler
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.media.controls.data.repository.mediaDataRepository
+import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
+import com.android.systemui.media.controls.util.mediaControllerFactory
+import com.android.systemui.media.controls.util.mediaFlags
+import com.android.systemui.media.controls.util.mediaUiEventLogger
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.util.Utils
+import com.android.systemui.util.settings.fakeSettings
+import com.android.systemui.util.time.systemClock
+
+val Kosmos.mediaDataProcessor by
+ Kosmos.Fixture {
+ MediaDataProcessor(
+ context = applicationContext,
+ applicationScope = applicationCoroutineScope,
+ backgroundDispatcher = testDispatcher,
+ backgroundExecutor = fakeExecutor,
+ uiExecutor = fakeExecutor,
+ foregroundExecutor = fakeExecutor,
+ handler = fakeExecutorHandler,
+ mediaControllerFactory = mediaControllerFactory,
+ broadcastDispatcher = broadcastDispatcher,
+ dumpManager = dumpManager,
+ activityStarter = activityStarter,
+ smartspaceMediaDataProvider = SmartspaceMediaDataProvider(),
+ useMediaResumption = Utils.useMediaResumption(applicationContext),
+ useQsMediaPlayer = Utils.useQsMediaPlayer(applicationContext),
+ systemClock = systemClock,
+ secureSettings = fakeSettings,
+ mediaFlags = mediaFlags,
+ logger = mediaUiEventLogger,
+ smartspaceManager = SmartspaceManager(applicationContext),
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ mediaDataRepository = mediaDataRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt
new file mode 100644
index 0000000..b98f557
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.content.applicationContext
+import android.media.MediaRouter2Manager
+import android.os.fakeExecutorHandler
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.controls.util.localMediaManagerFactory
+import com.android.systemui.media.controls.util.mediaControllerFactory
+import com.android.systemui.media.muteawait.mediaMuteAwaitConnectionManagerFactory
+import com.android.systemui.statusbar.policy.configurationController
+
+val Kosmos.mediaDeviceManager by
+ Kosmos.Fixture {
+ MediaDeviceManager(
+ context = applicationContext,
+ controllerFactory = mediaControllerFactory,
+ localMediaManagerFactory = localMediaManagerFactory,
+ mr2manager = { MediaRouter2Manager.getInstance(applicationContext) },
+ muteAwaitConnectionManagerFactory = mediaMuteAwaitConnectionManagerFactory,
+ configurationController = configurationController,
+ localBluetoothManager = {
+ LocalBluetoothManager.create(applicationContext, fakeExecutorHandler)
+ },
+ fgExecutor = fakeExecutor,
+ bgExecutor = fakeExecutor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaResumeListenerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaResumeListenerKosmos.kt
new file mode 100644
index 0000000..2a3e84b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaResumeListenerKosmos.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.content.applicationContext
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.controls.domain.resume.MediaResumeListener
+import com.android.systemui.media.controls.domain.resume.resumeMediaBrowserFactory
+import com.android.systemui.media.controls.util.mediaFlags
+import com.android.systemui.settings.userTracker
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.systemClock
+
+val Kosmos.mediaResumeListener by
+ Kosmos.Fixture {
+ MediaResumeListener(
+ context = applicationContext,
+ broadcastDispatcher = broadcastDispatcher,
+ userTracker = userTracker,
+ mainExecutor = fakeExecutor,
+ backgroundExecutor = fakeExecutor,
+ tunerService = mock<TunerService> {},
+ mediaBrowserFactory = resumeMediaBrowserFactory,
+ dumpManager = dumpManager,
+ systemClock = systemClock,
+ mediaFlags = mediaFlags,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterKosmos.kt
new file mode 100644
index 0000000..9b02a5b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterKosmos.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.content.applicationContext
+import android.media.session.MediaSessionManager
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaSessionBasedFilter by
+ Kosmos.Fixture {
+ MediaSessionBasedFilter(
+ context = applicationContext,
+ sessionManager = MediaSessionManager(applicationContext),
+ foregroundExecutor = fakeExecutor,
+ backgroundExecutor = fakeExecutor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerKosmos.kt
new file mode 100644
index 0000000..6ec6378
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerKosmos.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.media.controls.util.mediaControllerFactory
+import com.android.systemui.media.controls.util.mediaFlags
+import com.android.systemui.plugins.statusbar.statusBarStateController
+import com.android.systemui.util.time.systemClock
+
+val Kosmos.mediaTimeoutListener by
+ Kosmos.Fixture {
+ MediaTimeoutListener(
+ mediaControllerFactory = mediaControllerFactory,
+ mainExecutor = fakeExecutor,
+ logger = MediaTimeoutLogger(logcatLogBuffer("MediaTimeoutLogBuffer")),
+ statusBarStateController = statusBarStateController,
+ systemClock = systemClock,
+ mediaFlags = mediaFlags,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt
new file mode 100644
index 0000000..e5e2aff
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.media.controls.domain.pipeline.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.media.controls.data.repository.mediaDataRepository
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.mediaDataCombineLatest
+import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
+import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor
+import com.android.systemui.media.controls.domain.pipeline.mediaDeviceManager
+import com.android.systemui.media.controls.domain.pipeline.mediaResumeListener
+import com.android.systemui.media.controls.domain.pipeline.mediaSessionBasedFilter
+import com.android.systemui.media.controls.domain.pipeline.mediaTimeoutListener
+import com.android.systemui.media.controls.util.mediaFlags
+
+val Kosmos.mediaCarouselInteractor by
+ Kosmos.Fixture {
+ MediaCarouselInteractor(
+ applicationScope = applicationCoroutineScope,
+ mediaDataRepository = mediaDataRepository,
+ mediaDataProcessor = mediaDataProcessor,
+ mediaTimeoutListener = mediaTimeoutListener,
+ mediaResumeListener = mediaResumeListener,
+ mediaSessionBasedFilter = mediaSessionBasedFilter,
+ mediaDeviceManager = mediaDeviceManager,
+ mediaDataCombineLatest = mediaDataCombineLatest,
+ mediaDataFilter = mediaDataFilter,
+ mediaFilterRepository = mediaFilterRepository,
+ mediaFlags = mediaFlags,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/MediaBrowserFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/MediaBrowserFactoryKosmos.kt
new file mode 100644
index 0000000..2621869
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/MediaBrowserFactoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.media.controls.domain.resume
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaBrowserFactory by Kosmos.Fixture { MediaBrowserFactory(applicationContext) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/ResumeMediaBrowserFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/ResumeMediaBrowserFactoryKosmos.kt
new file mode 100644
index 0000000..ed720bd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/resume/ResumeMediaBrowserFactoryKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.media.controls.domain.resume
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.logcatLogBuffer
+
+val Kosmos.resumeMediaBrowserFactory by
+ Kosmos.Fixture {
+ ResumeMediaBrowserFactory(
+ applicationContext,
+ mediaBrowserFactory,
+ ResumeMediaBrowserLogger(logcatLogBuffer("ResumeMediaLogBuffer"))
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/LocalMediaManagerFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/LocalMediaManagerFactoryKosmos.kt
new file mode 100644
index 0000000..2e0c9b8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/LocalMediaManagerFactoryKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.media.controls.util
+
+import android.content.applicationContext
+import android.os.fakeExecutorHandler
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.localMediaManagerFactory by
+ Kosmos.Fixture {
+ LocalMediaManagerFactory(
+ context = applicationContext,
+ localBluetoothManager =
+ LocalBluetoothManager.create(applicationContext, fakeExecutorHandler),
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaControllerFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaControllerFactoryKosmos.kt
new file mode 100644
index 0000000..1ce6e82
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaControllerFactoryKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.media.controls.util
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaControllerFactory by Kosmos.Fixture { MediaControllerFactory(applicationContext) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaFlagsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaFlagsKosmos.kt
new file mode 100644
index 0000000..6f652f2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaFlagsKosmos.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.media.controls.util
+
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
+
+val Kosmos.mediaFlags by
+ Kosmos.Fixture {
+ MediaFlags(featureFlags = featureFlagsClassic, sceneContainerFlags = sceneContainerFlags)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaUiEventLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaUiEventLoggerKosmos.kt
new file mode 100644
index 0000000..b01876d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaUiEventLoggerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.media.controls.util
+
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.mediaUiEventLogger by Kosmos.Fixture { MediaUiEventLogger(uiEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactoryKosmos.kt
new file mode 100644
index 0000000..b78bd58
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactoryKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.media.muteawait
+
+import android.content.applicationContext
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.log.logcatLogBuffer
+
+val Kosmos.mediaMuteAwaitConnectionManagerFactory by
+ Kosmos.Fixture {
+ MediaMuteAwaitConnectionManagerFactory(
+ context = applicationContext,
+ logger = MediaMuteAwaitLogger(logcatLogBuffer("MediaMuteAwaitLogBuffer")),
+ mainExecutor = fakeExecutor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
index 7264f7a2..394c873 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
@@ -19,6 +19,7 @@
import com.android.internal.logging.uiEventLogger
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.jank.interactionJankMonitor
+import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -34,5 +35,6 @@
{ shadeInteractor },
{ deviceUnlockedInteractor },
{ sceneInteractor },
+ { keyguardClockInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/work/WorkModeTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/work/WorkModeTileKosmos.kt
new file mode 100644
index 0000000..c04c5ed
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/work/WorkModeTileKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.qs.tiles.impl.work
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+import com.android.systemui.statusbar.policy.PolicyModule
+
+val Kosmos.qsWorkModeTileConfig by
+ Kosmos.Fixture { PolicyModule.provideWorkModeTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 16c5b72..513c6ab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -18,7 +18,6 @@
package com.android.systemui.shade
-import android.view.WindowManager
import com.android.systemui.assist.AssistManager
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -66,7 +65,6 @@
ShadeControllerImpl(
mock<CommandQueue>(),
fakeExecutor,
- mock<LogBuffer>(),
windowRootViewVisibilityInteractor,
mock<KeyguardStateController>(),
statusBarStateController,
@@ -74,7 +72,7 @@
mock<StatusBarWindowController>(),
deviceProvisionedController,
mock<NotificationShadeWindowController>(),
- mock<WindowManager>(),
+ 0,
{ mock<NotificationPanelViewController>() },
{ mock<AssistManager>() },
{ mock<NotificationGutsManager>() },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
index b99fdb9..bbdb872 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
@@ -21,15 +21,22 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.shade.ShadeHeaderController
import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.shadeController
import com.android.systemui.statusbar.policy.splitShadeStateController
+import com.android.systemui.util.mockito.mock
val Kosmos.shadeStartable by Fixture {
ShadeStartable(
applicationScope = applicationCoroutineScope,
applicationContext = applicationContext,
+ touchLog = mock<LogBuffer>(),
configurationRepository = configurationRepository,
shadeRepository = shadeRepository,
controller = splitShadeStateController,
+ shadeHeaderController = mock<ShadeHeaderController>(),
+ shadeController = shadeController
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt
new file mode 100644
index 0000000..2e983a8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeHeadsUpRowRepository.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.notification.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeHeadsUpRowRepository(override val key: String, override val elementKey: Any) :
+ HeadsUpRowRepository {
+ override val isPinned: MutableStateFlow<Boolean> = MutableStateFlow(false)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt
index 25864ae..165c942 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt
@@ -18,11 +18,16 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
val Kosmos.headsUpNotificationRepository by Fixture { FakeHeadsUpNotificationRepository() }
-class FakeHeadsUpNotificationRepository : HeadsUpNotificationRepository {
- override val hasPinnedHeadsUp = MutableStateFlow(false)
+class FakeHeadsUpNotificationRepository : HeadsUpRepository {
+ override val headsUpAnimatingAway: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ override val topHeadsUpRow: Flow<HeadsUpRowRepository?> = MutableStateFlow(null)
+ override val activeHeadsUpRows: MutableStateFlow<Set<HeadsUpRowRepository>> =
+ MutableStateFlow(emptySet())
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationsRepositoryExt.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationsRepositoryExt.kt
new file mode 100644
index 0000000..9be7dfe
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationsRepositoryExt.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.notification.stack.data.repository
+
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository
+
+fun FakeHeadsUpNotificationRepository.setNotifications(notifications: List<HeadsUpRowRepository>) {
+ setNotifications(*notifications.toTypedArray())
+}
+
+fun FakeHeadsUpNotificationRepository.setNotifications(vararg notifications: HeadsUpRowRepository) {
+ this.activeHeadsUpRows.value = notifications.toSet()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
index 546a1e0..5605d10 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
@@ -18,10 +18,12 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.stack.data.repository.notificationStackAppearanceRepository
val Kosmos.notificationStackAppearanceInteractor by Fixture {
NotificationStackAppearanceInteractor(
repository = notificationStackAppearanceRepository,
+ shadeInteractor = shadeInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
index 2de26f1..ee3216b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
@@ -28,6 +28,7 @@
import com.android.systemui.statusbar.notification.stack.displaySwitchNotificationsHiderTracker
import com.android.systemui.statusbar.notification.stack.ui.view.notificationStatsLogger
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationListViewModel
+import com.android.systemui.statusbar.notification.ui.viewbinder.headsUpNotificationViewBinder
import com.android.systemui.statusbar.phone.notificationIconAreaController
import java.util.Optional
@@ -37,6 +38,7 @@
backgroundDispatcher = testDispatcher,
configuration = configurationState,
falsingManager = falsingManager,
+ hunBinder = headsUpNotificationViewBinder,
iconAreaController = notificationIconAreaController,
loggerOptional = Optional.of(notificationStatsLogger),
metricsLogger = metricsLogger,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index 930a4bb..c65d0a3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testDispatcher
@@ -25,6 +26,7 @@
import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackInteractor
import com.android.systemui.statusbar.policy.domain.interactor.userSetupInteractor
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
@@ -38,6 +40,8 @@
Optional.of(notificationListLoggerViewModel),
activeNotificationsInteractor,
notificationStackInteractor,
+ headsUpNotificationInteractor,
+ keyguardInteractor,
remoteInputInteractor,
seenNotificationsInteractor,
shadeInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt
new file mode 100644
index 0000000..6a995c0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt
@@ -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 com.android.systemui.statusbar.notification.ui.viewbinder
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationListViewModel
+
+val Kosmos.headsUpNotificationViewBinder by
+ Kosmos.Fixture { HeadsUpNotificationViewBinder(viewModel = notificationListViewModel) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java
index 18b07cf..59adb11 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java
@@ -19,24 +19,65 @@
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileController.Callback;
+import java.util.ArrayList;
+import java.util.List;
+
public class FakeManagedProfileController extends BaseLeakChecker<Callback> implements
ManagedProfileController {
+
+ private List<Callback> mCallbackList = new ArrayList<>();
+ private boolean mIsEnabled = false;
+ private boolean mHasActiveProfile = false;
+
public FakeManagedProfileController(LeakCheck test) {
super(test, "profile");
}
@Override
+ public void addCallback(Callback cb) {
+ mCallbackList.add(cb);
+ cb.onManagedProfileChanged();
+ }
+
+ @Override
+ public void removeCallback(Callback cb) {
+ mCallbackList.remove(cb);
+ }
+
+ @Override
public void setWorkModeEnabled(boolean enabled) {
+ if (mIsEnabled != enabled) {
+ mIsEnabled = enabled;
+ for (Callback cb: mCallbackList) {
+ cb.onManagedProfileChanged();
+ }
+ }
}
@Override
public boolean hasActiveProfile() {
- return false;
+ return mHasActiveProfile;
+ }
+
+ /**
+ * Triggers onManagedProfileChanged on callbacks when value flips.
+ */
+ public void setHasActiveProfile(boolean hasActiveProfile) {
+ if (mHasActiveProfile != hasActiveProfile) {
+ mHasActiveProfile = hasActiveProfile;
+ for (Callback cb: mCallbackList) {
+ cb.onManagedProfileChanged();
+ if (!hasActiveProfile) {
+ cb.onManagedProfileRemoved();
+ }
+ }
+ }
+
}
@Override
public boolean isWorkModeEnabled() {
- return false;
+ return mIsEnabled;
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaControllerKosmos.kt
new file mode 100644
index 0000000..5db1724
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaControllerKosmos.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.volume
+
+import android.content.packageManager
+import android.content.pm.ApplicationInfo
+import android.media.AudioAttributes
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+private const val LOCAL_PACKAGE = "local.test.pkg"
+var Kosmos.localMediaController: MediaController by
+ Kosmos.Fixture {
+ val appInfo: ApplicationInfo = mock {
+ whenever(loadLabel(any())).thenReturn("local_media_controller_label")
+ }
+ whenever(packageManager.getApplicationInfo(eq(LOCAL_PACKAGE), any<Int>()))
+ .thenReturn(appInfo)
+
+ val localSessionToken: MediaSession.Token = MediaSession.Token(0, mock {})
+ mock {
+ whenever(packageName).thenReturn(LOCAL_PACKAGE)
+ whenever(playbackInfo)
+ .thenReturn(
+ MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ 0,
+ 0,
+ 0,
+ AudioAttributes.Builder().build(),
+ "",
+ )
+ )
+ whenever(sessionToken).thenReturn(localSessionToken)
+ }
+ }
+
+private const val REMOTE_PACKAGE = "remote.test.pkg"
+var Kosmos.remoteMediaController: MediaController by
+ Kosmos.Fixture {
+ val appInfo: ApplicationInfo = mock {
+ whenever(loadLabel(any())).thenReturn("remote_media_controller_label")
+ }
+ whenever(packageManager.getApplicationInfo(eq(REMOTE_PACKAGE), any<Int>()))
+ .thenReturn(appInfo)
+
+ val remoteSessionToken: MediaSession.Token = MediaSession.Token(0, mock {})
+ mock {
+ whenever(packageName).thenReturn(REMOTE_PACKAGE)
+ whenever(playbackInfo)
+ .thenReturn(
+ MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ 0,
+ 0,
+ 0,
+ AudioAttributes.Builder().build(),
+ "",
+ )
+ )
+ whenever(sessionToken).thenReturn(remoteSessionToken)
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
index 3938f77..fa3a19b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt
@@ -18,7 +18,6 @@
import android.content.packageManager
import android.content.pm.ApplicationInfo
-import android.media.session.MediaController
import android.os.Handler
import android.testing.TestableLooper
import com.android.systemui.kosmos.Kosmos
@@ -32,11 +31,10 @@
import com.android.systemui.volume.data.repository.FakeMediaControllerRepository
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.FakeLocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputActionsInteractor
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
-var Kosmos.mediaController: MediaController by Kosmos.Fixture { mock {} }
-
val Kosmos.localMediaRepository by Kosmos.Fixture { FakeLocalMediaRepository() }
val Kosmos.localMediaRepositoryFactory: LocalMediaRepositoryFactory by
Kosmos.Fixture { FakeLocalMediaRepositoryFactory { localMediaRepository } }
@@ -56,6 +54,14 @@
},
testScope.backgroundScope,
testScope.testScheduler,
+ mediaControllerRepository,
+ )
+ }
+
+val Kosmos.mediaDeviceSessionInteractor by
+ Kosmos.Fixture {
+ MediaDeviceSessionInteractor(
+ testScope.testScheduler,
Handler(TestableLooper.get(testCase).looper),
mediaControllerRepository,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeLocalMediaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeLocalMediaRepository.kt
index 284bd55..909be75 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeLocalMediaRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeLocalMediaRepository.kt
@@ -17,7 +17,6 @@
package com.android.systemui.volume.data.repository
import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.volume.data.model.RoutingSession
import com.android.settingslib.volume.data.repository.LocalMediaRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -25,35 +24,11 @@
class FakeLocalMediaRepository : LocalMediaRepository {
- private val volumeBySession: MutableMap<String?, Int> = mutableMapOf()
-
- private val mutableMediaDevices = MutableStateFlow<List<MediaDevice>>(emptyList())
- override val mediaDevices: StateFlow<List<MediaDevice>>
- get() = mutableMediaDevices.asStateFlow()
-
private val mutableCurrentConnectedDevice = MutableStateFlow<MediaDevice?>(null)
override val currentConnectedDevice: StateFlow<MediaDevice?>
get() = mutableCurrentConnectedDevice.asStateFlow()
- private val mutableRemoteRoutingSessions = MutableStateFlow<List<RoutingSession>>(emptyList())
- override val remoteRoutingSessions: StateFlow<List<RoutingSession>>
- get() = mutableRemoteRoutingSessions.asStateFlow()
-
- fun updateMediaDevices(devices: List<MediaDevice>) {
- mutableMediaDevices.value = devices
- }
-
fun updateCurrentConnectedDevice(device: MediaDevice?) {
mutableCurrentConnectedDevice.value = device
}
-
- fun updateRemoteRoutingSessions(sessions: List<RoutingSession>) {
- mutableRemoteRoutingSessions.value = sessions
- }
-
- fun getSessionVolume(sessionId: String?): Int = volumeBySession.getOrDefault(sessionId, 0)
-
- override suspend fun adjustSessionVolume(sessionId: String?, volume: Int) {
- volumeBySession[sessionId] = volume
- }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeMediaControllerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeMediaControllerRepository.kt
index 6d52e52..8ab5bd90 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeMediaControllerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeMediaControllerRepository.kt
@@ -24,11 +24,11 @@
class FakeMediaControllerRepository : MediaControllerRepository {
- private val mutableActiveLocalMediaController = MutableStateFlow<MediaController?>(null)
- override val activeLocalMediaController: StateFlow<MediaController?> =
- mutableActiveLocalMediaController.asStateFlow()
+ private val mutableActiveSessions = MutableStateFlow<List<MediaController>>(emptyList())
+ override val activeSessions: StateFlow<List<MediaController>>
+ get() = mutableActiveSessions.asStateFlow()
- fun setActiveLocalMediaController(controller: MediaController?) {
- mutableActiveLocalMediaController.value = controller
+ fun setActiveSessions(sessions: List<MediaController>) {
+ mutableActiveSessions.value = sessions
}
}
diff --git a/ravenwood/README.md b/ravenwood/README.md
index 8cafb43..9c4fda7 100644
--- a/ravenwood/README.md
+++ b/ravenwood/README.md
@@ -1,11 +1,9 @@
# Ravenwood
-Ravenwood is a lightweight unit testing environment for Android platform code that runs on the host.
+Ravenwood is an officially-supported lightweight unit testing environment for Android platform code that runs on the host.
Ravenwood’s focus on Android platform use-cases, improved maintainability, and device consistency distinguishes it from Robolectric, which remains a popular choice for app testing.
-> **Note:** Active development of Ravenwood has been paused as of March 2024. Existing Ravenwood tests will continue running, but support has moved to a self-service model.
-
## Background
Executing tests on a typical Android device has substantial overhead, such as flashing the build, waiting for the boot to complete, and retrying tests that fail due to general flakiness.
diff --git a/ravenwood/api-maintainers.md b/ravenwood/api-maintainers.md
index c059cab..4b2f968 100644
--- a/ravenwood/api-maintainers.md
+++ b/ravenwood/api-maintainers.md
@@ -4,7 +4,7 @@
To opt-in to supporting an API under Ravenwood, you can use the inline annotations documented below to customize your API behavior when running under Ravenwood. Because these annotations are inline in the relevant platform source code, they serve as valuable reminders to future API maintainers of Ravenwood support expectations.
-> **Note:** Active development of Ravenwood has been paused as of March 2024. Currently supported APIs will continue working, but the addition of new APIs is not currently being supported. There is an allowlist that restricts where Ravenwood-specific annotations can be used, and that allowlist is not being expanded while development is paused.
+> **Note:** to ensure that API teams are well-supported during early Ravenwood onboarding, the Ravenwood team is manually maintaining an allow-list of classes that are able to use Ravenwood annotations. Please reach out to ravenwood@ so we can offer design advice and allow-list your APIs.
These Ravenwood-specific annotations have no bearing on the status of an API being public, `@SystemApi`, `@TestApi`, `@hide`, etc. Ravenwood annotations are an orthogonal concept that are only consumed by the internal `hoststubgen` tool during a post-processing step that generates the Ravenwood runtime environment. Teams that own APIs can continue to refactor opted-in `@hide` implementation details, as long as the test-visible behavior continues passing.
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
index 81ad31e..61ec7b4 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
@@ -383,9 +383,21 @@
// Assume false for now, because we don't support writing FDs yet.
return false;
}
+
public static boolean nativeHasFileDescriptorsInRange(
long nativePtr, int offset, int length) {
// Assume false for now, because we don't support writing FDs yet.
return false;
}
+
+ public static boolean nativeHasBinders(long nativePtr) {
+ // Assume false for now, because we don't support adding binders.
+ return false;
+ }
+
+ public static boolean nativeHasBindersInRange(
+ long nativePtr, int offset, int length) {
+ // Assume false for now, because we don't support writing FDs yet.
+ return false;
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index c570d65..d307484 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -79,6 +79,8 @@
private static int sNextWindowId;
+ private final Region mTmpRegion = new Region();
+
private final Object mLock;
private final Handler mHandler;
private final WindowManagerInternal mWindowManagerInternal;
@@ -613,7 +615,7 @@
}
// If the window is completely covered by other windows - ignore.
- if (unaccountedSpace.quickReject(regionInScreen)) {
+ if (!mTmpRegion.op(unaccountedSpace, regionInScreen, Region.Op.INTERSECT)) {
return false;
}
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 532db12..c130cee 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -16,6 +16,7 @@
flag {
name: "autofill_credman_dev_integration"
+ is_exported: true
namespace: "autofill"
description: "Guards against Autofill-Credman Phase1 developer integration via new APIs"
bug: "320730001"
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e4f1d3a..fef3216 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -363,6 +363,7 @@
case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_PCC_FEATURE_PROVIDER_HINTS:
case AutofillFeatureFlags.DEVICE_CONFIG_PREFER_PROVIDER_OVER_PCC:
case AutofillFeatureFlags.DEVICE_CONFIG_PCC_USE_FALLBACK:
+ case AutofillFeatureFlags.DEVICE_CONFIG_FILL_FIELDS_FROM_CURRENT_SESSION_ONLY:
case Flags.FLAG_AUTOFILL_CREDMAN_INTEGRATION:
setDeviceConfigProperties();
break;
@@ -710,7 +711,8 @@
AutofillFeatureFlags.DEVICE_CONFIG_MAX_INPUT_LENGTH_FOR_AUTOFILL,
AutofillFeatureFlags.DEFAULT_MAX_INPUT_LENGTH_FOR_AUTOFILL);
mAutofillCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
- mIsFillFieldsFromCurrentSessionOnly = Flags.fillFieldsFromCurrentSessionOnly();
+ mIsFillFieldsFromCurrentSessionOnly = AutofillFeatureFlags
+ .shouldFillFieldsFromCurrentSessionOnly();
if (verbose) {
Slog.v(mTag, "setDeviceConfigProperties() for PCC: "
+ "mPccClassificationEnabled=" + mPccClassificationEnabled
@@ -718,7 +720,9 @@
+ ", mPccUseFallbackDetection=" + mPccUseFallbackDetection
+ ", mPccProviderHints=" + mPccProviderHints
+ ", mAutofillCredmanIntegrationEnabled="
- + mAutofillCredmanIntegrationEnabled);
+ + mAutofillCredmanIntegrationEnabled
+ + ", mIsFillFieldsFromCurrentSessionOnly="
+ + mIsFillFieldsFromCurrentSessionOnly);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e1291e5..272d63d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -33,8 +33,10 @@
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
import android.metrics.LogMaker;
@@ -251,6 +253,31 @@
@Override // from PerUserSystemService
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
throws NameNotFoundException {
+ final List<ResolveInfo> resolveInfos =
+ getContext().getPackageManager().queryIntentServicesAsUser(
+ new Intent(AutofillService.SERVICE_INTERFACE),
+ // The MATCH_INSTANT flag is added because curret autofill CTS module is
+ // defined in one apk, which makes the test autofill service installed in a
+ // instant app when the CTS tests are running in instant app mode.
+ // TODO: Remove MATCH_INSTANT flag after completing refactoring the CTS module
+ // to make the test autofill service a separate apk.
+ PackageManager.GET_META_DATA | PackageManager.MATCH_INSTANT,
+ mUserId);
+ boolean serviceHasAutofillIntentFilter = false;
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (serviceInfo.getComponentName().equals(serviceComponent)) {
+ serviceHasAutofillIntentFilter = true;
+ break;
+ }
+ }
+ if (!serviceHasAutofillIntentFilter) {
+ Slog.w(TAG,
+ "Autofill service from '" + serviceComponent.getPackageName() + "' does"
+ + "not have intent filter " + AutofillService.SERVICE_INTERFACE);
+ throw new SecurityException("Service does not declare intent filter "
+ + AutofillService.SERVICE_INTERFACE);
+ }
mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
return mInfo.getServiceInfo();
}
@@ -1672,9 +1699,10 @@
@Override // from InlineSuggestionRenderCallbacksImpl
public void onServiceDied(@NonNull RemoteInlineSuggestionRenderService service) {
- // Don't do anything; eventually the system will bind to it again...
Slog.w(TAG, "remote service died: " + service);
- mRemoteInlineSuggestionRenderService = null;
+ synchronized (mLock) {
+ resetExtServiceLocked();
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index c3d9790..52108bf1 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -781,6 +781,9 @@
"Not restoring package "
+ key
+ " since it appears to have no signatures.");
+ if (!data.readNextHeader()) {
+ break;
+ }
continue;
}
@@ -790,18 +793,15 @@
sigMap.put(key, new Metadata(versionCode, sigs));
}
- boolean readNextHeader = data.readNextHeader();
- if (!readNextHeader) {
- if (DEBUG) {
- Slog.v(
- TAG,
- "LegacyRestoreDataConsumer:"
- + " we're done reading all the headers");
- }
+ if (!data.readNextHeader()) {
break;
}
}
+ if (DEBUG) {
+ Slog.v(TAG, "LegacyRestoreDataConsumer:" + " we're done reading all the headers");
+ }
+
// On successful completion, cache the signature map for the Backup Manager to use
mRestoredSignatures = sigMap;
}
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
deleted file mode 100644
index 0a41485..0000000
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.companion;
-
-import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.UserIdInt;
-import android.companion.AssociationInfo;
-import android.companion.CompanionDeviceService;
-import android.companion.DevicePresenceEvent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.hardware.power.Mode;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.os.PowerManagerInternal;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.PerUser;
-import com.android.server.companion.association.AssociationStore;
-import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
-import com.android.server.companion.presence.ObservableUuid;
-import com.android.server.companion.presence.ObservableUuidStore;
-import com.android.server.companion.utils.PackageUtils;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Manages communication with companion applications via
- * {@link android.companion.ICompanionDeviceService} interface, including "connecting" (binding) to
- * the services, maintaining the connection (the binding), and invoking callback methods such as
- * {@link CompanionDeviceService#onDeviceAppeared(AssociationInfo)},
- * {@link CompanionDeviceService#onDeviceDisappeared(AssociationInfo)} and
- * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} in the
- * application process.
- *
- * <p>
- * The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
- * utilized by {@link CompanionDeviceManagerService}):
- * <ul>
- * <li> {@link #bindCompanionApplication(int, String, boolean)}
- * <li> {@link #unbindCompanionApplication(int, String)}
- * <li> {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)}
- * <li> {@link #isCompanionApplicationBound(int, String)}
- * <li> {@link #isRebindingCompanionApplicationScheduled(int, String)}
- * </ul>
- *
- * @see CompanionDeviceService
- * @see android.companion.ICompanionDeviceService
- * @see CompanionDeviceServiceConnector
- */
-@SuppressLint("LongLogTag")
-public class CompanionApplicationController {
- static final boolean DEBUG = false;
- private static final String TAG = "CDM_CompanionApplicationController";
-
- private static final long REBIND_TIMEOUT = 10 * 1000; // 10 sec
-
- private final @NonNull Context mContext;
- private final @NonNull AssociationStore mAssociationStore;
- private final @NonNull ObservableUuidStore mObservableUuidStore;
- private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor;
- private final @NonNull CompanionServicesRegister mCompanionServicesRegister;
-
- private final PowerManagerInternal mPowerManagerInternal;
-
- @GuardedBy("mBoundCompanionApplications")
- private final @NonNull AndroidPackageMap<List<CompanionDeviceServiceConnector>>
- mBoundCompanionApplications;
- @GuardedBy("mScheduledForRebindingCompanionApplications")
- private final @NonNull AndroidPackageMap<Boolean> mScheduledForRebindingCompanionApplications;
-
- CompanionApplicationController(Context context, AssociationStore associationStore,
- ObservableUuidStore observableUuidStore,
- CompanionDevicePresenceMonitor companionDevicePresenceMonitor,
- PowerManagerInternal powerManagerInternal) {
- mContext = context;
- mAssociationStore = associationStore;
- mObservableUuidStore = observableUuidStore;
- mDevicePresenceMonitor = companionDevicePresenceMonitor;
- mPowerManagerInternal = powerManagerInternal;
- mCompanionServicesRegister = new CompanionServicesRegister();
- mBoundCompanionApplications = new AndroidPackageMap<>();
- mScheduledForRebindingCompanionApplications = new AndroidPackageMap<>();
- }
-
- void onPackagesChanged(@UserIdInt int userId) {
- mCompanionServicesRegister.invalidate(userId);
- }
-
- /**
- * CDM binds to the companion app.
- */
- public void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
- boolean isSelfManaged) {
- if (DEBUG) {
- Log.i(TAG, "bind() u" + userId + "/" + packageName
- + " isSelfManaged=" + isSelfManaged);
- }
-
- final List<ComponentName> companionServices =
- mCompanionServicesRegister.forPackage(userId, packageName);
- if (companionServices.isEmpty()) {
- Slog.w(TAG, "Can not bind companion applications u" + userId + "/" + packageName + ": "
- + "eligible CompanionDeviceService not found.\n"
- + "A CompanionDeviceService should declare an intent-filter for "
- + "\"android.companion.CompanionDeviceService\" action and require "
- + "\"android.permission.BIND_COMPANION_DEVICE_SERVICE\" permission.");
- return;
- }
-
- final List<CompanionDeviceServiceConnector> serviceConnectors = new ArrayList<>();
- synchronized (mBoundCompanionApplications) {
- if (mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
- if (DEBUG) Log.e(TAG, "u" + userId + "/" + packageName + " is ALREADY bound.");
- return;
- }
-
- for (int i = 0; i < companionServices.size(); i++) {
- boolean isPrimary = i == 0;
- serviceConnectors.add(CompanionDeviceServiceConnector.newInstance(mContext, userId,
- companionServices.get(i), isSelfManaged, isPrimary));
- }
-
- mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
- }
-
- // Set listeners for both Primary and Secondary connectors.
- for (CompanionDeviceServiceConnector serviceConnector : serviceConnectors) {
- serviceConnector.setListener(this::onBinderDied);
- }
-
- // Now "bind" all the connectors: the primary one and the rest of them.
- for (CompanionDeviceServiceConnector serviceConnector : serviceConnectors) {
- serviceConnector.connect();
- }
- }
-
- /**
- * CDM unbinds the companion app.
- */
- public void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Log.i(TAG, "unbind() u" + userId + "/" + packageName);
-
- final List<CompanionDeviceServiceConnector> serviceConnectors;
-
- synchronized (mBoundCompanionApplications) {
- serviceConnectors = mBoundCompanionApplications.removePackage(userId, packageName);
- }
-
- synchronized (mScheduledForRebindingCompanionApplications) {
- mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
- }
-
- if (serviceConnectors == null) {
- if (DEBUG) {
- Log.e(TAG, "unbindCompanionApplication(): "
- + "u" + userId + "/" + packageName + " is NOT bound");
- Log.d(TAG, "Stacktrace", new Throwable());
- }
- return;
- }
-
- for (CompanionDeviceServiceConnector serviceConnector : serviceConnectors) {
- serviceConnector.postUnbind();
- }
- }
-
- /**
- * @return whether the companion application is bound now.
- */
- public boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) {
- synchronized (mBoundCompanionApplications) {
- return mBoundCompanionApplications.containsValueForPackage(userId, packageName);
- }
- }
-
- private void scheduleRebinding(@UserIdInt int userId, @NonNull String packageName,
- CompanionDeviceServiceConnector serviceConnector) {
- Slog.i(TAG, "scheduleRebinding() " + userId + "/" + packageName);
-
- if (isRebindingCompanionApplicationScheduled(userId, packageName)) {
- if (DEBUG) {
- Log.i(TAG, "CompanionApplication rebinding has been scheduled, skipping "
- + serviceConnector.getComponentName());
- }
- return;
- }
-
- if (serviceConnector.isPrimary()) {
- synchronized (mScheduledForRebindingCompanionApplications) {
- mScheduledForRebindingCompanionApplications.setValueForPackage(
- userId, packageName, true);
- }
- }
-
- // Rebinding in 10 seconds.
- Handler.getMain().postDelayed(() ->
- onRebindingCompanionApplicationTimeout(userId, packageName, serviceConnector),
- REBIND_TIMEOUT);
- }
-
- private boolean isRebindingCompanionApplicationScheduled(
- @UserIdInt int userId, @NonNull String packageName) {
- synchronized (mScheduledForRebindingCompanionApplications) {
- return mScheduledForRebindingCompanionApplications.containsValueForPackage(
- userId, packageName);
- }
- }
-
- private void onRebindingCompanionApplicationTimeout(
- @UserIdInt int userId, @NonNull String packageName,
- @NonNull CompanionDeviceServiceConnector serviceConnector) {
- // Re-mark the application is bound.
- if (serviceConnector.isPrimary()) {
- synchronized (mBoundCompanionApplications) {
- if (!mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
- List<CompanionDeviceServiceConnector> serviceConnectors =
- Collections.singletonList(serviceConnector);
- mBoundCompanionApplications.setValueForPackage(userId, packageName,
- serviceConnectors);
- }
- }
-
- synchronized (mScheduledForRebindingCompanionApplications) {
- mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
- }
- }
-
- serviceConnector.connect();
- }
-
- /**
- * Notify the app that the device appeared.
- *
- * @deprecated use {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)} instead
- */
- @Deprecated
- public void notifyCompanionApplicationDeviceAppeared(AssociationInfo association) {
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
-
- Slog.i(TAG, "notifyDevice_Appeared() id=" + association.getId() + " u" + userId
- + "/" + packageName);
-
- final CompanionDeviceServiceConnector primaryServiceConnector =
- getPrimaryServiceConnector(userId, packageName);
- if (primaryServiceConnector == null) {
- Slog.e(TAG, "notify_CompanionApplicationDevice_Appeared(): "
- + "u" + userId + "/" + packageName + " is NOT bound.");
- Slog.e(TAG, "Stacktrace", new Throwable());
- return;
- }
-
- Log.i(TAG, "Calling onDeviceAppeared to userId=[" + userId + "] package=["
- + packageName + "] associationId=[" + association.getId() + "]");
-
- primaryServiceConnector.postOnDeviceAppeared(association);
- }
-
- /**
- * Notify the app that the device disappeared.
- *
- * @deprecated use {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)} instead
- */
- @Deprecated
- public void notifyCompanionApplicationDeviceDisappeared(AssociationInfo association) {
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
-
- Slog.i(TAG, "notifyDevice_Disappeared() id=" + association.getId() + " u" + userId
- + "/" + packageName);
-
- final CompanionDeviceServiceConnector primaryServiceConnector =
- getPrimaryServiceConnector(userId, packageName);
- if (primaryServiceConnector == null) {
- Slog.e(TAG, "notify_CompanionApplicationDevice_Disappeared(): "
- + "u" + userId + "/" + packageName + " is NOT bound.");
- Slog.e(TAG, "Stacktrace", new Throwable());
- return;
- }
-
- Log.i(TAG, "Calling onDeviceDisappeared to userId=[" + userId + "] package=["
- + packageName + "] associationId=[" + association.getId() + "]");
-
- primaryServiceConnector.postOnDeviceDisappeared(association);
- }
-
- /**
- * Notify the app that the device appeared.
- */
- public void notifyCompanionDevicePresenceEvent(AssociationInfo association, int event) {
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
- final CompanionDeviceServiceConnector primaryServiceConnector =
- getPrimaryServiceConnector(userId, packageName);
- final DevicePresenceEvent devicePresenceEvent =
- new DevicePresenceEvent(association.getId(), event, null);
-
- if (primaryServiceConnector == null) {
- Slog.e(TAG, "notifyCompanionApplicationDevicePresenceEvent(): "
- + "u" + userId + "/" + packageName
- + " event=[ " + event + " ] is NOT bound.");
- Slog.e(TAG, "Stacktrace", new Throwable());
- return;
- }
-
- Slog.i(TAG, "Calling onDevicePresenceEvent() to userId=[" + userId + "] package=["
- + packageName + "] associationId=[" + association.getId()
- + "] event=[" + event + "]");
-
- primaryServiceConnector.postOnDevicePresenceEvent(devicePresenceEvent);
- }
-
- /**
- * Notify the app that the device disappeared.
- */
- public void notifyUuidDevicePresenceEvent(ObservableUuid uuid, int event) {
- final int userId = uuid.getUserId();
- final ParcelUuid parcelUuid = uuid.getUuid();
- final String packageName = uuid.getPackageName();
- final CompanionDeviceServiceConnector primaryServiceConnector =
- getPrimaryServiceConnector(userId, packageName);
- final DevicePresenceEvent devicePresenceEvent =
- new DevicePresenceEvent(DevicePresenceEvent.NO_ASSOCIATION, event, parcelUuid);
-
- if (primaryServiceConnector == null) {
- Slog.e(TAG, "notifyApplicationDevicePresenceChanged(): "
- + "u" + userId + "/" + packageName
- + " event=[ " + event + " ] is NOT bound.");
- Slog.e(TAG, "Stacktrace", new Throwable());
- return;
- }
-
- Slog.i(TAG, "Calling onDevicePresenceEvent() to userId=[" + userId + "] package=["
- + packageName + "]" + "event= [" + event + "]");
-
- primaryServiceConnector.postOnDevicePresenceEvent(devicePresenceEvent);
- }
-
- void dump(@NonNull PrintWriter out) {
- out.append("Companion Device Application Controller: \n");
-
- synchronized (mBoundCompanionApplications) {
- out.append(" Bound Companion Applications: ");
- if (mBoundCompanionApplications.size() == 0) {
- out.append("<empty>\n");
- } else {
- out.append("\n");
- mBoundCompanionApplications.dump(out);
- }
- }
-
- out.append(" Companion Applications Scheduled For Rebinding: ");
- if (mScheduledForRebindingCompanionApplications.size() == 0) {
- out.append("<empty>\n");
- } else {
- out.append("\n");
- mScheduledForRebindingCompanionApplications.dump(out);
- }
- }
-
- /**
- * Rebinding for Self-Managed secondary services OR Non-Self-Managed services.
- */
- private void onBinderDied(@UserIdInt int userId, @NonNull String packageName,
- @NonNull CompanionDeviceServiceConnector serviceConnector) {
-
- boolean isPrimary = serviceConnector.isPrimary();
- Slog.i(TAG, "onBinderDied() u" + userId + "/" + packageName + " isPrimary: " + isPrimary);
-
- // First, disable hint mode for Auto profile and mark not BOUND for primary service ONLY.
- if (isPrimary) {
- final List<AssociationInfo> associations =
- mAssociationStore.getActiveAssociationsByPackage(userId, packageName);
-
- for (AssociationInfo association : associations) {
- final String deviceProfile = association.getDeviceProfile();
- if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
- Slog.i(TAG, "Disable hint mode for device profile: " + deviceProfile);
- mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
- break;
- }
- }
-
- synchronized (mBoundCompanionApplications) {
- mBoundCompanionApplications.removePackage(userId, packageName);
- }
- }
-
- // Second: schedule rebinding if needed.
- final boolean shouldScheduleRebind = shouldScheduleRebind(userId, packageName, isPrimary);
-
- if (shouldScheduleRebind) {
- scheduleRebinding(userId, packageName, serviceConnector);
- }
- }
-
- private @Nullable CompanionDeviceServiceConnector getPrimaryServiceConnector(
- @UserIdInt int userId, @NonNull String packageName) {
- final List<CompanionDeviceServiceConnector> connectors;
- synchronized (mBoundCompanionApplications) {
- connectors = mBoundCompanionApplications.getValueForPackage(userId, packageName);
- }
- return connectors != null ? connectors.get(0) : null;
- }
-
- private boolean shouldScheduleRebind(int userId, String packageName, boolean isPrimary) {
- // Make sure do not schedule rebind for the case ServiceConnector still gets callback after
- // app is uninstalled.
- boolean stillAssociated = false;
- // Make sure to clean up the state for all the associations
- // that associate with this package.
- boolean shouldScheduleRebind = false;
- boolean shouldScheduleRebindForUuid = false;
- final List<ObservableUuid> uuids =
- mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
-
- for (AssociationInfo ai :
- mAssociationStore.getActiveAssociationsByPackage(userId, packageName)) {
- final int associationId = ai.getId();
- stillAssociated = true;
- if (ai.isSelfManaged()) {
- // Do not rebind if primary one is died for selfManaged application.
- if (isPrimary
- && mDevicePresenceMonitor.isDevicePresent(associationId)) {
- mDevicePresenceMonitor.onSelfManagedDeviceReporterBinderDied(associationId);
- shouldScheduleRebind = false;
- }
- // Do not rebind if both primary and secondary services are died for
- // selfManaged application.
- shouldScheduleRebind = isCompanionApplicationBound(userId, packageName);
- } else if (ai.isNotifyOnDeviceNearby()) {
- // Always rebind for non-selfManaged devices.
- shouldScheduleRebind = true;
- }
- }
-
- for (ObservableUuid uuid : uuids) {
- if (mDevicePresenceMonitor.isDeviceUuidPresent(uuid.getUuid())) {
- shouldScheduleRebindForUuid = true;
- break;
- }
- }
-
- return (stillAssociated && shouldScheduleRebind) || shouldScheduleRebindForUuid;
- }
-
- private class CompanionServicesRegister extends PerUser<Map<String, List<ComponentName>>> {
- @Override
- public synchronized @NonNull Map<String, List<ComponentName>> forUser(
- @UserIdInt int userId) {
- return super.forUser(userId);
- }
-
- synchronized @NonNull List<ComponentName> forPackage(
- @UserIdInt int userId, @NonNull String packageName) {
- return forUser(userId).getOrDefault(packageName, Collections.emptyList());
- }
-
- synchronized void invalidate(@UserIdInt int userId) {
- remove(userId);
- }
-
- @Override
- protected final @NonNull Map<String, List<ComponentName>> create(@UserIdInt int userId) {
- return PackageUtils.getCompanionServicesForUser(mContext, userId);
- }
- }
-
- /**
- * Associates an Android package (defined by userId + packageName) with a value of type T.
- */
- private static class AndroidPackageMap<T> extends SparseArray<Map<String, T>> {
-
- void setValueForPackage(
- @UserIdInt int userId, @NonNull String packageName, @NonNull T value) {
- Map<String, T> forUser = get(userId);
- if (forUser == null) {
- forUser = /* Map<String, T> */ new HashMap();
- put(userId, forUser);
- }
-
- forUser.put(packageName, value);
- }
-
- boolean containsValueForPackage(@UserIdInt int userId, @NonNull String packageName) {
- final Map<String, ?> forUser = get(userId);
- return forUser != null && forUser.containsKey(packageName);
- }
-
- T getValueForPackage(@UserIdInt int userId, @NonNull String packageName) {
- final Map<String, T> forUser = get(userId);
- return forUser != null ? forUser.get(packageName) : null;
- }
-
- T removePackage(@UserIdInt int userId, @NonNull String packageName) {
- final Map<String, T> forUser = get(userId);
- if (forUser == null) return null;
- return forUser.remove(packageName);
- }
-
- void dump() {
- if (size() == 0) {
- Log.d(TAG, "<empty>");
- return;
- }
-
- for (int i = 0; i < size(); i++) {
- final int userId = keyAt(i);
- final Map<String, T> forUser = get(userId);
- if (forUser.isEmpty()) {
- Log.d(TAG, "u" + userId + ": <empty>");
- }
-
- for (Map.Entry<String, T> packageValue : forUser.entrySet()) {
- final String packageName = packageValue.getKey();
- final T value = packageValue.getValue();
- Log.d(TAG, "u" + userId + "\\" + packageName + " -> " + value);
- }
- }
- }
-
- private void dump(@NonNull PrintWriter out) {
- for (int i = 0; i < size(); i++) {
- final int userId = keyAt(i);
- final Map<String, T> forUser = get(userId);
- if (forUser.isEmpty()) {
- out.append(" u").append(String.valueOf(userId)).append(": <empty>\n");
- }
-
- for (Map.Entry<String, T> packageValue : forUser.entrySet()) {
- final String packageName = packageValue.getKey();
- final T value = packageValue.getValue();
- out.append(" u").append(String.valueOf(userId)).append("\\")
- .append(packageName).append(" -> ")
- .append(value.toString()).append('\n');
- }
- }
- }
- }
-}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 712162b..f4f6c13 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -20,15 +20,10 @@
import static android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES;
import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
+import static android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED;
import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
-import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
-import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
-import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED;
import static android.companion.DevicePresenceEvent.EVENT_BT_CONNECTED;
-import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
-import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_APPEARED;
-import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_DISAPPEARED;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -42,13 +37,10 @@
import static com.android.server.companion.utils.PackageUtils.isRestrictedSettingsAllowed;
import static com.android.server.companion.utils.PermissionsUtils.checkCallerCanManageCompanionDevice;
import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
-import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanObservingDevicePresenceByUuid;
import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOr;
import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
-import static com.android.server.companion.utils.PermissionsUtils.sanitizeWithCallerChecks;
import static java.util.Objects.requireNonNull;
-import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import android.annotation.EnforcePermission;
@@ -64,7 +56,6 @@
import android.bluetooth.BluetoothDevice;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
-import android.companion.DeviceNotAssociatedException;
import android.companion.IAssociationRequestCallback;
import android.companion.ICompanionDeviceManager;
import android.companion.IOnAssociationsChangedListener;
@@ -79,7 +70,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.hardware.power.Mode;
import android.net.MacAddress;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -91,7 +81,6 @@
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
@@ -118,7 +107,8 @@
import com.android.server.companion.datatransfer.contextsync.CrossDeviceCall;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback;
-import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.CompanionAppBinder;
+import com.android.server.companion.presence.DevicePresenceProcessor;
import com.android.server.companion.presence.ObservableUuid;
import com.android.server.companion.presence.ObservableUuidStore;
import com.android.server.companion.transport.CompanionTransportManager;
@@ -131,10 +121,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
@SuppressLint("LongLogTag")
@@ -146,10 +133,6 @@
private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
- private static final String SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW =
- "debug.cdm.cdmservice.removal_time_window";
-
- private static final long ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT = DAYS.toMillis(90);
private static final int MAX_CN_LENGTH = 500;
private final ActivityTaskManagerInternal mAtmInternal;
@@ -165,10 +148,11 @@
private final AssociationRequestsProcessor mAssociationRequestsProcessor;
private final SystemDataTransferProcessor mSystemDataTransferProcessor;
private final BackupRestoreProcessor mBackupRestoreProcessor;
- private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
- private final CompanionApplicationController mCompanionAppController;
+ private final DevicePresenceProcessor mDevicePresenceMonitor;
+ private final CompanionAppBinder mCompanionAppController;
private final CompanionTransportManager mTransportManager;
private final DisassociationProcessor mDisassociationProcessor;
+ private final InactiveAssociationsRemovalService mInactiveAssociationsRemovalService;
private final CrossDeviceSyncController mCrossDeviceSyncController;
public CompanionDeviceManagerService(Context context) {
@@ -185,7 +169,7 @@
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
final AssociationDiskStore associationDiskStore = new AssociationDiskStore();
- mAssociationStore = new AssociationStore(userManager, associationDiskStore);
+ mAssociationStore = new AssociationStore(context, userManager, associationDiskStore);
mSystemDataTransferRequestStore = new SystemDataTransferRequestStore();
mObservableUuidStore = new ObservableUuidStore();
@@ -196,11 +180,11 @@
mAssociationStore, associationDiskStore, mSystemDataTransferRequestStore,
mAssociationRequestsProcessor);
- mDevicePresenceMonitor = new CompanionDevicePresenceMonitor(userManager,
- mAssociationStore, mObservableUuidStore, mDevicePresenceCallback);
+ mCompanionAppController = new CompanionAppBinder(
+ context, mAssociationStore, mObservableUuidStore, mPowerManagerInternal);
- mCompanionAppController = new CompanionApplicationController(
- context, mAssociationStore, mObservableUuidStore, mDevicePresenceMonitor,
+ mDevicePresenceMonitor = new DevicePresenceProcessor(context,
+ mCompanionAppController, userManager, mAssociationStore, mObservableUuidStore,
mPowerManagerInternal);
mTransportManager = new CompanionTransportManager(context, mAssociationStore);
@@ -209,6 +193,9 @@
mAssociationStore, mPackageManagerInternal, mDevicePresenceMonitor,
mCompanionAppController, mSystemDataTransferRequestStore, mTransportManager);
+ mInactiveAssociationsRemovalService = new InactiveAssociationsRemovalService(
+ mAssociationStore, mDisassociationProcessor);
+
mSystemDataTransferProcessor = new SystemDataTransferProcessor(this,
mPackageManagerInternal, mAssociationStore,
mSystemDataTransferRequestStore, mTransportManager);
@@ -302,181 +289,6 @@
}
}
- @NonNull
- AssociationInfo getAssociationWithCallerChecks(
- @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
- AssociationInfo association = mAssociationStore.getFirstAssociationByAddress(
- userId, packageName, macAddress);
- association = sanitizeWithCallerChecks(getContext(), association);
- if (association != null) {
- return association;
- } else {
- throw new IllegalArgumentException("Association does not exist "
- + "or the caller does not have permissions to manage it "
- + "(ie. it belongs to a different package or a different user).");
- }
- }
-
- @NonNull
- AssociationInfo getAssociationWithCallerChecks(int associationId) {
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- association = sanitizeWithCallerChecks(getContext(), association);
- if (association != null) {
- return association;
- } else {
- throw new IllegalArgumentException("Association does not exist "
- + "or the caller does not have permissions to manage it "
- + "(ie. it belongs to a different package or a different user).");
- }
- }
-
- private void onDeviceAppearedInternal(int associationId) {
- if (DEBUG) Log.i(TAG, "onDevice_Appeared_Internal() id=" + associationId);
-
- final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (DEBUG) Log.d(TAG, " association=" + association);
-
- if (!association.shouldBindWhenPresent()) return;
-
- bindApplicationIfNeeded(association);
-
- mCompanionAppController.notifyCompanionApplicationDeviceAppeared(association);
- }
-
- private void onDeviceDisappearedInternal(int associationId) {
- if (DEBUG) Log.i(TAG, "onDevice_Disappeared_Internal() id=" + associationId);
-
- final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (DEBUG) Log.d(TAG, " association=" + association);
-
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
-
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- if (DEBUG) Log.w(TAG, "u" + userId + "\\" + packageName + " is NOT bound");
- return;
- }
-
- if (association.shouldBindWhenPresent()) {
- mCompanionAppController.notifyCompanionApplicationDeviceDisappeared(association);
- }
- }
-
- private void onDevicePresenceEventInternal(int associationId, int event) {
- Slog.i(TAG, "onDevicePresenceEventInternal() id=" + associationId + " event= " + event);
- final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- final String packageName = association.getPackageName();
- final int userId = association.getUserId();
- switch (event) {
- case EVENT_BLE_APPEARED:
- case EVENT_BT_CONNECTED:
- case EVENT_SELF_MANAGED_APPEARED:
- if (!association.shouldBindWhenPresent()) return;
-
- bindApplicationIfNeeded(association);
-
- mCompanionAppController.notifyCompanionDevicePresenceEvent(
- association, event);
- break;
- case EVENT_BLE_DISAPPEARED:
- case EVENT_BT_DISCONNECTED:
- case EVENT_SELF_MANAGED_DISAPPEARED:
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- if (DEBUG) Log.w(TAG, "u" + userId + "\\" + packageName + " is NOT bound");
- return;
- }
- if (association.shouldBindWhenPresent()) {
- mCompanionAppController.notifyCompanionDevicePresenceEvent(
- association, event);
- }
- // Check if there are other devices associated to the app that are present.
- if (shouldBindPackage(userId, packageName)) return;
- mCompanionAppController.unbindCompanionApplication(userId, packageName);
- break;
- default:
- Slog.e(TAG, "Event: " + event + "is not supported");
- break;
- }
- }
-
- private void onDevicePresenceEventByUuidInternal(ObservableUuid uuid, int event) {
- Slog.i(TAG, "onDevicePresenceEventByUuidInternal() id=" + uuid.getUuid()
- + "for package=" + uuid.getPackageName() + " event=" + event);
- final String packageName = uuid.getPackageName();
- final int userId = uuid.getUserId();
-
- switch (event) {
- case EVENT_BT_CONNECTED:
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(
- userId, packageName, /*bindImportant*/ false);
-
- } else if (DEBUG) {
- Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
- }
-
- mCompanionAppController.notifyUuidDevicePresenceEvent(uuid, event);
-
- break;
- case EVENT_BT_DISCONNECTED:
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- if (DEBUG) Log.w(TAG, "u" + userId + "\\" + packageName + " is NOT bound");
- return;
- }
-
- mCompanionAppController.notifyUuidDevicePresenceEvent(uuid, event);
- // Check if there are other devices associated to the app or the UUID to be
- // observed are present.
- if (shouldBindPackage(userId, packageName)) return;
-
- mCompanionAppController.unbindCompanionApplication(userId, packageName);
-
- break;
- default:
- Slog.e(TAG, "Event: " + event + "is not supported");
- break;
- }
- }
-
- private void bindApplicationIfNeeded(AssociationInfo association) {
- final String packageName = association.getPackageName();
- final int userId = association.getUserId();
- // Set bindImportant to true when the association is self-managed to avoid the target
- // service being killed.
- final boolean bindImportant = association.isSelfManaged();
- if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(
- userId, packageName, bindImportant);
- } else if (DEBUG) {
- Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
- }
- }
-
- /**
- * @return whether the package should be bound (i.e. at least one of the devices associated with
- * the package is currently present OR the UUID to be observed by this package is
- * currently present).
- */
- private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) {
- final List<AssociationInfo> packageAssociations =
- mAssociationStore.getActiveAssociationsByPackage(userId, packageName);
- final List<ObservableUuid> observableUuids =
- mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
-
- for (AssociationInfo association : packageAssociations) {
- if (!association.shouldBindWhenPresent()) continue;
- if (mDevicePresenceMonitor.isDevicePresent(association.getId())) return true;
- }
-
- for (ObservableUuid uuid : observableUuids) {
- if (mDevicePresenceMonitor.isDeviceUuidPresent(uuid.getUuid())) {
- return true;
- }
- }
-
- return false;
- }
-
private void onPackageRemoveOrDataClearedInternal(
@UserIdInt int userId, @NonNull String packageName) {
if (DEBUG) {
@@ -522,27 +334,8 @@
mBackupRestoreProcessor.restorePendingAssociations(userId, packageName);
}
- // Revoke associations if the selfManaged companion device does not connect for 3 months.
void removeInactiveSelfManagedAssociations() {
- final long currentTime = System.currentTimeMillis();
- long removalWindow = SystemProperties.getLong(SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW, -1);
- if (removalWindow <= 0) {
- // 0 or negative values indicate that the sysprop was never set or should be ignored.
- removalWindow = ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT;
- }
-
- for (AssociationInfo association : mAssociationStore.getAssociations()) {
- if (!association.isSelfManaged()) continue;
-
- final boolean isInactive =
- currentTime - association.getLastTimeConnectedMs() >= removalWindow;
- if (!isInactive) continue;
-
- final int id = association.getId();
-
- Slog.i(TAG, "Removing inactive self-managed association id=" + id);
- mDisassociationProcessor.disassociate(id);
- }
+ mInactiveAssociationsRemovalService.removeIdleSelfManagedAssociations();
}
public class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
@@ -679,24 +472,15 @@
@Deprecated
@Override
public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) {
- Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName
- + ", macAddress=" + deviceMacAddress);
-
requireNonNull(deviceMacAddress);
requireNonNull(packageName);
- final AssociationInfo association =
- getAssociationWithCallerChecks(userId, packageName, deviceMacAddress);
- mDisassociationProcessor.disassociate(association.getId());
+ mDisassociationProcessor.disassociate(userId, packageName, deviceMacAddress);
}
@Override
public void disassociate(int associationId) {
- Slog.i(TAG, "disassociate() associationId=" + associationId);
-
- final AssociationInfo association =
- getAssociationWithCallerChecks(associationId);
- mDisassociationProcessor.disassociate(association.getId());
+ mDisassociationProcessor.disassociate(associationId);
}
@Override
@@ -758,21 +542,25 @@
}
@Override
+ @Deprecated
@EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
- public void registerDevicePresenceListenerService(String deviceAddress,
- String callingPackage, int userId) throws RemoteException {
- registerDevicePresenceListenerService_enforcePermission();
- // TODO: take the userId into account.
- registerDevicePresenceListenerActive(callingPackage, deviceAddress, true);
+ public void legacyStartObservingDevicePresence(String deviceAddress, String callingPackage,
+ int userId) throws RemoteException {
+ legacyStartObservingDevicePresence_enforcePermission();
+
+ mDevicePresenceMonitor.startObservingDevicePresence(userId, callingPackage,
+ deviceAddress);
}
@Override
+ @Deprecated
@EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE)
- public void unregisterDevicePresenceListenerService(String deviceAddress,
- String callingPackage, int userId) throws RemoteException {
- unregisterDevicePresenceListenerService_enforcePermission();
- // TODO: take the userId into account.
- registerDevicePresenceListenerActive(callingPackage, deviceAddress, false);
+ public void legacyStopObservingDevicePresence(String deviceAddress, String callingPackage,
+ int userId) throws RemoteException {
+ legacyStopObservingDevicePresence_enforcePermission();
+
+ mDevicePresenceMonitor.stopObservingDevicePresence(userId, callingPackage,
+ deviceAddress);
}
@Override
@@ -780,7 +568,8 @@
public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
String packageName, int userId) {
startObservingDevicePresence_enforcePermission();
- registerDevicePresenceListener(request, packageName, userId, /* active */ true);
+
+ mDevicePresenceMonitor.startObservingDevicePresence(request, packageName, userId);
}
@Override
@@ -788,80 +577,8 @@
public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
String packageName, int userId) {
stopObservingDevicePresence_enforcePermission();
- registerDevicePresenceListener(request, packageName, userId, /* active */ false);
- }
- private void registerDevicePresenceListener(ObservingDevicePresenceRequest request,
- String packageName, int userId, boolean active) {
- enforceUsesCompanionDeviceFeature(getContext(), userId, packageName);
- enforceCallerIsSystemOr(userId, packageName);
-
- final int associationId = request.getAssociationId();
- final AssociationInfo associationInfo = mAssociationStore.getAssociationById(
- associationId);
- final ParcelUuid uuid = request.getUuid();
-
- if (uuid != null) {
- enforceCallerCanObservingDevicePresenceByUuid(getContext());
- if (active) {
- startObservingDevicePresenceByUuid(uuid, packageName, userId);
- } else {
- stopObservingDevicePresenceByUuid(uuid, packageName, userId);
- }
- } else if (associationInfo == null) {
- throw new IllegalArgumentException("App " + packageName
- + " is not associated with device " + request.getAssociationId()
- + " for user " + userId);
- } else {
- processDevicePresenceListener(
- associationInfo, userId, packageName, active);
- }
- }
-
- private void startObservingDevicePresenceByUuid(ParcelUuid uuid, String packageName,
- int userId) {
- final List<ObservableUuid> observableUuids =
- mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
-
- for (ObservableUuid observableUuid : observableUuids) {
- if (observableUuid.getUuid().equals(uuid)) {
- Slog.i(TAG, "The uuid: " + uuid + " for package:" + packageName
- + "has been already scheduled for observing");
- return;
- }
- }
-
- final ObservableUuid observableUuid = new ObservableUuid(userId, uuid,
- packageName, System.currentTimeMillis());
-
- mObservableUuidStore.writeObservableUuid(userId, observableUuid);
- }
-
- private void stopObservingDevicePresenceByUuid(ParcelUuid uuid, String packageName,
- int userId) {
- final List<ObservableUuid> uuidsTobeObserved =
- mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
- boolean isScheduledObserving = false;
-
- for (ObservableUuid observableUuid : uuidsTobeObserved) {
- if (observableUuid.getUuid().equals(uuid)) {
- isScheduledObserving = true;
- break;
- }
- }
-
- if (!isScheduledObserving) {
- Slog.i(TAG, "The uuid: " + uuid.toString() + " for package:" + packageName
- + "has NOT been scheduled for observing yet");
- return;
- }
-
- mObservableUuidStore.removeObservableUuid(userId, uuid, packageName);
- mDevicePresenceMonitor.removeCurrentConnectedUuidDevice(uuid);
-
- if (!shouldBindPackage(userId, packageName)) {
- mCompanionAppController.unbindCompanionApplication(userId, packageName);
- }
+ mDevicePresenceMonitor.stopObservingDevicePresence(request, packageName, userId);
}
@Override
@@ -874,8 +591,7 @@
@Override
public boolean isPermissionTransferUserConsented(String packageName, int userId,
int associationId) {
- return mSystemDataTransferProcessor.isPermissionTransferUserConsented(packageName,
- userId, associationId);
+ return mSystemDataTransferProcessor.isPermissionTransferUserConsented(associationId);
}
@Override
@@ -891,8 +607,7 @@
ParcelFileDescriptor fd) {
attachSystemDataTransport_enforcePermission();
- getAssociationWithCallerChecks(associationId);
- mTransportManager.attachSystemDataTransport(packageName, userId, associationId, fd);
+ mTransportManager.attachSystemDataTransport(associationId, fd);
}
@Override
@@ -900,96 +615,56 @@
public void detachSystemDataTransport(String packageName, int userId, int associationId) {
detachSystemDataTransport_enforcePermission();
- getAssociationWithCallerChecks(associationId);
- mTransportManager.detachSystemDataTransport(packageName, userId, associationId);
- }
-
- @Override
- public void enableSystemDataSync(int associationId, int flags) {
- getAssociationWithCallerChecks(associationId);
- mAssociationRequestsProcessor.enableSystemDataSync(associationId, flags);
- }
-
- @Override
- public void disableSystemDataSync(int associationId, int flags) {
- getAssociationWithCallerChecks(associationId);
- mAssociationRequestsProcessor.disableSystemDataSync(associationId, flags);
- }
-
- @Override
- public void enablePermissionsSync(int associationId) {
- getAssociationWithCallerChecks(associationId);
- mSystemDataTransferProcessor.enablePermissionsSync(associationId);
- }
-
- @Override
- public void disablePermissionsSync(int associationId) {
- getAssociationWithCallerChecks(associationId);
- mSystemDataTransferProcessor.disablePermissionsSync(associationId);
- }
-
- @Override
- public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
- // TODO: temporary fix, will remove soon
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- if (association == null) {
- return null;
- }
- getAssociationWithCallerChecks(associationId);
- return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ mTransportManager.detachSystemDataTransport(associationId);
}
@Override
@EnforcePermission(MANAGE_COMPANION_DEVICES)
public void enableSecureTransport(boolean enabled) {
enableSecureTransport_enforcePermission();
+
mTransportManager.enableSecureTransport(enabled);
}
@Override
- public void notifyDeviceAppeared(int associationId) {
- if (DEBUG) Log.i(TAG, "notifyDevice_Appeared() id=" + associationId);
-
- AssociationInfo association = getAssociationWithCallerChecks(associationId);
- if (!association.isSelfManaged()) {
- throw new IllegalArgumentException("Association with ID " + associationId
- + " is not self-managed. notifyDeviceAppeared(int) can only be called for"
- + " self-managed associations.");
- }
- // AssociationInfo class is immutable: create a new AssociationInfo object with updated
- // timestamp.
- association = (new AssociationInfo.Builder(association))
- .setLastTimeConnected(System.currentTimeMillis())
- .build();
- mAssociationStore.updateAssociation(association);
-
- mDevicePresenceMonitor.onSelfManagedDeviceConnected(associationId);
-
- final String deviceProfile = association.getDeviceProfile();
- if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
- Slog.i(TAG, "Enable hint mode for device device profile: " + deviceProfile);
- mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, true);
- }
+ public void enableSystemDataSync(int associationId, int flags) {
+ mAssociationRequestsProcessor.enableSystemDataSync(associationId, flags);
}
@Override
- public void notifyDeviceDisappeared(int associationId) {
- if (DEBUG) Log.i(TAG, "notifyDevice_Disappeared() id=" + associationId);
+ public void disableSystemDataSync(int associationId, int flags) {
+ mAssociationRequestsProcessor.disableSystemDataSync(associationId, flags);
+ }
- final AssociationInfo association = getAssociationWithCallerChecks(associationId);
- if (!association.isSelfManaged()) {
- throw new IllegalArgumentException("Association with ID " + associationId
- + " is not self-managed. notifyDeviceAppeared(int) can only be called for"
- + " self-managed associations.");
- }
+ @Override
+ public void enablePermissionsSync(int associationId) {
+ mSystemDataTransferProcessor.enablePermissionsSync(associationId);
+ }
- mDevicePresenceMonitor.onSelfManagedDeviceDisconnected(associationId);
+ @Override
+ public void disablePermissionsSync(int associationId) {
+ mSystemDataTransferProcessor.disablePermissionsSync(associationId);
+ }
- final String deviceProfile = association.getDeviceProfile();
- if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
- Slog.i(TAG, "Disable hint mode for device profile: " + deviceProfile);
- mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
- }
+ @Override
+ public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
+ return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ }
+
+ @Override
+ @EnforcePermission(REQUEST_COMPANION_SELF_MANAGED)
+ public void notifySelfManagedDeviceAppeared(int associationId) {
+ notifySelfManagedDeviceAppeared_enforcePermission();
+
+ mDevicePresenceMonitor.notifySelfManagedDevicePresenceEvent(associationId, true);
+ }
+
+ @Override
+ @EnforcePermission(REQUEST_COMPANION_SELF_MANAGED)
+ public void notifySelfManagedDeviceDisappeared(int associationId) {
+ notifySelfManagedDeviceDisappeared_enforcePermission();
+
+ mDevicePresenceMonitor.notifySelfManagedDevicePresenceEvent(associationId, false);
}
@Override
@@ -997,66 +672,6 @@
return mCompanionAppController.isCompanionApplicationBound(userId, packageName);
}
- private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
- boolean active) throws RemoteException {
- if (DEBUG) {
- Log.i(TAG, "registerDevicePresenceListenerActive()"
- + " active=" + active
- + " deviceAddress=" + deviceAddress);
- }
- final int userId = getCallingUserId();
- enforceCallerIsSystemOr(userId, packageName);
-
- AssociationInfo association = mAssociationStore.getFirstAssociationByAddress(
- userId, packageName, deviceAddress);
-
- if (association == null) {
- throw new RemoteException(new DeviceNotAssociatedException("App " + packageName
- + " is not associated with device " + deviceAddress
- + " for user " + userId));
- }
-
- processDevicePresenceListener(association, userId, packageName, active);
- }
-
- private void processDevicePresenceListener(AssociationInfo association,
- int userId, String packageName, boolean active) {
- // If already at specified state, then no-op.
- if (active == association.isNotifyOnDeviceNearby()) {
- if (DEBUG) Log.d(TAG, "Device presence listener is already at desired state.");
- return;
- }
-
- // AssociationInfo class is immutable: create a new AssociationInfo object with updated
- // flag.
- association = (new AssociationInfo.Builder(association))
- .setNotifyOnDeviceNearby(active)
- .build();
- // Do not need to call {@link BleCompanionDeviceScanner#restartScan()} since it will
- // trigger {@link BleCompanionDeviceScanner#restartScan(int, AssociationInfo)} when
- // an application sets/unsets the mNotifyOnDeviceNearby flag.
- mAssociationStore.updateAssociation(association);
-
- int associationId = association.getId();
- // If device is already present, then trigger callback.
- if (active && mDevicePresenceMonitor.isDevicePresent(associationId)) {
- Slog.i(TAG, "Device is already present. Triggering callback.");
- if (mDevicePresenceMonitor.isBlePresent(associationId)
- || mDevicePresenceMonitor.isSimulatePresent(associationId)) {
- onDeviceAppearedInternal(associationId);
- onDevicePresenceEventInternal(associationId, EVENT_BLE_APPEARED);
- } else if (mDevicePresenceMonitor.isBtConnected(associationId)) {
- onDevicePresenceEventInternal(associationId, EVENT_BT_CONNECTED);
- }
- }
-
- // If last listener is unregistered, then unbind application.
- if (!active && !shouldBindPackage(userId, packageName)) {
- if (DEBUG) Log.d(TAG, "Last listener unregistered. Unbinding application.");
- mCompanionAppController.unbindCompanionApplication(userId, packageName);
- }
- }
-
@Override
@EnforcePermission(ASSOCIATE_COMPANION_DEVICES)
public void createAssociation(String packageName, String macAddress, int userId,
@@ -1070,7 +685,8 @@
}
final MacAddress macAddressObj = MacAddress.fromString(macAddress);
- createNewAssociation(userId, packageName, macAddressObj, null, null, false);
+ mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddressObj,
+ null, null, null, false, null, null);
}
private void checkCanCallNotificationApi(String callingPackage, int userId) {
@@ -1099,9 +715,7 @@
@Override
public void setAssociationTag(int associationId, String tag) {
- AssociationInfo association = getAssociationWithCallerChecks(associationId);
- association = (new AssociationInfo.Builder(association)).setTag(tag).build();
- mAssociationStore.updateAssociation(association);
+ mAssociationRequestsProcessor.setAssociationTag(associationId, tag);
}
@Override
@@ -1146,14 +760,6 @@
}
}
- void createNewAssociation(@UserIdInt int userId, @NonNull String packageName,
- @Nullable MacAddress macAddress, @Nullable CharSequence displayName,
- @Nullable String deviceProfile, boolean isSelfManaged) {
- mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddress,
- displayName, deviceProfile, /* associatedDevice */ null, isSelfManaged,
- /* callback */ null, /* resultReceiver */ null);
- }
-
/**
* Update special access for the association's package
*/
@@ -1169,8 +775,6 @@
return;
}
- Slog.i(TAG, "Updating special access for package=[" + packageInfo.packageName + "]...");
-
if (containsEither(packageInfo.requestedPermissions,
android.Manifest.permission.RUN_IN_BACKGROUND,
android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
@@ -1280,29 +884,6 @@
}
};
- private final CompanionDevicePresenceMonitor.Callback mDevicePresenceCallback =
- new CompanionDevicePresenceMonitor.Callback() {
- @Override
- public void onDeviceAppeared(int associationId) {
- onDeviceAppearedInternal(associationId);
- }
-
- @Override
- public void onDeviceDisappeared(int associationId) {
- onDeviceDisappearedInternal(associationId);
- }
-
- @Override
- public void onDevicePresenceEvent(int associationId, int event) {
- onDevicePresenceEventInternal(associationId, event);
- }
-
- @Override
- public void onDevicePresenceEventByUuid(ObservableUuid uuid, int event) {
- onDevicePresenceEventByUuidInternal(uuid, event);
- }
- };
-
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public void onPackageRemoved(String packageName, int uid) {
@@ -1315,7 +896,7 @@
}
@Override
- public void onPackageModified(String packageName) {
+ public void onPackageModified(@NonNull String packageName) {
onPackageModifiedInternal(getChangingUserId(), packageName);
}
@@ -1325,28 +906,12 @@
}
};
- private static Map<String, Set<Integer>> deepUnmodifiableCopy(Map<String, Set<Integer>> orig) {
- final Map<String, Set<Integer>> copy = new HashMap<>();
-
- for (Map.Entry<String, Set<Integer>> entry : orig.entrySet()) {
- final Set<Integer> valueCopy = new HashSet<>(entry.getValue());
- copy.put(entry.getKey(), Collections.unmodifiableSet(valueCopy));
- }
-
- return Collections.unmodifiableMap(copy);
- }
-
private static <T> boolean containsEither(T[] array, T a, T b) {
return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
}
private class LocalService implements CompanionDeviceManagerServiceInternal {
@Override
- public void removeInactiveSelfManagedAssociations() {
- CompanionDeviceManagerService.this.removeInactiveSelfManagedAssociations();
- }
-
- @Override
public void registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback,
@CrossDeviceSyncControllerCallback.Type int type) {
if (CompanionDeviceConfig.isEnabled(
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
index cdf832f..e3b4c95 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java
@@ -28,11 +28,6 @@
*/
public interface CompanionDeviceManagerServiceInternal {
/**
- * @see CompanionDeviceManagerService#removeInactiveSelfManagedAssociations
- */
- void removeInactiveSelfManagedAssociations();
-
- /**
* Registers a callback from an InCallService / ConnectionService to CDM to process sync
* requests and perform call control actions.
*/
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index a7a73cb..a789384 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -18,8 +18,6 @@
import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC;
-import static com.android.server.companion.utils.PermissionsUtils.sanitizeWithCallerChecks;
-
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
import android.companion.Flags;
@@ -38,7 +36,7 @@
import com.android.server.companion.datatransfer.SystemDataTransferProcessor;
import com.android.server.companion.datatransfer.contextsync.BitmapUtils;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
-import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.DevicePresenceProcessor;
import com.android.server.companion.presence.ObservableUuid;
import com.android.server.companion.transport.CompanionTransportManager;
@@ -51,7 +49,7 @@
private final CompanionDeviceManagerService mService;
private final DisassociationProcessor mDisassociationProcessor;
private final AssociationStore mAssociationStore;
- private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
+ private final DevicePresenceProcessor mDevicePresenceProcessor;
private final CompanionTransportManager mTransportManager;
private final SystemDataTransferProcessor mSystemDataTransferProcessor;
@@ -60,7 +58,7 @@
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
AssociationStore associationStore,
- CompanionDevicePresenceMonitor devicePresenceMonitor,
+ DevicePresenceProcessor devicePresenceProcessor,
CompanionTransportManager transportManager,
SystemDataTransferProcessor systemDataTransferProcessor,
AssociationRequestsProcessor associationRequestsProcessor,
@@ -68,7 +66,7 @@
DisassociationProcessor disassociationProcessor) {
mService = service;
mAssociationStore = associationStore;
- mDevicePresenceMonitor = devicePresenceMonitor;
+ mDevicePresenceProcessor = devicePresenceProcessor;
mTransportManager = transportManager;
mSystemDataTransferProcessor = systemDataTransferProcessor;
mAssociationRequestsProcessor = associationRequestsProcessor;
@@ -85,7 +83,7 @@
if ("simulate-device-event".equals(cmd) && Flags.devicePresence()) {
associationId = getNextIntArgRequired();
int event = getNextIntArgRequired();
- mDevicePresenceMonitor.simulateDeviceEvent(associationId, event);
+ mDevicePresenceProcessor.simulateDeviceEvent(associationId, event);
return 0;
}
@@ -97,7 +95,7 @@
ObservableUuid observableUuid = new ObservableUuid(
userId, ParcelUuid.fromString(uuid), packageName,
System.currentTimeMillis());
- mDevicePresenceMonitor.simulateDeviceEventByUuid(observableUuid, event);
+ mDevicePresenceProcessor.simulateDeviceEventByUuid(observableUuid, event);
return 0;
}
@@ -124,8 +122,9 @@
String address = getNextArgRequired();
String deviceProfile = getNextArg();
final MacAddress macAddress = MacAddress.fromString(address);
- mService.createNewAssociation(userId, packageName, macAddress,
- /* displayName= */ deviceProfile, deviceProfile, false);
+ mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddress,
+ deviceProfile, deviceProfile, /* associatedDevice */ null, false,
+ /* callback */ null, /* resultReceiver */ null);
}
break;
@@ -134,8 +133,13 @@
final String packageName = getNextArgRequired();
final String address = getNextArgRequired();
final AssociationInfo association =
- mService.getAssociationWithCallerChecks(userId, packageName, address);
- mDisassociationProcessor.disassociate(association.getId());
+ mAssociationStore.getFirstAssociationByAddress(userId, packageName,
+ address);
+ if (association == null) {
+ out.println("Association doesn't exist.");
+ } else {
+ mDisassociationProcessor.disassociate(association.getId());
+ }
}
break;
@@ -144,9 +148,7 @@
final List<AssociationInfo> userAssociations =
mAssociationStore.getAssociationsByUser(userId);
for (AssociationInfo association : userAssociations) {
- if (sanitizeWithCallerChecks(mService.getContext(), association) != null) {
- mDisassociationProcessor.disassociate(association.getId());
- }
+ mDisassociationProcessor.disassociate(association.getId());
}
}
break;
@@ -157,12 +159,12 @@
case "simulate-device-appeared":
associationId = getNextIntArgRequired();
- mDevicePresenceMonitor.simulateDeviceEvent(associationId, /* event */ 0);
+ mDevicePresenceProcessor.simulateDeviceEvent(associationId, /* event */ 0);
break;
case "simulate-device-disappeared":
associationId = getNextIntArgRequired();
- mDevicePresenceMonitor.simulateDeviceEvent(associationId, /* event */ 1);
+ mDevicePresenceProcessor.simulateDeviceEvent(associationId, /* event */ 1);
break;
case "get-backup-payload": {
@@ -410,10 +412,9 @@
pw.println(" Remove an existing Association.");
pw.println(" disassociate-all USER_ID");
pw.println(" Remove all Associations for a user.");
- pw.println(" clear-association-memory-cache");
+ pw.println(" refresh-cache");
pw.println(" Clear the in-memory association cache and reload all association ");
- pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
- pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+ pw.println(" information from disk. USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
pw.println(" simulate-device-appeared ASSOCIATION_ID");
pw.println(" Make CDM act as if the given companion device has appeared.");
diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
index a02d9f9..a18776e 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
@@ -145,7 +145,8 @@
/**
* Handle incoming {@link AssociationRequest}s, sent via
- * {@link android.companion.ICompanionDeviceManager#associate(AssociationRequest, IAssociationRequestCallback, String, int)}
+ * {@link android.companion.ICompanionDeviceManager#associate(AssociationRequest,
+ * IAssociationRequestCallback, String, int)}
*/
public void processNewAssociationRequest(@NonNull AssociationRequest request,
@NonNull String packageName, @UserIdInt int userId,
@@ -212,7 +213,8 @@
// 2b.4. Send the PendingIntent back to the app.
try {
callback.onAssociationPending(pendingIntent);
- } catch (RemoteException ignore) { }
+ } catch (RemoteException ignore) {
+ }
}
/**
@@ -252,7 +254,8 @@
// forward it back to the application via the callback.
try {
callback.onFailure(e.getMessage());
- } catch (RemoteException ignore) { }
+ } catch (RemoteException ignore) {
+ }
return;
}
@@ -322,7 +325,8 @@
* Enable system data sync.
*/
public void enableSystemDataSync(int associationId, int flags) {
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() | flags).build();
mAssociationStore.updateAssociation(updated);
@@ -332,12 +336,23 @@
* Disable system data sync.
*/
public void disableSystemDataSync(int associationId, int flags) {
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() & (~flags)).build();
mAssociationStore.updateAssociation(updated);
}
+ /**
+ * Set association tag.
+ */
+ public void setAssociationTag(int associationId, String tag) {
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
+ association = (new AssociationInfo.Builder(association)).setTag(tag).build();
+ mAssociationStore.updateAssociation(association);
+ }
+
private void sendCallbackAndFinish(@Nullable AssociationInfo association,
@Nullable IAssociationRequestCallback callback,
@Nullable ResultReceiver resultReceiver) {
@@ -396,14 +411,14 @@
// If the application already has a pending association request, that PendingIntent
// will be cancelled except application wants to cancel the request by the system.
return Binder.withCleanCallingIdentity(() ->
- PendingIntent.getActivityAsUser(
- mContext, /*requestCode */ packageUid, intent,
- FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE,
- ActivityOptions.makeBasic()
- .setPendingIntentCreatorBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
- .toBundle(),
- UserHandle.CURRENT)
+ PendingIntent.getActivityAsUser(
+ mContext, /*requestCode */ packageUid, intent,
+ FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE,
+ ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ .toBundle(),
+ UserHandle.CURRENT)
);
}
diff --git a/services/companion/java/com/android/server/companion/association/AssociationStore.java b/services/companion/java/com/android/server/companion/association/AssociationStore.java
index edebb55..ae2b708 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationStore.java
@@ -18,6 +18,7 @@
import static com.android.server.companion.utils.MetricUtils.logCreateAssociation;
import static com.android.server.companion.utils.MetricUtils.logRemoveAssociation;
+import static com.android.server.companion.utils.PermissionsUtils.checkCallerCanManageAssociationsForPackage;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -26,6 +27,7 @@
import android.annotation.UserIdInt;
import android.companion.AssociationInfo;
import android.companion.IOnAssociationsChangedListener;
+import android.content.Context;
import android.content.pm.UserInfo;
import android.net.MacAddress;
import android.os.Binder;
@@ -57,21 +59,22 @@
@SuppressLint("LongLogTag")
public class AssociationStore {
- @IntDef(prefix = { "CHANGE_TYPE_" }, value = {
+ @IntDef(prefix = {"CHANGE_TYPE_"}, value = {
CHANGE_TYPE_ADDED,
CHANGE_TYPE_REMOVED,
CHANGE_TYPE_UPDATED_ADDRESS_CHANGED,
CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface ChangeType {}
+ public @interface ChangeType {
+ }
public static final int CHANGE_TYPE_ADDED = 0;
public static final int CHANGE_TYPE_REMOVED = 1;
public static final int CHANGE_TYPE_UPDATED_ADDRESS_CHANGED = 2;
public static final int CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED = 3;
- /** Listener for any changes to associations. */
+ /** Listener for any changes to associations. */
public interface OnChangeListener {
/**
* Called when there are association changes.
@@ -100,25 +103,30 @@
/**
* Called when an association is added.
*/
- default void onAssociationAdded(AssociationInfo association) {}
+ default void onAssociationAdded(AssociationInfo association) {
+ }
/**
* Called when an association is removed.
*/
- default void onAssociationRemoved(AssociationInfo association) {}
+ default void onAssociationRemoved(AssociationInfo association) {
+ }
/**
* Called when an association is updated.
*/
- default void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {}
+ default void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {
+ }
}
private static final String TAG = "CDM_AssociationStore";
- private final Object mLock = new Object();
-
+ private final Context mContext;
+ private final UserManager mUserManager;
+ private final AssociationDiskStore mDiskStore;
private final ExecutorService mExecutor;
+ private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mPersisted = false;
@GuardedBy("mLock")
@@ -132,10 +140,9 @@
private final RemoteCallbackList<IOnAssociationsChangedListener> mRemoteListeners =
new RemoteCallbackList<>();
- private final UserManager mUserManager;
- private final AssociationDiskStore mDiskStore;
-
- public AssociationStore(UserManager userManager, AssociationDiskStore diskStore) {
+ public AssociationStore(Context context, UserManager userManager,
+ AssociationDiskStore diskStore) {
+ mContext = context;
mUserManager = userManager;
mDiskStore = diskStore;
mExecutor = Executors.newSingleThreadExecutor();
@@ -202,7 +209,7 @@
synchronized (mLock) {
if (mIdToAssociationMap.containsKey(id)) {
- Slog.e(TAG, "Association with id=[" + id + "] already exists.");
+ Slog.e(TAG, "Association id=[" + id + "] already exists.");
return;
}
@@ -449,6 +456,26 @@
}
/**
+ * Get association by id with caller checks.
+ */
+ @NonNull
+ public AssociationInfo getAssociationWithCallerChecks(int associationId) {
+ AssociationInfo association = getAssociationById(associationId);
+ if (association == null) {
+ throw new IllegalArgumentException(
+ "getAssociationWithCallerChecks() Association id=[" + associationId
+ + "] doesn't exist.");
+ }
+ if (checkCallerCanManageAssociationsForPackage(mContext, association.getUserId(),
+ association.getPackageName())) {
+ return association;
+ }
+
+ throw new IllegalArgumentException(
+ "The caller can't interact with the association id=[" + associationId + "].");
+ }
+
+ /**
* Register a local listener for association changes.
*/
public void registerLocalListener(@NonNull OnChangeListener listener) {
diff --git a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
index ec897791..20de121 100644
--- a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java
@@ -33,18 +33,19 @@
import android.os.UserHandle;
import android.util.Slog;
-import com.android.server.companion.CompanionApplicationController;
import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
-import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.CompanionAppBinder;
+import com.android.server.companion.presence.DevicePresenceProcessor;
import com.android.server.companion.transport.CompanionTransportManager;
/**
- * A class response for Association removal.
+ * This class responsible for disassociation.
*/
@SuppressLint("LongLogTag")
public class DisassociationProcessor {
private static final String TAG = "CDM_DisassociationProcessor";
+
@NonNull
private final Context mContext;
@NonNull
@@ -52,11 +53,11 @@
@NonNull
private final PackageManagerInternal mPackageManagerInternal;
@NonNull
- private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
+ private final DevicePresenceProcessor mDevicePresenceMonitor;
@NonNull
private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
@NonNull
- private final CompanionApplicationController mCompanionAppController;
+ private final CompanionAppBinder mCompanionAppController;
@NonNull
private final CompanionTransportManager mTransportManager;
private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
@@ -66,8 +67,8 @@
@NonNull ActivityManager activityManager,
@NonNull AssociationStore associationStore,
@NonNull PackageManagerInternal packageManager,
- @NonNull CompanionDevicePresenceMonitor devicePresenceMonitor,
- @NonNull CompanionApplicationController applicationController,
+ @NonNull DevicePresenceProcessor devicePresenceMonitor,
+ @NonNull CompanionAppBinder applicationController,
@NonNull SystemDataTransferRequestStore systemDataTransferRequestStore,
@NonNull CompanionTransportManager companionTransportManager) {
mContext = context;
@@ -89,11 +90,7 @@
public void disassociate(int id) {
Slog.i(TAG, "Disassociating id=[" + id + "]...");
- final AssociationInfo association = mAssociationStore.getAssociationById(id);
- if (association == null) {
- Slog.e(TAG, "Can't disassociate id=[" + id + "]. It doesn't exist.");
- return;
- }
+ final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(id);
final int userId = association.getUserId();
final String packageName = association.getPackageName();
@@ -118,12 +115,12 @@
return;
}
- // Association cleanup.
- mAssociationStore.removeAssociation(association.getId());
- mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, id);
-
// Detach transport if exists
- mTransportManager.detachSystemDataTransport(packageName, userId, id);
+ mTransportManager.detachSystemDataTransport(id);
+
+ // Association cleanup.
+ mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, id);
+ mAssociationStore.removeAssociation(association.getId());
// If role is not in use by other associations, revoke the role.
// Do not need to remove the system role since it was pre-granted by the system.
@@ -147,6 +144,24 @@
}
}
+ /**
+ * @deprecated Use {@link #disassociate(int)} instead.
+ */
+ @Deprecated
+ public void disassociate(int userId, String packageName, String macAddress) {
+ AssociationInfo association = mAssociationStore.getFirstAssociationByAddress(userId,
+ packageName, macAddress);
+
+ if (association == null) {
+ throw new IllegalArgumentException(
+ "Association for mac address=[" + macAddress + "] doesn't exist");
+ }
+
+ mAssociationStore.getAssociationWithCallerChecks(association.getId());
+
+ disassociate(association.getId());
+ }
+
@SuppressLint("MissingPermission")
private int getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) {
return Binder.withCleanCallingIdentity(() -> {
@@ -163,7 +178,7 @@
() -> mActivityManager.addOnUidImportanceListener(
mOnPackageVisibilityChangeListener,
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE));
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException e) {
Slog.e(TAG, "Failed to start listening to uid importance changes.");
}
}
diff --git a/services/companion/java/com/android/server/companion/association/InactiveAssociationsRemovalService.java b/services/companion/java/com/android/server/companion/association/InactiveAssociationsRemovalService.java
index f287315..b52904a 100644
--- a/services/companion/java/com/android/server/companion/association/InactiveAssociationsRemovalService.java
+++ b/services/companion/java/com/android/server/companion/association/InactiveAssociationsRemovalService.java
@@ -22,15 +22,14 @@
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.companion.AssociationInfo;
import android.content.ComponentName;
import android.content.Context;
+import android.os.SystemProperties;
import android.util.Slog;
-import com.android.server.LocalServices;
-import com.android.server.companion.CompanionDeviceManagerServiceInternal;
-
/**
- * A Job Service responsible for clean up idle self-managed associations.
+ * A Job Service responsible for clean up self-managed associations if it's idle for 90 days.
*
* The job will be executed only if the device is charging and in idle mode due to the application
* will be killed if association/role are revoked. See {@link DisassociationProcessor}
@@ -41,14 +40,25 @@
private static final String JOB_NAMESPACE = "companion";
private static final int JOB_ID = 1;
private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
+ private static final String SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW =
+ "debug.cdm.cdmservice.removal_time_window";
+ private static final long ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT = DAYS.toMillis(90);
+
+ private final AssociationStore mAssociationStore;
+ private final DisassociationProcessor mDisassociationProcessor;
+
+ public InactiveAssociationsRemovalService(AssociationStore associationStore,
+ DisassociationProcessor disassociationProcessor) {
+ mAssociationStore = associationStore;
+ mDisassociationProcessor = disassociationProcessor;
+ }
@Override
public boolean onStartJob(final JobParameters params) {
Slog.i(TAG, "Execute the Association Removal job");
- // Special policy for selfManaged that need to revoke associations if the device
- // does not connect for 90 days.
- LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
- .removeInactiveSelfManagedAssociations();
+
+ removeIdleSelfManagedAssociations();
+
jobFinished(params, false);
return true;
}
@@ -77,4 +87,29 @@
.build();
jobScheduler.schedule(job);
}
+
+ /**
+ * Remove idle self-managed associations.
+ */
+ public void removeIdleSelfManagedAssociations() {
+ final long currentTime = System.currentTimeMillis();
+ long removalWindow = SystemProperties.getLong(SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW, -1);
+ if (removalWindow <= 0) {
+ // 0 or negative values indicate that the sysprop was never set or should be ignored.
+ removalWindow = ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT;
+ }
+
+ for (AssociationInfo association : mAssociationStore.getAssociations()) {
+ if (!association.isSelfManaged()) continue;
+
+ final boolean isInactive =
+ currentTime - association.getLastTimeConnectedMs() >= removalWindow;
+ if (!isInactive) continue;
+
+ final int id = association.getId();
+
+ Slog.i(TAG, "Removing inactive self-managed association id=" + id);
+ mDisassociationProcessor.disassociate(id);
+ }
+ }
}
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 c5ca0bf..9069689 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -31,7 +31,6 @@
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
-import android.companion.DeviceNotAssociatedException;
import android.companion.IOnMessageReceivedListener;
import android.companion.ISystemDataTransferCallback;
import android.companion.datatransfer.PermissionSyncRequest;
@@ -56,7 +55,6 @@
import com.android.server.companion.association.AssociationStore;
import com.android.server.companion.transport.CompanionTransportManager;
import com.android.server.companion.utils.PackageUtils;
-import com.android.server.companion.utils.PermissionsUtils;
import java.util.List;
import java.util.concurrent.ExecutorService;
@@ -120,28 +118,10 @@
}
/**
- * Resolve the requested association, throwing if the caller doesn't have
- * adequate permissions.
- */
- @NonNull
- private AssociationInfo resolveAssociation(String packageName, int userId,
- int associationId) {
- AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association);
- if (association == null) {
- throw new DeviceNotAssociatedException("Association "
- + associationId + " is not associated with the app " + packageName
- + " for user " + userId);
- }
- return association;
- }
-
- /**
* Return whether the user has consented to the permission transfer for the association.
*/
- public boolean isPermissionTransferUserConsented(String packageName, @UserIdInt int userId,
- int associationId) {
- resolveAssociation(packageName, userId, associationId);
+ public boolean isPermissionTransferUserConsented(int associationId) {
+ mAssociationStore.getAssociationWithCallerChecks(associationId);
PermissionSyncRequest request = getPermissionSyncRequest(associationId);
if (request == null) {
@@ -167,7 +147,8 @@
return null;
}
- final AssociationInfo association = resolveAssociation(packageName, userId, associationId);
+ final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
Slog.i(LOG_TAG, "Creating permission sync intent for userId [" + userId
+ "] associationId [" + associationId + "]");
@@ -207,7 +188,7 @@
Slog.i(LOG_TAG, "Start system data transfer for package [" + packageName
+ "] userId [" + userId + "] associationId [" + associationId + "]");
- final AssociationInfo association = resolveAssociation(packageName, userId, associationId);
+ mAssociationStore.getAssociationWithCallerChecks(associationId);
// Check if the request has been consented by the user.
PermissionSyncRequest request = getPermissionSyncRequest(associationId);
@@ -239,24 +220,20 @@
* Enable perm sync for the association
*/
public void enablePermissionsSync(int associationId) {
- Binder.withCleanCallingIdentity(() -> {
- int userId = mAssociationStore.getAssociationById(associationId).getUserId();
- PermissionSyncRequest request = new PermissionSyncRequest(associationId);
- request.setUserConsented(true);
- mSystemDataTransferRequestStore.writeRequest(userId, request);
- });
+ int userId = mAssociationStore.getAssociationWithCallerChecks(associationId).getUserId();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserConsented(true);
+ mSystemDataTransferRequestStore.writeRequest(userId, request);
}
/**
* Disable perm sync for the association
*/
public void disablePermissionsSync(int associationId) {
- Binder.withCleanCallingIdentity(() -> {
- int userId = mAssociationStore.getAssociationById(associationId).getUserId();
- PermissionSyncRequest request = new PermissionSyncRequest(associationId);
- request.setUserConsented(false);
- mSystemDataTransferRequestStore.writeRequest(userId, request);
- });
+ int userId = mAssociationStore.getAssociationWithCallerChecks(associationId).getUserId();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserConsented(false);
+ mSystemDataTransferRequestStore.writeRequest(userId, request);
}
/**
@@ -264,18 +241,17 @@
*/
@Nullable
public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
- return Binder.withCleanCallingIdentity(() -> {
- int userId = mAssociationStore.getAssociationById(associationId).getUserId();
- List<SystemDataTransferRequest> requests =
- mSystemDataTransferRequestStore.readRequestsByAssociationId(userId,
- associationId);
- for (SystemDataTransferRequest request : requests) {
- if (request instanceof PermissionSyncRequest) {
- return (PermissionSyncRequest) request;
- }
+ int userId = mAssociationStore.getAssociationWithCallerChecks(associationId)
+ .getUserId();
+ List<SystemDataTransferRequest> requests =
+ mSystemDataTransferRequestStore.readRequestsByAssociationId(userId,
+ associationId);
+ for (SystemDataTransferRequest request : requests) {
+ if (request instanceof PermissionSyncRequest) {
+ return (PermissionSyncRequest) request;
}
- return null;
- });
+ }
+ return null;
}
/**
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index c89ce11..9c37881 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -33,7 +33,7 @@
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_MATCH_LOST;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
-import static com.android.server.companion.presence.CompanionDevicePresenceMonitor.DEBUG;
+import static com.android.server.companion.presence.DevicePresenceProcessor.DEBUG;
import static com.android.server.companion.utils.Utils.btDeviceToString;
import static java.util.Objects.requireNonNull;
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index cb363a7..2d345c4 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -19,7 +19,7 @@
import static android.companion.DevicePresenceEvent.EVENT_BT_CONNECTED;
import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
-import static com.android.server.companion.presence.CompanionDevicePresenceMonitor.DEBUG;
+import static com.android.server.companion.presence.DevicePresenceProcessor.DEBUG;
import static com.android.server.companion.utils.Utils.btDeviceToString;
import android.annotation.NonNull;
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java b/services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java
new file mode 100644
index 0000000..4ba4e2c
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/presence/CompanionAppBinder.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.presence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
+import android.companion.CompanionDeviceService;
+import android.companion.DevicePresenceEvent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManagerInternal;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.PerUser;
+import com.android.server.companion.CompanionDeviceManagerService;
+import com.android.server.companion.association.AssociationStore;
+import com.android.server.companion.utils.PackageUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Manages communication with companion applications via
+ * {@link android.companion.ICompanionDeviceService} interface, including "connecting" (binding) to
+ * the services, maintaining the connection (the binding), and invoking callback methods such as
+ * {@link CompanionDeviceService#onDeviceAppeared(AssociationInfo)},
+ * {@link CompanionDeviceService#onDeviceDisappeared(AssociationInfo)} and
+ * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} in the
+ * application process.
+ *
+ * <p>
+ * The following is the list of the APIs provided by {@link CompanionAppBinder} (to be
+ * utilized by {@link CompanionDeviceManagerService}):
+ * <ul>
+ * <li> {@link #bindCompanionApplication(int, String, boolean, CompanionServiceConnector.Listener)}
+ * <li> {@link #unbindCompanionApplication(int, String)}
+ * <li> {@link #isCompanionApplicationBound(int, String)}
+ * <li> {@link #isRebindingCompanionApplicationScheduled(int, String)}
+ * </ul>
+ *
+ * @see CompanionDeviceService
+ * @see android.companion.ICompanionDeviceService
+ * @see CompanionServiceConnector
+ */
+@SuppressLint("LongLogTag")
+public class CompanionAppBinder {
+ private static final String TAG = "CDM_CompanionAppBinder";
+
+ private static final long REBIND_TIMEOUT = 10 * 1000; // 10 sec
+
+ @NonNull
+ private final Context mContext;
+ @NonNull
+ private final AssociationStore mAssociationStore;
+ @NonNull
+ private final ObservableUuidStore mObservableUuidStore;
+ @NonNull
+ private final CompanionServicesRegister mCompanionServicesRegister;
+
+ private final PowerManagerInternal mPowerManagerInternal;
+
+ @NonNull
+ @GuardedBy("mBoundCompanionApplications")
+ private final AndroidPackageMap<List<CompanionServiceConnector>>
+ mBoundCompanionApplications;
+ @NonNull
+ @GuardedBy("mScheduledForRebindingCompanionApplications")
+ private final AndroidPackageMap<Boolean> mScheduledForRebindingCompanionApplications;
+
+ public CompanionAppBinder(@NonNull Context context,
+ @NonNull AssociationStore associationStore,
+ @NonNull ObservableUuidStore observableUuidStore,
+ @NonNull PowerManagerInternal powerManagerInternal) {
+ mContext = context;
+ mAssociationStore = associationStore;
+ mObservableUuidStore = observableUuidStore;
+ mPowerManagerInternal = powerManagerInternal;
+ mCompanionServicesRegister = new CompanionServicesRegister();
+ mBoundCompanionApplications = new AndroidPackageMap<>();
+ mScheduledForRebindingCompanionApplications = new AndroidPackageMap<>();
+ }
+
+ /**
+ * On package changed.
+ */
+ public void onPackagesChanged(@UserIdInt int userId) {
+ mCompanionServicesRegister.invalidate(userId);
+ }
+
+ /**
+ * CDM binds to the companion app.
+ */
+ public void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ boolean isSelfManaged, CompanionServiceConnector.Listener listener) {
+ Slog.i(TAG, "Binding user=[" + userId + "], package=[" + packageName + "], isSelfManaged=["
+ + isSelfManaged + "]...");
+
+ final List<ComponentName> companionServices =
+ mCompanionServicesRegister.forPackage(userId, packageName);
+ if (companionServices.isEmpty()) {
+ Slog.e(TAG, "Can not bind companion applications u" + userId + "/" + packageName + ": "
+ + "eligible CompanionDeviceService not found.\n"
+ + "A CompanionDeviceService should declare an intent-filter for "
+ + "\"android.companion.CompanionDeviceService\" action and require "
+ + "\"android.permission.BIND_COMPANION_DEVICE_SERVICE\" permission.");
+ return;
+ }
+
+ final List<CompanionServiceConnector> serviceConnectors = new ArrayList<>();
+ synchronized (mBoundCompanionApplications) {
+ if (mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
+ Slog.w(TAG, "The package is ALREADY bound.");
+ return;
+ }
+
+ for (int i = 0; i < companionServices.size(); i++) {
+ boolean isPrimary = i == 0;
+ serviceConnectors.add(CompanionServiceConnector.newInstance(mContext, userId,
+ companionServices.get(i), isSelfManaged, isPrimary));
+ }
+
+ mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
+ }
+
+ // Set listeners for both Primary and Secondary connectors.
+ for (CompanionServiceConnector serviceConnector : serviceConnectors) {
+ serviceConnector.setListener(listener);
+ }
+
+ // Now "bind" all the connectors: the primary one and the rest of them.
+ for (CompanionServiceConnector serviceConnector : serviceConnectors) {
+ serviceConnector.connect();
+ }
+ }
+
+ /**
+ * CDM unbinds the companion app.
+ */
+ public void unbindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
+ Slog.i(TAG, "Unbinding user=[" + userId + "], package=[" + packageName + "]...");
+
+ final List<CompanionServiceConnector> serviceConnectors;
+
+ synchronized (mBoundCompanionApplications) {
+ serviceConnectors = mBoundCompanionApplications.removePackage(userId, packageName);
+ }
+
+ synchronized (mScheduledForRebindingCompanionApplications) {
+ mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
+ }
+
+ if (serviceConnectors == null) {
+ Slog.e(TAG, "The package is not bound.");
+ return;
+ }
+
+ for (CompanionServiceConnector serviceConnector : serviceConnectors) {
+ serviceConnector.postUnbind();
+ }
+ }
+
+ /**
+ * @return whether the companion application is bound now.
+ */
+ public boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) {
+ synchronized (mBoundCompanionApplications) {
+ return mBoundCompanionApplications.containsValueForPackage(userId, packageName);
+ }
+ }
+
+ /**
+ * Remove bound apps for package.
+ */
+ public void removePackage(int userId, String packageName) {
+ synchronized (mBoundCompanionApplications) {
+ mBoundCompanionApplications.removePackage(userId, packageName);
+ }
+ }
+
+ /**
+ * Schedule rebinding for the package.
+ */
+ public void scheduleRebinding(@UserIdInt int userId, @NonNull String packageName,
+ CompanionServiceConnector serviceConnector) {
+ Slog.i(TAG, "scheduleRebinding() " + userId + "/" + packageName);
+
+ if (isRebindingCompanionApplicationScheduled(userId, packageName)) {
+ Slog.i(TAG, "CompanionApplication rebinding has been scheduled, skipping "
+ + serviceConnector.getComponentName());
+ return;
+ }
+
+ if (serviceConnector.isPrimary()) {
+ synchronized (mScheduledForRebindingCompanionApplications) {
+ mScheduledForRebindingCompanionApplications.setValueForPackage(
+ userId, packageName, true);
+ }
+ }
+
+ // Rebinding in 10 seconds.
+ Handler.getMain().postDelayed(() ->
+ onRebindingCompanionApplicationTimeout(userId, packageName,
+ serviceConnector),
+ REBIND_TIMEOUT);
+ }
+
+ private boolean isRebindingCompanionApplicationScheduled(
+ @UserIdInt int userId, @NonNull String packageName) {
+ synchronized (mScheduledForRebindingCompanionApplications) {
+ return mScheduledForRebindingCompanionApplications.containsValueForPackage(
+ userId, packageName);
+ }
+ }
+
+ private void onRebindingCompanionApplicationTimeout(
+ @UserIdInt int userId, @NonNull String packageName,
+ @NonNull CompanionServiceConnector serviceConnector) {
+ // Re-mark the application is bound.
+ if (serviceConnector.isPrimary()) {
+ synchronized (mBoundCompanionApplications) {
+ if (!mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
+ List<CompanionServiceConnector> serviceConnectors =
+ Collections.singletonList(serviceConnector);
+ mBoundCompanionApplications.setValueForPackage(userId, packageName,
+ serviceConnectors);
+ }
+ }
+
+ synchronized (mScheduledForRebindingCompanionApplications) {
+ mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
+ }
+ }
+
+ serviceConnector.connect();
+ }
+
+ /**
+ * Dump bound apps.
+ */
+ public void dump(@NonNull PrintWriter out) {
+ out.append("Companion Device Application Controller: \n");
+
+ synchronized (mBoundCompanionApplications) {
+ out.append(" Bound Companion Applications: ");
+ if (mBoundCompanionApplications.size() == 0) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ mBoundCompanionApplications.dump(out);
+ }
+ }
+
+ out.append(" Companion Applications Scheduled For Rebinding: ");
+ synchronized (mScheduledForRebindingCompanionApplications) {
+ if (mScheduledForRebindingCompanionApplications.size() == 0) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ mScheduledForRebindingCompanionApplications.dump(out);
+ }
+ }
+ }
+
+ @Nullable
+ CompanionServiceConnector getPrimaryServiceConnector(
+ @UserIdInt int userId, @NonNull String packageName) {
+ final List<CompanionServiceConnector> connectors;
+ synchronized (mBoundCompanionApplications) {
+ connectors = mBoundCompanionApplications.getValueForPackage(userId, packageName);
+ }
+ return connectors != null ? connectors.get(0) : null;
+ }
+
+ private class CompanionServicesRegister extends PerUser<Map<String, List<ComponentName>>> {
+ @Override
+ public synchronized @NonNull Map<String, List<ComponentName>> forUser(
+ @UserIdInt int userId) {
+ return super.forUser(userId);
+ }
+
+ synchronized @NonNull List<ComponentName> forPackage(
+ @UserIdInt int userId, @NonNull String packageName) {
+ return forUser(userId).getOrDefault(packageName, Collections.emptyList());
+ }
+
+ synchronized void invalidate(@UserIdInt int userId) {
+ remove(userId);
+ }
+
+ @Override
+ protected final @NonNull Map<String, List<ComponentName>> create(@UserIdInt int userId) {
+ return PackageUtils.getCompanionServicesForUser(mContext, userId);
+ }
+ }
+
+ /**
+ * Associates an Android package (defined by userId + packageName) with a value of type T.
+ */
+ private static class AndroidPackageMap<T> extends SparseArray<Map<String, T>> {
+
+ void setValueForPackage(
+ @UserIdInt int userId, @NonNull String packageName, @NonNull T value) {
+ Map<String, T> forUser = get(userId);
+ if (forUser == null) {
+ forUser = /* Map<String, T> */ new HashMap();
+ put(userId, forUser);
+ }
+
+ forUser.put(packageName, value);
+ }
+
+ boolean containsValueForPackage(@UserIdInt int userId, @NonNull String packageName) {
+ final Map<String, ?> forUser = get(userId);
+ return forUser != null && forUser.containsKey(packageName);
+ }
+
+ T getValueForPackage(@UserIdInt int userId, @NonNull String packageName) {
+ final Map<String, T> forUser = get(userId);
+ return forUser != null ? forUser.get(packageName) : null;
+ }
+
+ T removePackage(@UserIdInt int userId, @NonNull String packageName) {
+ final Map<String, T> forUser = get(userId);
+ if (forUser == null) return null;
+ return forUser.remove(packageName);
+ }
+
+ void dump() {
+ if (size() == 0) {
+ Log.d(TAG, "<empty>");
+ return;
+ }
+
+ for (int i = 0; i < size(); i++) {
+ final int userId = keyAt(i);
+ final Map<String, T> forUser = get(userId);
+ if (forUser.isEmpty()) {
+ Log.d(TAG, "u" + userId + ": <empty>");
+ }
+
+ for (Map.Entry<String, T> packageValue : forUser.entrySet()) {
+ final String packageName = packageValue.getKey();
+ final T value = packageValue.getValue();
+ Log.d(TAG, "u" + userId + "\\" + packageName + " -> " + value);
+ }
+ }
+ }
+
+ private void dump(@NonNull PrintWriter out) {
+ for (int i = 0; i < size(); i++) {
+ final int userId = keyAt(i);
+ final Map<String, T> forUser = get(userId);
+ if (forUser.isEmpty()) {
+ out.append(" u").append(String.valueOf(userId)).append(": <empty>\n");
+ }
+
+ for (Map.Entry<String, T> packageValue : forUser.entrySet()) {
+ final String packageName = packageValue.getKey();
+ final T value = packageValue.getValue();
+ out.append(" u").append(String.valueOf(userId)).append("\\")
+ .append(packageName).append(" -> ")
+ .append(value.toString()).append('\n');
+ }
+ }
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
deleted file mode 100644
index 7a1a83f..0000000
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.companion.presence;
-
-import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
-import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED;
-import static android.companion.DevicePresenceEvent.EVENT_BT_CONNECTED;
-import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
-import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_APPEARED;
-import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_DISAPPEARED;
-import static android.os.Process.ROOT_UID;
-import static android.os.Process.SHELL_UID;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.annotation.TestApi;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.companion.AssociationInfo;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelUuid;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.companion.association.AssociationStore;
-
-import java.io.PrintWriter;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Class responsible for monitoring companion devices' "presence" status (i.e.
- * connected/disconnected for Bluetooth devices; nearby or not for BLE devices).
- *
- * <p>
- * Should only be used by
- * {@link com.android.server.companion.CompanionDeviceManagerService CompanionDeviceManagerService}
- * to which it provides the following API:
- * <ul>
- * <li> {@link #onSelfManagedDeviceConnected(int)}
- * <li> {@link #onSelfManagedDeviceDisconnected(int)}
- * <li> {@link #isDevicePresent(int)}
- * <li> {@link Callback#onDeviceAppeared(int) Callback.onDeviceAppeared(int)}
- * <li> {@link Callback#onDeviceDisappeared(int) Callback.onDeviceDisappeared(int)}
- * <li> {@link Callback#onDevicePresenceEvent(int, int)}}
- * </ul>
- */
-@SuppressLint("LongLogTag")
-public class CompanionDevicePresenceMonitor implements AssociationStore.OnChangeListener,
- BluetoothCompanionDeviceConnectionListener.Callback, BleCompanionDeviceScanner.Callback {
- static final boolean DEBUG = false;
- private static final String TAG = "CDM_CompanionDevicePresenceMonitor";
-
- /** Callback for notifying about changes to status of companion devices. */
- public interface Callback {
- /** Invoked when companion device is found nearby or connects. */
- void onDeviceAppeared(int associationId);
-
- /** Invoked when a companion device no longer seen nearby or disconnects. */
- void onDeviceDisappeared(int associationId);
-
- /** Invoked when device has corresponding event changes. */
- void onDevicePresenceEvent(int associationId, int event);
-
- /** Invoked when device has corresponding event changes base on the UUID */
- void onDevicePresenceEventByUuid(ObservableUuid uuid, int event);
- }
-
- private final @NonNull AssociationStore mAssociationStore;
- private final @NonNull ObservableUuidStore mObservableUuidStore;
- private final @NonNull Callback mCallback;
- private final @NonNull BluetoothCompanionDeviceConnectionListener mBtConnectionListener;
- private final @NonNull BleCompanionDeviceScanner mBleScanner;
-
- // NOTE: Same association may appear in more than one of the following sets at the same time.
- // (E.g. self-managed devices that have MAC addresses, could be reported as present by their
- // companion applications, while at the same be connected via BT, or detected nearby by BLE
- // scanner)
- private final @NonNull Set<Integer> mConnectedBtDevices = new HashSet<>();
- private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>();
- private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>();
- private final @NonNull Set<ParcelUuid> mConnectedUuidDevices = new HashSet<>();
- @GuardedBy("mBtDisconnectedDevices")
- private final @NonNull Set<Integer> mBtDisconnectedDevices = new HashSet<>();
-
- // A map to track device presence within 10 seconds of Bluetooth disconnection.
- // The key is the association ID, and the boolean value indicates if the device
- // was detected again within that time frame.
- @GuardedBy("mBtDisconnectedDevices")
- private final @NonNull SparseBooleanArray mBtDisconnectedDevicesBlePresence =
- new SparseBooleanArray();
-
- // Tracking "simulated" presence. Used for debugging and testing only.
- private final @NonNull Set<Integer> mSimulated = new HashSet<>();
- private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
- new SimulatedDevicePresenceSchedulerHelper();
-
- private final BleDeviceDisappearedScheduler mBleDeviceDisappearedScheduler =
- new BleDeviceDisappearedScheduler();
-
- public CompanionDevicePresenceMonitor(UserManager userManager,
- @NonNull AssociationStore associationStore,
- @NonNull ObservableUuidStore observableUuidStore, @NonNull Callback callback) {
- mAssociationStore = associationStore;
- mObservableUuidStore = observableUuidStore;
- mCallback = callback;
- mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(userManager,
- associationStore, mObservableUuidStore,
- /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
- mBleScanner = new BleCompanionDeviceScanner(associationStore,
- /* BleCompanionDeviceScanner.Callback */ this);
- }
-
- /** Initialize {@link CompanionDevicePresenceMonitor} */
- public void init(Context context) {
- if (DEBUG) Log.i(TAG, "init()");
-
- final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
- if (btAdapter != null) {
- mBtConnectionListener.init(btAdapter);
- mBleScanner.init(context, btAdapter);
- } else {
- Log.w(TAG, "BluetoothAdapter is NOT available.");
- }
-
- mAssociationStore.registerLocalListener(this);
- }
-
- /**
- * @return current connected UUID devices.
- */
- public Set<ParcelUuid> getCurrentConnectedUuidDevices() {
- return mConnectedUuidDevices;
- }
-
- /**
- * Remove current connected UUID device.
- */
- public void removeCurrentConnectedUuidDevice(ParcelUuid uuid) {
- mConnectedUuidDevices.remove(uuid);
- }
-
- /**
- * @return whether the associated companion devices is present. I.e. device is nearby (for BLE);
- * or devices is connected (for Bluetooth); or reported (by the application) to be
- * nearby (for "self-managed" associations).
- */
- public boolean isDevicePresent(int associationId) {
- return mReportedSelfManagedDevices.contains(associationId)
- || mConnectedBtDevices.contains(associationId)
- || mNearbyBleDevices.contains(associationId)
- || mSimulated.contains(associationId);
- }
-
- /**
- * @return whether the current uuid to be observed is present.
- */
- public boolean isDeviceUuidPresent(ParcelUuid uuid) {
- return mConnectedUuidDevices.contains(uuid);
- }
-
- /**
- * @return whether the current device is BT connected and had already reported to the app.
- */
-
- public boolean isBtConnected(int associationId) {
- return mConnectedBtDevices.contains(associationId);
- }
-
- /**
- * @return whether the current device in BLE range and had already reported to the app.
- */
- public boolean isBlePresent(int associationId) {
- return mNearbyBleDevices.contains(associationId);
- }
-
- /**
- * @return whether the current device had been already reported by the simulator.
- */
- public boolean isSimulatePresent(int associationId) {
- return mSimulated.contains(associationId);
- }
-
- /**
- * Marks a "self-managed" device as connected.
- *
- * <p>
- * Must ONLY be invoked by the
- * {@link com.android.server.companion.CompanionDeviceManagerService CompanionDeviceManagerService}
- * when an application invokes
- * {@link android.companion.CompanionDeviceManager#notifyDeviceAppeared(int) notifyDeviceAppeared()}
- */
- public void onSelfManagedDeviceConnected(int associationId) {
- onDevicePresenceEvent(mReportedSelfManagedDevices,
- associationId, EVENT_SELF_MANAGED_APPEARED);
- }
-
- /**
- * Marks a "self-managed" device as disconnected.
- *
- * <p>
- * Must ONLY be invoked by the
- * {@link com.android.server.companion.CompanionDeviceManagerService CompanionDeviceManagerService}
- * when an application invokes
- * {@link android.companion.CompanionDeviceManager#notifyDeviceDisappeared(int) notifyDeviceDisappeared()}
- */
- public void onSelfManagedDeviceDisconnected(int associationId) {
- onDevicePresenceEvent(mReportedSelfManagedDevices,
- associationId, EVENT_SELF_MANAGED_DISAPPEARED);
- }
-
- /**
- * Marks a "self-managed" device as disconnected when binderDied.
- */
- public void onSelfManagedDeviceReporterBinderDied(int associationId) {
- onDevicePresenceEvent(mReportedSelfManagedDevices,
- associationId, EVENT_SELF_MANAGED_DISAPPEARED);
- }
-
- @Override
- public void onBluetoothCompanionDeviceConnected(int associationId) {
- synchronized (mBtDisconnectedDevices) {
- // A device is considered reconnected within 10 seconds if a pending BLE lost report is
- // followed by a detected Bluetooth connection.
- boolean isReconnected = mBtDisconnectedDevices.contains(associationId);
- if (isReconnected) {
- Slog.i(TAG, "Device ( " + associationId + " ) is reconnected within 10s.");
- mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
- }
-
- Slog.i(TAG, "onBluetoothCompanionDeviceConnected: "
- + "associationId( " + associationId + " )");
- onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED);
-
- // Stop the BLE scan if all devices report BT connected status and BLE was present.
- if (canStopBleScan()) {
- mBleScanner.stopScanIfNeeded();
- }
-
- }
- }
-
- @Override
- public void onBluetoothCompanionDeviceDisconnected(int associationId) {
- Slog.i(TAG, "onBluetoothCompanionDeviceDisconnected "
- + "associationId( " + associationId + " )");
- // Start BLE scanning when the device is disconnected.
- mBleScanner.startScan();
-
- onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED);
- // If current device is BLE present but BT is disconnected , means it will be
- // potentially out of range later. Schedule BLE disappeared callback.
- if (isBlePresent(associationId)) {
- synchronized (mBtDisconnectedDevices) {
- mBtDisconnectedDevices.add(associationId);
- }
- mBleDeviceDisappearedScheduler.scheduleBleDeviceDisappeared(associationId);
- }
- }
-
- @Override
- public void onDevicePresenceEventByUuid(ObservableUuid uuid, int event) {
- final ParcelUuid parcelUuid = uuid.getUuid();
-
- switch(event) {
- case EVENT_BT_CONNECTED:
- boolean added = mConnectedUuidDevices.add(parcelUuid);
-
- if (!added) {
- Slog.w(TAG, "Uuid= " + parcelUuid + "is ALREADY reported as "
- + "present by this event=" + event);
- }
-
- break;
- case EVENT_BT_DISCONNECTED:
- final boolean removed = mConnectedUuidDevices.remove(parcelUuid);
-
- if (!removed) {
- Slog.w(TAG, "UUID= " + parcelUuid + " was NOT reported "
- + "as present by this event= " + event);
-
- return;
- }
-
- break;
- }
-
- mCallback.onDevicePresenceEventByUuid(uuid, event);
- }
-
-
- @Override
- public void onBleCompanionDeviceFound(int associationId) {
- onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED);
- synchronized (mBtDisconnectedDevices) {
- final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(associationId);
- if (mBtDisconnectedDevices.contains(associationId) && isCurrentPresent) {
- mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
- }
- }
- }
-
- @Override
- public void onBleCompanionDeviceLost(int associationId) {
- onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED);
- }
-
- /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
- @TestApi
- public void simulateDeviceEvent(int associationId, int event) {
- // IMPORTANT: this API should only be invoked via the
- // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
- // make this call are SHELL and ROOT.
- // No other caller (including SYSTEM!) should be allowed.
- enforceCallerShellOrRoot();
- // Make sure the association exists.
- enforceAssociationExists(associationId);
-
- switch (event) {
- case EVENT_BLE_APPEARED:
- simulateDeviceAppeared(associationId, event);
- break;
- case EVENT_BT_CONNECTED:
- onBluetoothCompanionDeviceConnected(associationId);
- break;
- case EVENT_BLE_DISAPPEARED:
- simulateDeviceDisappeared(associationId, event);
- break;
- case EVENT_BT_DISCONNECTED:
- onBluetoothCompanionDeviceDisconnected(associationId);
- break;
- default:
- throw new IllegalArgumentException("Event: " + event + "is not supported");
- }
- }
-
- /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
- @TestApi
- public void simulateDeviceEventByUuid(ObservableUuid uuid, int event) {
- // IMPORTANT: this API should only be invoked via the
- // 'companiondevice simulate-device-uuid-events' Shell command, so the only uid-s allowed to
- // make this call are SHELL and ROOT.
- // No other caller (including SYSTEM!) should be allowed.
- enforceCallerShellOrRoot();
- onDevicePresenceEventByUuid(uuid, event);
- }
-
- private void simulateDeviceAppeared(int associationId, int state) {
- onDevicePresenceEvent(mSimulated, associationId, state);
- mSchedulerHelper.scheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
- }
-
- private void simulateDeviceDisappeared(int associationId, int state) {
- mSchedulerHelper.unscheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
- onDevicePresenceEvent(mSimulated, associationId, state);
- }
-
- private void enforceAssociationExists(int associationId) {
- if (mAssociationStore.getAssociationById(associationId) == null) {
- throw new IllegalArgumentException(
- "Association with id " + associationId + " does not exist.");
- }
- }
-
- private void onDevicePresenceEvent(@NonNull Set<Integer> presentDevicesForSource,
- int associationId, int event) {
- Slog.i(TAG, "onDevicePresenceEvent() id=" + associationId + ", event=" + event);
-
- switch (event) {
- case EVENT_BLE_APPEARED:
- synchronized (mBtDisconnectedDevices) {
- // If a BLE device is detected within 10 seconds after BT is disconnected,
- // flag it as BLE is present.
- if (mBtDisconnectedDevices.contains(associationId)) {
- Slog.i(TAG, "Device ( " + associationId + " ) is present,"
- + " do not need to send the callback with event ( "
- + EVENT_BLE_APPEARED + " ).");
- mBtDisconnectedDevicesBlePresence.append(associationId, true);
- }
- }
- case EVENT_BT_CONNECTED:
- case EVENT_SELF_MANAGED_APPEARED:
- final boolean added = presentDevicesForSource.add(associationId);
-
- if (!added) {
- Slog.w(TAG, "Association with id "
- + associationId + " is ALREADY reported as "
- + "present by this source, event=" + event);
- }
-
- mCallback.onDeviceAppeared(associationId);
-
- break;
- case EVENT_BLE_DISAPPEARED:
- case EVENT_BT_DISCONNECTED:
- case EVENT_SELF_MANAGED_DISAPPEARED:
- final boolean removed = presentDevicesForSource.remove(associationId);
-
- if (!removed) {
- Slog.w(TAG, "Association with id " + associationId + " was NOT reported "
- + "as present by this source, event= " + event);
-
- return;
- }
-
- mCallback.onDeviceDisappeared(associationId);
-
- break;
- default:
- Slog.e(TAG, "Event: " + event + " is not supported");
- return;
- }
-
- mCallback.onDevicePresenceEvent(associationId, event);
- }
-
- /**
- * Implements
- * {@link AssociationStore.OnChangeListener#onAssociationRemoved(AssociationInfo)}
- */
- @Override
- public void onAssociationRemoved(@NonNull AssociationInfo association) {
- final int id = association.getId();
- if (DEBUG) {
- Log.i(TAG, "onAssociationRemoved() id=" + id);
- Log.d(TAG, " > association=" + association);
- }
-
- mConnectedBtDevices.remove(id);
- mNearbyBleDevices.remove(id);
- mReportedSelfManagedDevices.remove(id);
- mSimulated.remove(id);
- mBtDisconnectedDevices.remove(id);
- mBtDisconnectedDevicesBlePresence.delete(id);
-
- // Do NOT call mCallback.onDeviceDisappeared()!
- // CompanionDeviceManagerService will know that the association is removed, and will do
- // what's needed.
- }
-
- /**
- * Return a set of devices that pending to report connectivity
- */
- public SparseArray<Set<BluetoothDevice>> getPendingConnectedDevices() {
- synchronized (mBtConnectionListener.mPendingConnectedDevices) {
- return mBtConnectionListener.mPendingConnectedDevices;
- }
- }
-
- private static void enforceCallerShellOrRoot() {
- final int callingUid = Binder.getCallingUid();
- if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
-
- throw new SecurityException("Caller is neither Shell nor Root");
- }
-
- /**
- * The BLE scan can be only stopped if all the devices have been reported
- * BT connected and BLE presence and are not pending to report BLE lost.
- */
- private boolean canStopBleScan() {
- for (AssociationInfo ai : mAssociationStore.getActiveAssociations()) {
- int id = ai.getId();
- synchronized (mBtDisconnectedDevices) {
- if (ai.isNotifyOnDeviceNearby() && !(isBtConnected(id)
- && isBlePresent(id) && mBtDisconnectedDevices.isEmpty())) {
- Slog.i(TAG, "The BLE scan cannot be stopped, "
- + "device( " + id + " ) is not yet connected "
- + "OR the BLE is not current present Or is pending to report BLE lost");
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Dumps system information about devices that are marked as "present".
- */
- public void dump(@NonNull PrintWriter out) {
- out.append("Companion Device Present: ");
- if (mConnectedBtDevices.isEmpty()
- && mNearbyBleDevices.isEmpty()
- && mReportedSelfManagedDevices.isEmpty()) {
- out.append("<empty>\n");
- return;
- } else {
- out.append("\n");
- }
-
- out.append(" Connected Bluetooth Devices: ");
- if (mConnectedBtDevices.isEmpty()) {
- out.append("<empty>\n");
- } else {
- out.append("\n");
- for (int associationId : mConnectedBtDevices) {
- AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
- }
- }
-
- out.append(" Nearby BLE Devices: ");
- if (mNearbyBleDevices.isEmpty()) {
- out.append("<empty>\n");
- } else {
- out.append("\n");
- for (int associationId : mNearbyBleDevices) {
- AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
- }
- }
-
- out.append(" Self-Reported Devices: ");
- if (mReportedSelfManagedDevices.isEmpty()) {
- out.append("<empty>\n");
- } else {
- out.append("\n");
- for (int associationId : mReportedSelfManagedDevices) {
- AssociationInfo a = mAssociationStore.getAssociationById(associationId);
- out.append(" ").append(a.toShortString()).append('\n');
- }
- }
- }
-
- private class SimulatedDevicePresenceSchedulerHelper extends Handler {
- SimulatedDevicePresenceSchedulerHelper() {
- super(Looper.getMainLooper());
- }
-
- void scheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
- // First, unschedule if it was scheduled previously.
- if (hasMessages(/* what */ associationId)) {
- removeMessages(/* what */ associationId);
- }
-
- sendEmptyMessageDelayed(/* what */ associationId, 60 * 1000 /* 60 seconds */);
- }
-
- void unscheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
- removeMessages(/* what */ associationId);
- }
-
- @Override
- public void handleMessage(@NonNull Message msg) {
- final int associationId = msg.what;
- if (mSimulated.contains(associationId)) {
- onDevicePresenceEvent(mSimulated, associationId, EVENT_BLE_DISAPPEARED);
- }
- }
- }
-
- private class BleDeviceDisappearedScheduler extends Handler {
- BleDeviceDisappearedScheduler() {
- super(Looper.getMainLooper());
- }
-
- void scheduleBleDeviceDisappeared(int associationId) {
- if (hasMessages(associationId)) {
- removeMessages(associationId);
- }
- Slog.i(TAG, "scheduleBleDeviceDisappeared for Device: ( " + associationId + " ).");
- sendEmptyMessageDelayed(associationId, 10 * 1000 /* 10 seconds */);
- }
-
- void unScheduleDeviceDisappeared(int associationId) {
- if (hasMessages(associationId)) {
- Slog.i(TAG, "unScheduleDeviceDisappeared for Device( " + associationId + " )");
- synchronized (mBtDisconnectedDevices) {
- mBtDisconnectedDevices.remove(associationId);
- mBtDisconnectedDevicesBlePresence.delete(associationId);
- }
-
- removeMessages(associationId);
- }
- }
-
- @Override
- public void handleMessage(@NonNull Message msg) {
- final int associationId = msg.what;
- synchronized (mBtDisconnectedDevices) {
- final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(
- associationId);
- // If a device hasn't reported after 10 seconds and is not currently present,
- // assume BLE is lost and trigger the onDeviceEvent callback with the
- // EVENT_BLE_DISAPPEARED event.
- if (mBtDisconnectedDevices.contains(associationId)
- && !isCurrentPresent) {
- Slog.i(TAG, "Device ( " + associationId + " ) is likely BLE out of range, "
- + "sending callback with event ( " + EVENT_BLE_DISAPPEARED + " )");
- onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED);
- }
-
- mBtDisconnectedDevices.remove(associationId);
- mBtDisconnectedDevicesBlePresence.delete(associationId);
- }
- }
- }
-}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java
similarity index 83%
rename from services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
rename to services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java
index 5abdb42..c01c319 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionServiceConnector.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.companion;
+package com.android.server.companion.presence;
import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE;
@@ -33,36 +33,42 @@
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.infra.ServiceConnector;
import com.android.server.ServiceThread;
+import com.android.server.companion.CompanionDeviceManagerService;
/**
* Manages a connection (binding) to an instance of {@link CompanionDeviceService} running in the
* application process.
*/
@SuppressLint("LongLogTag")
-class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
+public class CompanionServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
+
+ /** Listener for changes to the state of the {@link CompanionServiceConnector} */
+ public interface Listener {
+ /**
+ * Called when service binding is died.
+ */
+ void onBindingDied(@UserIdInt int userId, @NonNull String packageName,
+ @NonNull CompanionServiceConnector serviceConnector);
+ }
+
private static final String TAG = "CDM_CompanionServiceConnector";
- private static final boolean DEBUG = false;
/* Unbinding before executing the callbacks can cause problems. Wait 5-seconds before unbind. */
private static final long UNBIND_POST_DELAY_MS = 5_000;
-
- /** Listener for changes to the state of the {@link CompanionDeviceServiceConnector} */
- interface Listener {
- void onBindingDied(@UserIdInt int userId, @NonNull String packageName,
- @NonNull CompanionDeviceServiceConnector serviceConnector);
- }
-
- private final @UserIdInt int mUserId;
- private final @NonNull ComponentName mComponentName;
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final ComponentName mComponentName;
+ private final boolean mIsPrimary;
// IMPORTANT: this can (and will!) be null (at the moment, CompanionApplicationController only
// installs a listener to the primary ServiceConnector), hence we should always null-check the
// reference before calling on it.
- private @Nullable Listener mListener;
- private boolean mIsPrimary;
+ @Nullable
+ private Listener mListener;
/**
* Create a CompanionDeviceServiceConnector instance.
@@ -79,16 +85,16 @@
* IMPORTANCE_FOREGROUND_SERVICE = 125. In order to kill the one time permission session, the
* service importance level should be higher than 125.
*/
- static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
+ static CompanionServiceConnector newInstance(@NonNull Context context,
@UserIdInt int userId, @NonNull ComponentName componentName, boolean isSelfManaged,
boolean isPrimary) {
final int bindingFlags = isSelfManaged ? BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE
: BIND_ALMOST_PERCEPTIBLE;
- return new CompanionDeviceServiceConnector(
+ return new CompanionServiceConnector(
context, userId, componentName, bindingFlags, isPrimary);
}
- private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
+ private CompanionServiceConnector(@NonNull Context context, @UserIdInt int userId,
@NonNull ComponentName componentName, int bindingFlags, boolean isPrimary) {
super(context, buildIntent(componentName), bindingFlags, userId, null);
mUserId = userId;
@@ -133,6 +139,7 @@
return mIsPrimary;
}
+ @NonNull
ComponentName getComponentName() {
return mComponentName;
}
@@ -140,17 +147,15 @@
@Override
protected void onServiceConnectionStatusChanged(
@NonNull ICompanionDeviceService service, boolean isConnected) {
- if (DEBUG) {
- Log.d(TAG, "onServiceConnection_StatusChanged() " + mComponentName.toShortString()
- + " connected=" + isConnected);
- }
+ Slog.d(TAG, "onServiceConnectionStatusChanged() " + mComponentName.toShortString()
+ + " connected=" + isConnected);
}
@Override
public void binderDied() {
super.binderDied();
- if (DEBUG) Log.d(TAG, "binderDied() " + mComponentName.toShortString());
+ Slog.d(TAG, "binderDied() " + mComponentName.toShortString());
// Handle primary process being killed
if (mListener != null) {
@@ -172,7 +177,8 @@
* within system_server and thus tends to get heavily congested)
*/
@Override
- protected @NonNull Handler getJobHandler() {
+ @NonNull
+ protected Handler getJobHandler() {
return getServiceThread().getThreadHandler();
}
@@ -182,12 +188,14 @@
return -1;
}
- private static @NonNull Intent buildIntent(@NonNull ComponentName componentName) {
+ @NonNull
+ private static Intent buildIntent(@NonNull ComponentName componentName) {
return new Intent(CompanionDeviceService.SERVICE_INTERFACE)
.setComponent(componentName);
}
- private static @NonNull ServiceThread getServiceThread() {
+ @NonNull
+ private static ServiceThread getServiceThread() {
if (sServiceThread == null) {
synchronized (CompanionDeviceManagerService.class) {
if (sServiceThread == null) {
@@ -206,5 +214,6 @@
* <p>
* Do NOT reference directly, use {@link #getServiceThread()} method instead.
*/
- private static volatile @Nullable ServiceThread sServiceThread;
+ @Nullable
+ private static volatile ServiceThread sServiceThread;
}
diff --git a/services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java b/services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java
new file mode 100644
index 0000000..2a933a8
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/presence/DevicePresenceProcessor.java
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.presence;
+
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
+import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
+import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED;
+import static android.companion.DevicePresenceEvent.EVENT_BT_CONNECTED;
+import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
+import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_APPEARED;
+import static android.companion.DevicePresenceEvent.EVENT_SELF_MANAGED_DISAPPEARED;
+import static android.companion.DevicePresenceEvent.NO_ASSOCIATION;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
+
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanObserveDevicePresenceByUuid;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.companion.AssociationInfo;
+import android.companion.DeviceNotAssociatedException;
+import android.companion.DevicePresenceEvent;
+import android.companion.ObservingDevicePresenceRequest;
+import android.content.Context;
+import android.hardware.power.Mode;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.companion.association.AssociationStore;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Class responsible for monitoring companion devices' "presence" status (i.e.
+ * connected/disconnected for Bluetooth devices; nearby or not for BLE devices).
+ *
+ * <p>
+ * Should only be used by
+ * {@link com.android.server.companion.CompanionDeviceManagerService CompanionDeviceManagerService}
+ * to which it provides the following API:
+ * <ul>
+ * <li> {@link #onSelfManagedDeviceConnected(int)}
+ * <li> {@link #onSelfManagedDeviceDisconnected(int)}
+ * <li> {@link #isDevicePresent(int)}
+ * </ul>
+ */
+@SuppressLint("LongLogTag")
+public class DevicePresenceProcessor implements AssociationStore.OnChangeListener,
+ BluetoothCompanionDeviceConnectionListener.Callback, BleCompanionDeviceScanner.Callback {
+ static final boolean DEBUG = false;
+ private static final String TAG = "CDM_DevicePresenceProcessor";
+
+ @NonNull
+ private final Context mContext;
+ @NonNull
+ private final CompanionAppBinder mCompanionAppBinder;
+ @NonNull
+ private final AssociationStore mAssociationStore;
+ @NonNull
+ private final ObservableUuidStore mObservableUuidStore;
+ @NonNull
+ private final BluetoothCompanionDeviceConnectionListener mBtConnectionListener;
+ @NonNull
+ private final BleCompanionDeviceScanner mBleScanner;
+ @NonNull
+ private final PowerManagerInternal mPowerManagerInternal;
+
+ // NOTE: Same association may appear in more than one of the following sets at the same time.
+ // (E.g. self-managed devices that have MAC addresses, could be reported as present by their
+ // companion applications, while at the same be connected via BT, or detected nearby by BLE
+ // scanner)
+ @NonNull
+ private final Set<Integer> mConnectedBtDevices = new HashSet<>();
+ @NonNull
+ private final Set<Integer> mNearbyBleDevices = new HashSet<>();
+ @NonNull
+ private final Set<Integer> mReportedSelfManagedDevices = new HashSet<>();
+ @NonNull
+ private final Set<ParcelUuid> mConnectedUuidDevices = new HashSet<>();
+ @NonNull
+ @GuardedBy("mBtDisconnectedDevices")
+ private final Set<Integer> mBtDisconnectedDevices = new HashSet<>();
+
+ // A map to track device presence within 10 seconds of Bluetooth disconnection.
+ // The key is the association ID, and the boolean value indicates if the device
+ // was detected again within that time frame.
+ @GuardedBy("mBtDisconnectedDevices")
+ private final @NonNull SparseBooleanArray mBtDisconnectedDevicesBlePresence =
+ new SparseBooleanArray();
+
+ // Tracking "simulated" presence. Used for debugging and testing only.
+ private final @NonNull Set<Integer> mSimulated = new HashSet<>();
+ private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
+ new SimulatedDevicePresenceSchedulerHelper();
+
+ private final BleDeviceDisappearedScheduler mBleDeviceDisappearedScheduler =
+ new BleDeviceDisappearedScheduler();
+
+ public DevicePresenceProcessor(@NonNull Context context,
+ @NonNull CompanionAppBinder companionAppBinder,
+ UserManager userManager,
+ @NonNull AssociationStore associationStore,
+ @NonNull ObservableUuidStore observableUuidStore,
+ @NonNull PowerManagerInternal powerManagerInternal) {
+ mContext = context;
+ mCompanionAppBinder = companionAppBinder;
+ mAssociationStore = associationStore;
+ mObservableUuidStore = observableUuidStore;
+ mBtConnectionListener = new BluetoothCompanionDeviceConnectionListener(userManager,
+ associationStore, mObservableUuidStore,
+ /* BluetoothCompanionDeviceConnectionListener.Callback */ this);
+ mBleScanner = new BleCompanionDeviceScanner(associationStore,
+ /* BleCompanionDeviceScanner.Callback */ this);
+ mPowerManagerInternal = powerManagerInternal;
+ }
+
+ /** Initialize {@link DevicePresenceProcessor} */
+ public void init(Context context) {
+ if (DEBUG) Slog.i(TAG, "init()");
+
+ final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (btAdapter != null) {
+ mBtConnectionListener.init(btAdapter);
+ mBleScanner.init(context, btAdapter);
+ } else {
+ Slog.w(TAG, "BluetoothAdapter is NOT available.");
+ }
+
+ mAssociationStore.registerLocalListener(this);
+ }
+
+ /**
+ * Process device presence start request.
+ */
+ public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
+ String packageName, int userId) {
+ Slog.i(TAG,
+ "Start observing request=[" + request + "] for userId=[" + userId + "], package=["
+ + packageName + "]...");
+ final ParcelUuid requestUuid = request.getUuid();
+
+ if (requestUuid != null) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext);
+
+ // If it's already being observed, then no-op.
+ if (mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
+ Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
+ + userId + "] is already being observed.");
+ return;
+ }
+
+ final ObservableUuid observableUuid = new ObservableUuid(userId, requestUuid,
+ packageName, System.currentTimeMillis());
+ mObservableUuidStore.writeObservableUuid(userId, observableUuid);
+ } else {
+ final int associationId = request.getAssociationId();
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
+
+ // If it's already being observed, then no-op.
+ if (association.isNotifyOnDeviceNearby()) {
+ Slog.i(TAG, "Associated device id=[" + association.getId()
+ + "] is already being observed. No-op.");
+ return;
+ }
+
+ association = (new AssociationInfo.Builder(association)).setNotifyOnDeviceNearby(true)
+ .build();
+ mAssociationStore.updateAssociation(association);
+
+ // Send callback immediately if the device is present.
+ if (isDevicePresent(associationId)) {
+ Slog.i(TAG, "Device is already present. Triggering callback.");
+ if (isBlePresent(associationId)) {
+ onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED);
+ } else if (isBtConnected(associationId)) {
+ onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED);
+ } else if (isSimulatePresent(associationId)) {
+ onDevicePresenceEvent(mSimulated, associationId, EVENT_BLE_APPEARED);
+ }
+ }
+ }
+
+ Slog.i(TAG, "Registered device presence listener.");
+ }
+
+ /**
+ * Process device presence stop request.
+ */
+ public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
+ String packageName, int userId) {
+ Slog.i(TAG,
+ "Stop observing request=[" + request + "] for userId=[" + userId + "], package=["
+ + packageName + "]...");
+
+ final ParcelUuid requestUuid = request.getUuid();
+
+ if (requestUuid != null) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext);
+
+ if (!mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
+ Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
+ + userId + "] is already not being observed.");
+ return;
+ }
+
+ mObservableUuidStore.removeObservableUuid(userId, requestUuid, packageName);
+ removeCurrentConnectedUuidDevice(requestUuid);
+ } else {
+ final int associationId = request.getAssociationId();
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
+
+ // If it's already being observed, then no-op.
+ if (!association.isNotifyOnDeviceNearby()) {
+ Slog.i(TAG, "Associated device id=[" + association.getId()
+ + "] is already not being observed. No-op.");
+ return;
+ }
+
+ association = (new AssociationInfo.Builder(association)).setNotifyOnDeviceNearby(false)
+ .build();
+ mAssociationStore.updateAssociation(association);
+ }
+
+ Slog.i(TAG, "Unregistered device presence listener.");
+
+ // If last listener is unregistered, then unbind application.
+ if (!shouldBindPackage(userId, packageName)) {
+ mCompanionAppBinder.unbindCompanionApplication(userId, packageName);
+ }
+ }
+
+ /**
+ * For legacy device presence below Android V.
+ *
+ * @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
+ * int)}
+ */
+ @Deprecated
+ public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
+ throws RemoteException {
+ Slog.i(TAG,
+ "Start observing device=[" + deviceAddress + "] for userId=[" + userId
+ + "], package=["
+ + packageName + "]...");
+
+ enforceCallerCanManageAssociationsForPackage(mContext, userId, packageName, null);
+
+ AssociationInfo association = mAssociationStore.getFirstAssociationByAddress(userId,
+ packageName, deviceAddress);
+
+ if (association == null) {
+ throw new RemoteException(new DeviceNotAssociatedException("App " + packageName
+ + " is not associated with device " + deviceAddress
+ + " for user " + userId));
+ }
+
+ startObservingDevicePresence(
+ new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
+ .build(), packageName, userId);
+ }
+
+ /**
+ * For legacy device presence below Android V.
+ *
+ * @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
+ * int)}
+ */
+ @Deprecated
+ public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
+ throws RemoteException {
+ Slog.i(TAG,
+ "Stop observing device=[" + deviceAddress + "] for userId=[" + userId
+ + "], package=["
+ + packageName + "]...");
+
+ enforceCallerCanManageAssociationsForPackage(mContext, userId, packageName, null);
+
+ AssociationInfo association = mAssociationStore.getFirstAssociationByAddress(userId,
+ packageName, deviceAddress);
+
+ if (association == null) {
+ throw new RemoteException(new DeviceNotAssociatedException("App " + packageName
+ + " is not associated with device " + deviceAddress
+ + " for user " + userId));
+ }
+
+ stopObservingDevicePresence(
+ new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
+ .build(), packageName, userId);
+ }
+
+ /**
+ * @return whether the package should be bound (i.e. at least one of the devices associated with
+ * the package is currently present OR the UUID to be observed by this package is
+ * currently present).
+ */
+ private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) {
+ final List<AssociationInfo> packageAssociations =
+ mAssociationStore.getActiveAssociationsByPackage(userId, packageName);
+ final List<ObservableUuid> observableUuids =
+ mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
+
+ for (AssociationInfo association : packageAssociations) {
+ if (!association.shouldBindWhenPresent()) continue;
+ if (isDevicePresent(association.getId())) return true;
+ }
+
+ for (ObservableUuid uuid : observableUuids) {
+ if (isDeviceUuidPresent(uuid.getUuid())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Bind the system to the app if it's not bound.
+ *
+ * Set bindImportant to true when the association is self-managed to avoid the target service
+ * being killed.
+ */
+ private void bindApplicationIfNeeded(int userId, String packageName, boolean bindImportant) {
+ if (!mCompanionAppBinder.isCompanionApplicationBound(userId, packageName)) {
+ mCompanionAppBinder.bindCompanionApplication(
+ userId, packageName, bindImportant, this::onBinderDied);
+ } else {
+ Slog.i(TAG,
+ "UserId=[" + userId + "], packageName=[" + packageName + "] is already bound.");
+ }
+ }
+
+ /**
+ * @return current connected UUID devices.
+ */
+ public Set<ParcelUuid> getCurrentConnectedUuidDevices() {
+ return mConnectedUuidDevices;
+ }
+
+ /**
+ * Remove current connected UUID device.
+ */
+ public void removeCurrentConnectedUuidDevice(ParcelUuid uuid) {
+ mConnectedUuidDevices.remove(uuid);
+ }
+
+ /**
+ * @return whether the associated companion devices is present. I.e. device is nearby (for BLE);
+ * or devices is connected (for Bluetooth); or reported (by the application) to be
+ * nearby (for "self-managed" associations).
+ */
+ public boolean isDevicePresent(int associationId) {
+ return mReportedSelfManagedDevices.contains(associationId)
+ || mConnectedBtDevices.contains(associationId)
+ || mNearbyBleDevices.contains(associationId)
+ || mSimulated.contains(associationId);
+ }
+
+ /**
+ * @return whether the current uuid to be observed is present.
+ */
+ public boolean isDeviceUuidPresent(ParcelUuid uuid) {
+ return mConnectedUuidDevices.contains(uuid);
+ }
+
+ /**
+ * @return whether the current device is BT connected and had already reported to the app.
+ */
+
+ public boolean isBtConnected(int associationId) {
+ return mConnectedBtDevices.contains(associationId);
+ }
+
+ /**
+ * @return whether the current device in BLE range and had already reported to the app.
+ */
+ public boolean isBlePresent(int associationId) {
+ return mNearbyBleDevices.contains(associationId);
+ }
+
+ /**
+ * @return whether the current device had been already reported by the simulator.
+ */
+ public boolean isSimulatePresent(int associationId) {
+ return mSimulated.contains(associationId);
+ }
+
+ /**
+ * Marks a "self-managed" device as connected.
+ *
+ * <p>
+ * Must ONLY be invoked by the
+ * {@link com.android.server.companion.CompanionDeviceManagerService
+ * CompanionDeviceManagerService}
+ * when an application invokes
+ * {@link android.companion.CompanionDeviceManager#notifyDeviceAppeared(int)
+ * notifyDeviceAppeared()}
+ */
+ public void onSelfManagedDeviceConnected(int associationId) {
+ onDevicePresenceEvent(mReportedSelfManagedDevices,
+ associationId, EVENT_SELF_MANAGED_APPEARED);
+ }
+
+ /**
+ * Marks a "self-managed" device as disconnected.
+ *
+ * <p>
+ * Must ONLY be invoked by the
+ * {@link com.android.server.companion.CompanionDeviceManagerService
+ * CompanionDeviceManagerService}
+ * when an application invokes
+ * {@link android.companion.CompanionDeviceManager#notifyDeviceDisappeared(int)
+ * notifyDeviceDisappeared()}
+ */
+ public void onSelfManagedDeviceDisconnected(int associationId) {
+ onDevicePresenceEvent(mReportedSelfManagedDevices,
+ associationId, EVENT_SELF_MANAGED_DISAPPEARED);
+ }
+
+ /**
+ * Marks a "self-managed" device as disconnected when binderDied.
+ */
+ public void onSelfManagedDeviceReporterBinderDied(int associationId) {
+ onDevicePresenceEvent(mReportedSelfManagedDevices,
+ associationId, EVENT_SELF_MANAGED_DISAPPEARED);
+ }
+
+ @Override
+ public void onBluetoothCompanionDeviceConnected(int associationId) {
+ synchronized (mBtDisconnectedDevices) {
+ // A device is considered reconnected within 10 seconds if a pending BLE lost report is
+ // followed by a detected Bluetooth connection.
+ boolean isReconnected = mBtDisconnectedDevices.contains(associationId);
+ if (isReconnected) {
+ Slog.i(TAG, "Device ( " + associationId + " ) is reconnected within 10s.");
+ mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
+ }
+
+ Slog.i(TAG, "onBluetoothCompanionDeviceConnected: "
+ + "associationId( " + associationId + " )");
+ onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED);
+
+ // Stop the BLE scan if all devices report BT connected status and BLE was present.
+ if (canStopBleScan()) {
+ mBleScanner.stopScanIfNeeded();
+ }
+
+ }
+ }
+
+ @Override
+ public void onBluetoothCompanionDeviceDisconnected(int associationId) {
+ Slog.i(TAG, "onBluetoothCompanionDeviceDisconnected "
+ + "associationId( " + associationId + " )");
+ // Start BLE scanning when the device is disconnected.
+ mBleScanner.startScan();
+
+ onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED);
+ // If current device is BLE present but BT is disconnected , means it will be
+ // potentially out of range later. Schedule BLE disappeared callback.
+ if (isBlePresent(associationId)) {
+ synchronized (mBtDisconnectedDevices) {
+ mBtDisconnectedDevices.add(associationId);
+ }
+ mBleDeviceDisappearedScheduler.scheduleBleDeviceDisappeared(associationId);
+ }
+ }
+
+
+ @Override
+ public void onBleCompanionDeviceFound(int associationId) {
+ onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED);
+ synchronized (mBtDisconnectedDevices) {
+ final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(associationId);
+ if (mBtDisconnectedDevices.contains(associationId) && isCurrentPresent) {
+ mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
+ }
+ }
+ }
+
+ @Override
+ public void onBleCompanionDeviceLost(int associationId) {
+ onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED);
+ }
+
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceEvent(int associationId, int event) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ // Make sure the association exists.
+ enforceAssociationExists(associationId);
+
+ switch (event) {
+ case EVENT_BLE_APPEARED:
+ simulateDeviceAppeared(associationId, event);
+ break;
+ case EVENT_BT_CONNECTED:
+ onBluetoothCompanionDeviceConnected(associationId);
+ break;
+ case EVENT_BLE_DISAPPEARED:
+ simulateDeviceDisappeared(associationId, event);
+ break;
+ case EVENT_BT_DISCONNECTED:
+ onBluetoothCompanionDeviceDisconnected(associationId);
+ break;
+ default:
+ throw new IllegalArgumentException("Event: " + event + "is not supported");
+ }
+ }
+
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceEventByUuid(ObservableUuid uuid, int event) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-uuid-events' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ onDevicePresenceEventByUuid(uuid, event);
+ }
+
+ private void simulateDeviceAppeared(int associationId, int state) {
+ onDevicePresenceEvent(mSimulated, associationId, state);
+ mSchedulerHelper.scheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+ }
+
+ private void simulateDeviceDisappeared(int associationId, int state) {
+ mSchedulerHelper.unscheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+ onDevicePresenceEvent(mSimulated, associationId, state);
+ }
+
+ private void enforceAssociationExists(int associationId) {
+ if (mAssociationStore.getAssociationById(associationId) == null) {
+ throw new IllegalArgumentException(
+ "Association with id " + associationId + " does not exist.");
+ }
+ }
+
+ private void onDevicePresenceEvent(@NonNull Set<Integer> presentDevicesForSource,
+ int associationId, int eventType) {
+ Slog.i(TAG,
+ "onDevicePresenceEvent() id=[" + associationId + "], event=[" + eventType + "]...");
+
+ AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ if (association == null) {
+ Slog.e(TAG, "Association doesn't exist.");
+ return;
+ }
+
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+ final DevicePresenceEvent event = new DevicePresenceEvent(associationId, eventType, null);
+
+ if (eventType == EVENT_BLE_APPEARED) {
+ synchronized (mBtDisconnectedDevices) {
+ // If a BLE device is detected within 10 seconds after BT is disconnected,
+ // flag it as BLE is present.
+ if (mBtDisconnectedDevices.contains(associationId)) {
+ Slog.i(TAG, "Device ( " + associationId + " ) is present,"
+ + " do not need to send the callback with event ( "
+ + EVENT_BLE_APPEARED + " ).");
+ mBtDisconnectedDevicesBlePresence.append(associationId, true);
+ }
+ }
+ }
+
+ switch (eventType) {
+ case EVENT_BLE_APPEARED:
+ case EVENT_BT_CONNECTED:
+ case EVENT_SELF_MANAGED_APPEARED:
+ final boolean added = presentDevicesForSource.add(associationId);
+ if (!added) {
+ Slog.w(TAG, "The association is already present.");
+ }
+
+ if (association.shouldBindWhenPresent()) {
+ bindApplicationIfNeeded(userId, packageName, association.isSelfManaged());
+ } else {
+ return;
+ }
+
+ if (association.isSelfManaged() || added) {
+ notifyDevicePresenceEvent(userId, packageName, event);
+ // Also send the legacy callback.
+ legacyNotifyDevicePresenceEvent(association, true);
+ }
+ break;
+ case EVENT_BLE_DISAPPEARED:
+ case EVENT_BT_DISCONNECTED:
+ case EVENT_SELF_MANAGED_DISAPPEARED:
+ final boolean removed = presentDevicesForSource.remove(associationId);
+ if (!removed) {
+ Slog.w(TAG, "The association is already NOT present.");
+ }
+
+ if (!mCompanionAppBinder.isCompanionApplicationBound(userId, packageName)) {
+ Slog.e(TAG, "Package is not bound");
+ return;
+ }
+
+ if (association.isSelfManaged() || removed) {
+ notifyDevicePresenceEvent(userId, packageName, event);
+ // Also send the legacy callback.
+ legacyNotifyDevicePresenceEvent(association, false);
+ }
+
+ // Check if there are other devices associated to the app that are present.
+ if (!shouldBindPackage(userId, packageName)) {
+ mCompanionAppBinder.unbindCompanionApplication(userId, packageName);
+ }
+ break;
+ default:
+ Slog.e(TAG, "Event: " + eventType + " is not supported.");
+ break;
+ }
+ }
+
+ @Override
+ public void onDevicePresenceEventByUuid(ObservableUuid uuid, int eventType) {
+ Slog.i(TAG, "onDevicePresenceEventByUuid ObservableUuid=[" + uuid + "], event=[" + eventType
+ + "]...");
+
+ final ParcelUuid parcelUuid = uuid.getUuid();
+ final String packageName = uuid.getPackageName();
+ final int userId = uuid.getUserId();
+ final DevicePresenceEvent event = new DevicePresenceEvent(NO_ASSOCIATION, eventType,
+ parcelUuid);
+
+ switch (eventType) {
+ case EVENT_BT_CONNECTED:
+ boolean added = mConnectedUuidDevices.add(parcelUuid);
+ if (!added) {
+ Slog.w(TAG, "This device is already connected.");
+ }
+
+ bindApplicationIfNeeded(userId, packageName, false);
+
+ notifyDevicePresenceEvent(userId, packageName, event);
+ break;
+ case EVENT_BT_DISCONNECTED:
+ final boolean removed = mConnectedUuidDevices.remove(parcelUuid);
+ if (!removed) {
+ Slog.w(TAG, "This device is already disconnected.");
+ return;
+ }
+
+ if (!mCompanionAppBinder.isCompanionApplicationBound(userId, packageName)) {
+ Slog.e(TAG, "Package is not bound.");
+ return;
+ }
+
+ notifyDevicePresenceEvent(userId, packageName, event);
+
+ if (!shouldBindPackage(userId, packageName)) {
+ mCompanionAppBinder.unbindCompanionApplication(userId, packageName);
+ }
+ break;
+ default:
+ Slog.e(TAG, "Event: " + eventType + " is not supported");
+ break;
+ }
+ }
+
+ /**
+ * Notify device presence event to the app.
+ *
+ * @deprecated Use {@link #notifyDevicePresenceEvent(int, String, DevicePresenceEvent)} instead.
+ */
+ @Deprecated
+ private void legacyNotifyDevicePresenceEvent(AssociationInfo association,
+ boolean isAppeared) {
+ Slog.i(TAG, "legacyNotifyDevicePresenceEvent() association=[" + association.toShortString()
+ + "], isAppeared=[" + isAppeared + "]");
+
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+
+ final CompanionServiceConnector primaryServiceConnector =
+ mCompanionAppBinder.getPrimaryServiceConnector(userId, packageName);
+ if (primaryServiceConnector == null) {
+ Slog.e(TAG, "Package is not bound.");
+ return;
+ }
+
+ if (isAppeared) {
+ primaryServiceConnector.postOnDeviceAppeared(association);
+ } else {
+ primaryServiceConnector.postOnDeviceDisappeared(association);
+ }
+ }
+
+ /**
+ * Notify the device presence event to the app.
+ */
+ private void notifyDevicePresenceEvent(int userId, String packageName,
+ DevicePresenceEvent event) {
+ Slog.i(TAG,
+ "notifyCompanionDevicePresenceEvent userId=[" + userId + "], packageName=["
+ + packageName + "], event=[" + event + "]...");
+
+ final CompanionServiceConnector primaryServiceConnector =
+ mCompanionAppBinder.getPrimaryServiceConnector(userId, packageName);
+
+ if (primaryServiceConnector == null) {
+ Slog.e(TAG, "Package is NOT bound.");
+ return;
+ }
+
+ primaryServiceConnector.postOnDevicePresenceEvent(event);
+ }
+
+ /**
+ * Notify the self-managed device presence event to the app.
+ */
+ public void notifySelfManagedDevicePresenceEvent(int associationId, boolean isAppeared) {
+ Slog.i(TAG, "notifySelfManagedDeviceAppeared() id=" + associationId);
+
+ AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(
+ associationId);
+ if (!association.isSelfManaged()) {
+ throw new IllegalArgumentException("Association id=[" + associationId
+ + "] is not self-managed.");
+ }
+ // AssociationInfo class is immutable: create a new AssociationInfo object with updated
+ // timestamp.
+ association = (new AssociationInfo.Builder(association))
+ .setLastTimeConnected(System.currentTimeMillis())
+ .build();
+ mAssociationStore.updateAssociation(association);
+
+ if (isAppeared) {
+ onSelfManagedDeviceConnected(associationId);
+ } else {
+ onSelfManagedDeviceDisconnected(associationId);
+ }
+
+ final String deviceProfile = association.getDeviceProfile();
+ if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
+ Slog.i(TAG, "Enable hint mode for device device profile: " + deviceProfile);
+ mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, isAppeared);
+ }
+ }
+
+ private void onBinderDied(@UserIdInt int userId, @NonNull String packageName,
+ @NonNull CompanionServiceConnector serviceConnector) {
+
+ boolean isPrimary = serviceConnector.isPrimary();
+ Slog.i(TAG, "onBinderDied() u" + userId + "/" + packageName + " isPrimary: " + isPrimary);
+
+ // First, disable hint mode for Auto profile and mark not BOUND for primary service ONLY.
+ if (isPrimary) {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getActiveAssociationsByPackage(userId, packageName);
+
+ for (AssociationInfo association : associations) {
+ final String deviceProfile = association.getDeviceProfile();
+ if (DEVICE_PROFILE_AUTOMOTIVE_PROJECTION.equals(deviceProfile)) {
+ Slog.i(TAG, "Disable hint mode for device profile: " + deviceProfile);
+ mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
+ break;
+ }
+ }
+
+ mCompanionAppBinder.removePackage(userId, packageName);
+ }
+
+ // Second: schedule rebinding if needed.
+ final boolean shouldScheduleRebind = shouldScheduleRebind(userId, packageName, isPrimary);
+
+ if (shouldScheduleRebind) {
+ mCompanionAppBinder.scheduleRebinding(userId, packageName, serviceConnector);
+ }
+ }
+
+ /**
+ * Check if the system should rebind the self-managed secondary services
+ * OR non-self-managed services.
+ */
+ private boolean shouldScheduleRebind(int userId, String packageName, boolean isPrimary) {
+ // Make sure do not schedule rebind for the case ServiceConnector still gets callback after
+ // app is uninstalled.
+ boolean stillAssociated = false;
+ // Make sure to clean up the state for all the associations
+ // that associate with this package.
+ boolean shouldScheduleRebind = false;
+ boolean shouldScheduleRebindForUuid = false;
+ final List<ObservableUuid> uuids =
+ mObservableUuidStore.getObservableUuidsForPackage(userId, packageName);
+
+ for (AssociationInfo ai :
+ mAssociationStore.getActiveAssociationsByPackage(userId, packageName)) {
+ final int associationId = ai.getId();
+ stillAssociated = true;
+ if (ai.isSelfManaged()) {
+ // Do not rebind if primary one is died for selfManaged application.
+ if (isPrimary && isDevicePresent(associationId)) {
+ onSelfManagedDeviceReporterBinderDied(associationId);
+ shouldScheduleRebind = false;
+ }
+ // Do not rebind if both primary and secondary services are died for
+ // selfManaged application.
+ shouldScheduleRebind = mCompanionAppBinder.isCompanionApplicationBound(userId,
+ packageName);
+ } else if (ai.isNotifyOnDeviceNearby()) {
+ // Always rebind for non-selfManaged devices.
+ shouldScheduleRebind = true;
+ }
+ }
+
+ for (ObservableUuid uuid : uuids) {
+ if (isDeviceUuidPresent(uuid.getUuid())) {
+ shouldScheduleRebindForUuid = true;
+ break;
+ }
+ }
+
+ return (stillAssociated && shouldScheduleRebind) || shouldScheduleRebindForUuid;
+ }
+
+ /**
+ * Implements
+ * {@link AssociationStore.OnChangeListener#onAssociationRemoved(AssociationInfo)}
+ */
+ @Override
+ public void onAssociationRemoved(@NonNull AssociationInfo association) {
+ final int id = association.getId();
+ if (DEBUG) {
+ Log.i(TAG, "onAssociationRemoved() id=" + id);
+ Log.d(TAG, " > association=" + association);
+ }
+
+ mConnectedBtDevices.remove(id);
+ mNearbyBleDevices.remove(id);
+ mReportedSelfManagedDevices.remove(id);
+ mSimulated.remove(id);
+ synchronized (mBtDisconnectedDevices) {
+ mBtDisconnectedDevices.remove(id);
+ mBtDisconnectedDevicesBlePresence.delete(id);
+ }
+
+ // Do NOT call mCallback.onDeviceDisappeared()!
+ // CompanionDeviceManagerService will know that the association is removed, and will do
+ // what's needed.
+ }
+
+ /**
+ * Return a set of devices that pending to report connectivity
+ */
+ public SparseArray<Set<BluetoothDevice>> getPendingConnectedDevices() {
+ synchronized (mBtConnectionListener.mPendingConnectedDevices) {
+ return mBtConnectionListener.mPendingConnectedDevices;
+ }
+ }
+
+ private static void enforceCallerShellOrRoot() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
+
+ throw new SecurityException("Caller is neither Shell nor Root");
+ }
+
+ /**
+ * The BLE scan can be only stopped if all the devices have been reported
+ * BT connected and BLE presence and are not pending to report BLE lost.
+ */
+ private boolean canStopBleScan() {
+ for (AssociationInfo ai : mAssociationStore.getActiveAssociations()) {
+ int id = ai.getId();
+ synchronized (mBtDisconnectedDevices) {
+ if (ai.isNotifyOnDeviceNearby() && !(isBtConnected(id)
+ && isBlePresent(id) && mBtDisconnectedDevices.isEmpty())) {
+ Slog.i(TAG, "The BLE scan cannot be stopped, "
+ + "device( " + id + " ) is not yet connected "
+ + "OR the BLE is not current present Or is pending to report BLE lost");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Dumps system information about devices that are marked as "present".
+ */
+ public void dump(@NonNull PrintWriter out) {
+ out.append("Companion Device Present: ");
+ if (mConnectedBtDevices.isEmpty()
+ && mNearbyBleDevices.isEmpty()
+ && mReportedSelfManagedDevices.isEmpty()) {
+ out.append("<empty>\n");
+ return;
+ } else {
+ out.append("\n");
+ }
+
+ out.append(" Connected Bluetooth Devices: ");
+ if (mConnectedBtDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mConnectedBtDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+
+ out.append(" Nearby BLE Devices: ");
+ if (mNearbyBleDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mNearbyBleDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+
+ out.append(" Self-Reported Devices: ");
+ if (mReportedSelfManagedDevices.isEmpty()) {
+ out.append("<empty>\n");
+ } else {
+ out.append("\n");
+ for (int associationId : mReportedSelfManagedDevices) {
+ AssociationInfo a = mAssociationStore.getAssociationById(associationId);
+ out.append(" ").append(a.toShortString()).append('\n');
+ }
+ }
+ }
+
+ private class SimulatedDevicePresenceSchedulerHelper extends Handler {
+ SimulatedDevicePresenceSchedulerHelper() {
+ super(Looper.getMainLooper());
+ }
+
+ void scheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ // First, unschedule if it was scheduled previously.
+ if (hasMessages(/* what */ associationId)) {
+ removeMessages(/* what */ associationId);
+ }
+
+ sendEmptyMessageDelayed(/* what */ associationId, 60 * 1000 /* 60 seconds */);
+ }
+
+ void unscheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ removeMessages(/* what */ associationId);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ final int associationId = msg.what;
+ if (mSimulated.contains(associationId)) {
+ onDevicePresenceEvent(mSimulated, associationId, EVENT_BLE_DISAPPEARED);
+ }
+ }
+ }
+
+ private class BleDeviceDisappearedScheduler extends Handler {
+ BleDeviceDisappearedScheduler() {
+ super(Looper.getMainLooper());
+ }
+
+ void scheduleBleDeviceDisappeared(int associationId) {
+ if (hasMessages(associationId)) {
+ removeMessages(associationId);
+ }
+ Slog.i(TAG, "scheduleBleDeviceDisappeared for Device: ( " + associationId + " ).");
+ sendEmptyMessageDelayed(associationId, 10 * 1000 /* 10 seconds */);
+ }
+
+ void unScheduleDeviceDisappeared(int associationId) {
+ if (hasMessages(associationId)) {
+ Slog.i(TAG, "unScheduleDeviceDisappeared for Device( " + associationId + " )");
+ synchronized (mBtDisconnectedDevices) {
+ mBtDisconnectedDevices.remove(associationId);
+ mBtDisconnectedDevicesBlePresence.delete(associationId);
+ }
+
+ removeMessages(associationId);
+ }
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ final int associationId = msg.what;
+ synchronized (mBtDisconnectedDevices) {
+ final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(
+ associationId);
+ // If a device hasn't reported after 10 seconds and is not currently present,
+ // assume BLE is lost and trigger the onDeviceEvent callback with the
+ // EVENT_BLE_DISAPPEARED event.
+ if (mBtDisconnectedDevices.contains(associationId)
+ && !isCurrentPresent) {
+ Slog.i(TAG, "Device ( " + associationId + " ) is likely BLE out of range, "
+ + "sending callback with event ( " + EVENT_BLE_DISAPPEARED + " )");
+ onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED);
+ }
+
+ mBtDisconnectedDevices.remove(associationId);
+ mBtDisconnectedDevicesBlePresence.delete(associationId);
+ }
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java b/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
index db15da29..fa0f6bd 100644
--- a/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
+++ b/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
@@ -300,4 +300,18 @@
return readObservableUuidsFromCache(userId);
}
}
+
+ /**
+ * Check if a UUID is being observed by the package.
+ */
+ public boolean isUuidBeingObserved(ParcelUuid uuid, int userId, String packageName) {
+ final List<ObservableUuid> uuidsBeingObserved = getObservableUuidsForPackage(userId,
+ packageName);
+ for (ObservableUuid observableUuid : uuidsBeingObserved) {
+ if (observableUuid.getUuid().equals(uuid)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 793fb7f..697ef87 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -46,7 +46,6 @@
@SuppressLint("LongLogTag")
public class CompanionTransportManager {
private static final String TAG = "CDM_CompanionTransportManager";
- private static final boolean DEBUG = false;
private boolean mSecureTransportEnabled = true;
@@ -137,11 +136,17 @@
}
}
- public void attachSystemDataTransport(String packageName, int userId, int associationId,
- ParcelFileDescriptor fd) {
+ /**
+ * Attach transport.
+ */
+ public void attachSystemDataTransport(int associationId, ParcelFileDescriptor fd) {
+ Slog.i(TAG, "Attaching transport for association id=[" + associationId + "]...");
+
+ mAssociationStore.getAssociationWithCallerChecks(associationId);
+
synchronized (mTransports) {
if (mTransports.contains(associationId)) {
- detachSystemDataTransport(packageName, userId, associationId);
+ detachSystemDataTransport(associationId);
}
// TODO: Implement new API to pass a PSK
@@ -149,9 +154,18 @@
notifyOnTransportsChanged();
}
+
+ Slog.i(TAG, "Transport attached.");
}
- public void detachSystemDataTransport(String packageName, int userId, int associationId) {
+ /**
+ * Detach transport.
+ */
+ public void detachSystemDataTransport(int associationId) {
+ Slog.i(TAG, "Detaching transport for association id=[" + associationId + "]...");
+
+ mAssociationStore.getAssociationWithCallerChecks(associationId);
+
synchronized (mTransports) {
final Transport transport = mTransports.removeReturnOld(associationId);
if (transport == null) {
@@ -161,6 +175,8 @@
transport.stop();
notifyOnTransportsChanged();
}
+
+ Slog.i(TAG, "Transport detached.");
}
private void notifyOnTransportsChanged() {
@@ -307,8 +323,7 @@
int associationId = transport.mAssociationId;
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
if (association != null) {
- detachSystemDataTransport(association.getPackageName(),
- association.getUserId(),
+ detachSystemDataTransport(
association.getId());
}
}
diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index 2cf1f46..d7e766e 100644
--- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -39,7 +39,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.content.Context;
@@ -208,7 +207,7 @@
/**
* Require the caller to hold necessary permission to observe device presence by UUID.
*/
- public static void enforceCallerCanObservingDevicePresenceByUuid(@NonNull Context context) {
+ public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context) {
if (context.checkCallingPermission(REQUEST_OBSERVE_DEVICE_UUID_PRESENCE)
!= PERMISSION_GRANTED) {
throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
@@ -235,23 +234,6 @@
return checkCallerCanManageCompanionDevice(context);
}
- /**
- * Check if CDM can trust the context to process the association.
- */
- @Nullable
- public static AssociationInfo sanitizeWithCallerChecks(@NonNull Context context,
- @Nullable AssociationInfo association) {
- if (association == null) return null;
-
- final int userId = association.getUserId();
- final String packageName = association.getPackageName();
- if (!checkCallerCanManageAssociationsForPackage(context, userId, packageName)) {
- return null;
- }
-
- return association;
- }
-
private static boolean checkPackage(@UserIdInt int uid, @NonNull String packageName) {
try {
return getAppOpsService().checkPackage(uid, packageName) == MODE_ALLOWED;
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8244d20..3ec6e47 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -23,6 +23,7 @@
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
@@ -82,6 +83,8 @@
import android.hardware.input.VirtualStylusMotionEvent;
import android.hardware.input.VirtualTouchEvent;
import android.hardware.input.VirtualTouchscreenConfig;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioMix;
import android.os.Binder;
import android.os.IBinder;
import android.os.LocaleList;
@@ -1063,6 +1066,37 @@
}
@Override
+ public boolean hasCustomAudioInputSupport() throws RemoteException {
+ if (!Flags.vdmPublicApis()) {
+ return false;
+ }
+
+ if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
+ return false;
+ }
+ if (!android.media.audiopolicy.Flags.recordAudioDeviceAwarePermission()) {
+ return false;
+ }
+
+ if (getDevicePolicy(POLICY_TYPE_AUDIO) == VirtualDeviceParams.DEVICE_POLICY_DEFAULT) {
+ return false;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ for (AudioMix mix : audioManager.getRegisteredPolicyMixes()) {
+ if (mix.matchesVirtualDeviceId(getDeviceId())
+ && mix.getMixType() == AudioMix.MIX_TYPE_RECORDERS) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return false;
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
String indent = " ";
fout.println(" VirtualDevice: ");
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 6b5ba96..2607ed3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -1297,15 +1297,19 @@
@Override
public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
- RemoteContentProtectionService service = createRemoteContentProtectionService();
- if (service == null) {
- return;
- }
- try {
- service.onLoginDetected(events);
- } catch (Exception ex) {
- Slog.e(TAG, "Failed to call remote service", ex);
- }
+ Binder.withCleanCallingIdentity(
+ () -> {
+ RemoteContentProtectionService service =
+ createRemoteContentProtectionService();
+ if (service == null) {
+ return;
+ }
+ try {
+ service.onLoginDetected(events);
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to call remote service", ex);
+ }
+ });
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d1d7ee7..7f5867f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -242,6 +242,7 @@
"apache-commons-math",
"backstage_power_flags_lib",
"notification_flags_lib",
+ "power_hint_flags_lib",
"biometrics_flags_lib",
"am_flags_lib",
"com_android_server_accessibility_flags_lib",
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 6b3f5e2..730e508 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.app.admin.DevicePolicyManager.IS_DEVICE_OWNER_USER_AWARE;
import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY;
import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU;
import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU;
@@ -28,12 +29,14 @@
import android.Manifest;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
+import android.app.compat.CompatChanges;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.CpuUsageInfo;
import android.os.IHardwarePropertiesManager;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import com.android.internal.util.DumpUtils;
import com.android.server.vr.VrManagerInternal;
@@ -168,7 +171,15 @@
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
final int userId = UserHandle.getUserId(Binder.getCallingUid());
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
- final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ final DevicePolicyManager dpm;
+ if (Flags.systemServerRoleControllerEnabled()
+ && CompatChanges.isChangeEnabled(IS_DEVICE_OWNER_USER_AWARE)) {
+ final UserHandle handle = new UserHandle(userId);
+ dpm = mContext.createContextAsUser(handle, 0)
+ .getSystemService(DevicePolicyManager.class);
+ } else {
+ dpm = mContext.getSystemService(DevicePolicyManager.class);
+ }
if (!dpm.isDeviceOwnerApp(callingPackage)
&& mContext.checkCallingOrSelfPermission(Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index cc40940..589d8b3 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -69,6 +69,8 @@
final Object mSensitiveContentProtectionLock = new Object();
+ private final ArraySet<PackageInfo> mPackagesShowingSensitiveContent = new ArraySet<>();
+
@GuardedBy("mSensitiveContentProtectionLock")
private boolean mProjectionActive = false;
@@ -205,6 +207,10 @@
if (sensitiveNotificationAppProtection()) {
updateAppsThatShouldBlockScreenCapture();
}
+
+ if (sensitiveContentAppProtection() && mPackagesShowingSensitiveContent.size() > 0) {
+ mWindowManager.addBlockScreenCaptureForApps(mPackagesShowingSensitiveContent);
+ }
}
}
@@ -354,17 +360,27 @@
void setSensitiveContentProtection(IBinder windowToken, String packageName, int uid,
boolean isShowingSensitiveContent) {
synchronized (mSensitiveContentProtectionLock) {
+ // The window token distinguish this package from packages added for notifications.
+ PackageInfo packageInfo = new PackageInfo(packageName, uid, windowToken);
+ // track these packages to protect when screen share starts.
+ if (isShowingSensitiveContent) {
+ mPackagesShowingSensitiveContent.add(packageInfo);
+ if (mPackagesShowingSensitiveContent.size() > 100) {
+ Log.w(TAG, "Unexpectedly large number of sensitive windows, count: "
+ + mPackagesShowingSensitiveContent.size());
+ }
+ } else {
+ mPackagesShowingSensitiveContent.remove(packageInfo);
+ }
if (!mProjectionActive) {
return;
}
if (DEBUG) {
- Log.d(TAG, "setSensitiveContentProtection - windowToken=" + windowToken
- + ", package=" + packageName + ", uid=" + uid
- + ", isShowingSensitiveContent=" + isShowingSensitiveContent);
+ Log.d(TAG, "setSensitiveContentProtection - current package=" + packageInfo
+ + ", isShowingSensitiveContent=" + isShowingSensitiveContent
+ + ", sensitive packages=" + mPackagesShowingSensitiveContent);
}
- // The window token distinguish this package from packages added for notifications.
- PackageInfo packageInfo = new PackageInfo(packageName, uid, windowToken);
ArraySet<PackageInfo> packageInfos = new ArraySet<>();
packageInfos.add(packageInfo);
if (isShowingSensitiveContent) {
@@ -392,6 +408,12 @@
verifyCallingPackage(callingUid, packageName);
final long identity = Binder.clearCallingIdentity();
try {
+ if (isShowingSensitiveContent
+ && mWindowManager.getWindowName(windowToken) == null) {
+ Log.e(TAG, "window token is not know to WMS, can't apply protection,"
+ + " token: " + windowToken + ", package: " + packageName);
+ return;
+ }
SensitiveContentProtectionManagerService.this.setSensitiveContentProtection(
windowToken, packageName, callingUid, isShowingSensitiveContent);
} finally {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 133a77d..04dd2f3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -8154,7 +8154,7 @@
BackgroundStartPrivileges.NONE);
@ReasonCode int allowStartFgs = shouldAllowFgsStartForegroundNoBindingCheckLocked(
allowWhileInUse, callingPid, callingUid, callingPackage, null /* targetService */,
- BackgroundStartPrivileges.NONE);
+ BackgroundStartPrivileges.NONE, null);
if (allowStartFgs == REASON_DENIED) {
if (canBindingClientStartFgsLocked(callingUid) != null) {
@@ -8410,7 +8410,8 @@
allowWhileInUse2,
clientPid, clientUid, clientPackageName,
null /* targetService */,
- BackgroundStartPrivileges.NONE);
+ BackgroundStartPrivileges.NONE,
+ pr);
if (allowStartFgs != REASON_DENIED) {
return new Pair<>(allowStartFgs, clientPackageName);
} else {
@@ -8447,7 +8448,7 @@
ActivityManagerService.FgsTempAllowListItem tempAllowListReason =
r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
int ret = shouldAllowFgsStartForegroundNoBindingCheckLocked(allowWhileInUse, callingPid,
- callingUid, callingPackage, r, backgroundStartPrivileges);
+ callingUid, callingPackage, r, backgroundStartPrivileges, null);
// If an app (App 1) is bound by another app (App 2) that could start an FGS, then App 1
// is also allowed to start an FGS. We check all the binding
@@ -8503,7 +8504,8 @@
private @ReasonCode int shouldAllowFgsStartForegroundNoBindingCheckLocked(
@ReasonCode int allowWhileInUse, int callingPid, int callingUid, String callingPackage,
@Nullable ServiceRecord targetService,
- BackgroundStartPrivileges backgroundStartPrivileges) {
+ BackgroundStartPrivileges backgroundStartPrivileges,
+ @Nullable ProcessRecord targetRecord) {
int ret = allowWhileInUse;
if (ret == REASON_DENIED) {
@@ -8565,13 +8567,15 @@
if (ret == REASON_DENIED) {
// Flag check: are we disabling SAW FGS background starts?
final boolean shouldDisableSaw = Flags.fgsDisableSaw()
- && CompatChanges.isChangeEnabled(FGS_BOOT_COMPLETED_RESTRICTIONS, callingUid);
+ && CompatChanges.isChangeEnabled(FGS_SAW_RESTRICTIONS, callingUid);
if (shouldDisableSaw) {
- final ProcessRecord processRecord = mAm
- .getProcessRecordLocked(targetService.processName,
- targetService.appInfo.uid);
- if (processRecord != null) {
- if (processRecord.mState.hasOverlayUi()) {
+ if (targetRecord == null) {
+ synchronized (mAm.mPidsSelfLocked) {
+ targetRecord = mAm.mPidsSelfLocked.get(callingPid);
+ }
+ }
+ if (targetRecord != null) {
+ if (targetRecord.mState.hasOverlayUi()) {
if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
callingPackage)) {
ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 03ab5b3..4f1a35c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2656,6 +2656,11 @@
return mBackgroundLaunchBroadcasts;
}
+ private String getWearRemoteIntentAction() {
+ return mContext.getResources().getString(
+ com.android.internal.R.string.config_wearRemoteIntentAction);
+ }
+
/**
* Ensures that the given package name has an explicit set of allowed associations.
* If it does not, give it an empty set.
@@ -9973,7 +9978,7 @@
"getHistoricalProcessStartReasons");
if (uid != INVALID_UID) {
mProcessList.getAppStartInfoTracker().getStartInfo(
- packageName, userId, callingPid, maxNum, results);
+ packageName, uid, callingPid, maxNum, results);
}
} else {
// If no package name is given, use the caller's uid as the filter uid.
@@ -15213,6 +15218,18 @@
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
+ // TODO: b/329211459 - Remove this after background remote intent is fixed.
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+ && getWearRemoteIntentAction().equals(action)) {
+ final int callerProcState = callerApp != null
+ ? callerApp.getCurProcState()
+ : ActivityManager.PROCESS_STATE_NONEXISTENT;
+ if (ActivityManager.RunningAppProcessInfo.procStateToImportance(callerProcState)
+ > ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ return ActivityManager.START_CANCELED;
+ }
+ }
+
switch (action) {
case Intent.ACTION_MEDIA_SCANNER_SCAN_FILE:
UserManagerInternal umInternal = LocalServices.getService(
@@ -19630,7 +19647,7 @@
record.procStateSeqWaitingForNetwork = 0;
final long totalTime = SystemClock.uptimeMillis() - startTime;
if (totalTime >= mConstants.mNetworkAccessTimeoutMs || DEBUG_NETWORK) {
- Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
+ Slog.wtf(TAG_NETWORK, "Total time waited for network rules to get updated: "
+ totalTime + ". Uid: " + callingUid + " procStateSeq: "
+ procStateSeq + " UidRec: " + record
+ " validateUidRec: "
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 4ebabdc..5a97e87 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1164,8 +1164,7 @@
synchronized (mInternal) {
synchronized (mInternal.mProcLock) {
app.mOptRecord.setFreezeSticky(isSticky);
- mInternal.mOomAdjuster.mCachedAppOptimizer.freezeAppAsyncInternalLSP(
- app, 0 /* delayMillis */, true /* force */, false /* immediate */);
+ mInternal.mOomAdjuster.mCachedAppOptimizer.forceFreezeAppAsyncLSP(app);
}
}
return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 91cfb8f..e676b1f 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -281,7 +281,7 @@
* For {@link BroadcastQueueModernImpl}: Maximum number of outgoing broadcasts from a
* freezable process that will be allowed before killing the process.
*/
- public long MAX_FROZEN_OUTGOING_BROADCASTS = DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS;
+ public int MAX_FROZEN_OUTGOING_BROADCASTS = DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS;
private static final String KEY_MAX_FROZEN_OUTGOING_BROADCASTS =
"max_frozen_outgoing_broadcasts";
private static final int DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS = 32;
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index e98e1ba..ed3cd1e 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -277,6 +277,10 @@
mOutgoingBroadcasts.clear();
}
+ public void clearOutgoingBroadcasts() {
+ mOutgoingBroadcasts.clear();
+ }
+
/**
* Enqueue the given broadcast to be dispatched to this process at some
* future point in time. The target receiver is indicated by the given index
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index a6f6b34..c082889 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -166,7 +166,7 @@
/**
* Map from UID to per-process broadcast queues. If a UID hosts more than
* one process, each additional process is stored as a linked list using
- * {@link BroadcastProcessQueue#next}.
+ * {@link BroadcastProcessQueue#processNameNext}.
*
* @see #getProcessQueue
* @see #getOrCreateProcessQueue
@@ -661,6 +661,10 @@
final BroadcastProcessQueue queue = getProcessQueue(app);
if (queue != null) {
setQueueProcess(queue, app);
+ // Outgoing broadcasts should be cleared when the process dies but there have been
+ // issues due to AMS not always informing the BroadcastQueue of process deaths.
+ // So, clear them when a new process starts as well.
+ queue.clearOutgoingBroadcasts();
}
boolean didSomething = false;
@@ -730,6 +734,8 @@
demoteFromRunningLocked(queue);
}
+ queue.clearOutgoingBroadcasts();
+
// Skip any pending registered receivers, since the old process
// would never be around to receive them
boolean didSomething = queue.forEachMatchingBroadcast((r, i) -> {
@@ -781,8 +787,11 @@
final BroadcastProcessQueue queue = getOrCreateProcessQueue(
r.callerApp.processName, r.callerApp.uid);
if (queue.getOutgoingBroadcastCount() >= mConstants.MAX_FROZEN_OUTGOING_BROADCASTS) {
- // TODO: Kill the process if the outgoing broadcasts count is
- // beyond a certain limit.
+ r.callerApp.killLocked("Too many outgoing broadcasts in cached state",
+ ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED,
+ true /* noisy */);
+ return;
}
queue.enqueueOutgoingBroadcast(r);
mHistory.onBroadcastFrozenLocked(r);
diff --git a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
index 66abb42..b8ef03f 100644
--- a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
+++ b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
@@ -19,6 +19,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerService.checkComponentPermission;
import static com.android.server.am.BroadcastQueue.TAG;
+import static com.android.server.am.Flags.usePermissionManagerForBroadcastDeliveryCheck;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +28,7 @@
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.IIntentSender;
import android.content.Intent;
@@ -39,6 +41,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.permission.IPermissionManager;
+import android.permission.PermissionManager;
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
@@ -54,6 +57,9 @@
public class BroadcastSkipPolicy {
private final ActivityManagerService mService;
+ @Nullable
+ private PermissionManager mPermissionManager;
+
public BroadcastSkipPolicy(@NonNull ActivityManagerService service) {
mService = Objects.requireNonNull(service);
}
@@ -283,14 +289,35 @@
if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+ final AttributionSource attributionSource;
+ if (usePermissionManagerForBroadcastDeliveryCheck()) {
+ attributionSource =
+ new AttributionSource.Builder(info.activityInfo.applicationInfo.uid)
+ .setPackageName(info.activityInfo.packageName)
+ .build();
+ } else {
+ attributionSource = null;
+ }
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
try {
- perm = AppGlobals.getPackageManager().
- checkPermission(requiredPermission,
- info.activityInfo.applicationInfo.packageName,
- UserHandle
- .getUserId(info.activityInfo.applicationInfo.uid));
+ if (usePermissionManagerForBroadcastDeliveryCheck()) {
+ final PermissionManager permissionManager = getPermissionManager();
+ if (permissionManager != null) {
+ perm = permissionManager.checkPermissionForDataDelivery(
+ requiredPermission, attributionSource, null /* message */);
+ } else {
+ // Assume permission denial if PermissionManager is not yet available.
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+ } else {
+ perm = AppGlobals.getPackageManager()
+ .checkPermission(
+ requiredPermission,
+ info.activityInfo.applicationInfo.packageName,
+ UserHandle
+ .getUserId(info.activityInfo.applicationInfo.uid));
+ }
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
@@ -302,11 +329,13 @@
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")";
}
- int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
- if (!noteOpForManifestReceiver(appOp, r, info, component)) {
- return "Skipping delivery to " + info.activityInfo.packageName
- + " due to required appop " + appOp;
+ if (!usePermissionManagerForBroadcastDeliveryCheck()) {
+ int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
+ if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
+ if (!noteOpForManifestReceiver(appOp, r, info, component)) {
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to required appop " + appOp;
+ }
}
}
}
@@ -694,4 +723,11 @@
return false;
}
+
+ private PermissionManager getPermissionManager() {
+ if (mPermissionManager == null) {
+ mPermissionManager = mService.mContext.getSystemService(PermissionManager.class);
+ }
+ return mPermissionManager;
+ }
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 0cf5575..6e20f6c 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1414,8 +1414,13 @@
}
@GuardedBy({"mAm", "mProcLock"})
+ void forceFreezeAppAsyncLSP(ProcessRecord app) {
+ freezeAppAsyncInternalLSP(app, 0 /* delayMillis */, true /* force */);
+ }
+
+ @GuardedBy({"mAm", "mProcLock"})
private void freezeAppAsyncLSP(ProcessRecord app, @UptimeMillisLong long delayMillis) {
- freezeAppAsyncInternalLSP(app, delayMillis, false, false);
+ freezeAppAsyncInternalLSP(app, delayMillis, false /* force */);
}
@GuardedBy({"mAm", "mProcLock"})
@@ -1427,17 +1432,18 @@
// and remove this method.
@GuardedBy({"mAm", "mProcLock"})
void freezeAppAsyncImmediateLSP(ProcessRecord app) {
- freezeAppAsyncInternalLSP(app, 0, false, true);
+ freezeAppAsyncInternalLSP(app, 0 /* delayMillis */, false /* force */);
}
- // TODO: Update this method to be private and have the existing clients call different methods.
- // This "internal" method should not be directly triggered by clients outside this class.
@GuardedBy({"mAm", "mProcLock"})
- void freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis,
- boolean force, boolean immediate) {
+ private void freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis,
+ boolean force) {
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
if (opt.isPendingFreeze()) {
- if (immediate) {
+ if (delayMillis == 0) {
+ // Caller is requesting to freeze the process without delay, so remove
+ // any already posted messages which would have been handled with a delay and
+ // post a new message without a delay.
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
mFreezeHandler.sendMessage(mFreezeHandler.obtainMessage(
SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app));
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 0209944..fd847f1 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -86,3 +86,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "backstage_power"
+ name: "use_permission_manager_for_broadcast_delivery_check"
+ description: "Use PermissionManager API for broadcast delivery permission checks."
+ bug: "315468967"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e8c05c6..0f951746 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -73,6 +73,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
+import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -6853,15 +6854,6 @@
ringerMode = RINGER_MODE_SILENT;
}
}
- } else if (mIsSingleVolume && (direction == AudioManager.ADJUST_TOGGLE_MUTE
- || direction == AudioManager.ADJUST_MUTE)) {
- if (mHasVibrator) {
- ringerMode = RINGER_MODE_VIBRATE;
- } else {
- ringerMode = RINGER_MODE_SILENT;
- }
- // Setting the ringer mode will toggle mute
- result &= ~FLAG_ADJUST_VOLUME;
}
break;
case RINGER_MODE_VIBRATE:
@@ -6870,11 +6862,8 @@
"but no vibrator is present");
break;
}
- if ((direction == AudioManager.ADJUST_LOWER)) {
- // This is the case we were muted with the volume turned up
- if (mIsSingleVolume && oldIndex >= 2 * step && isMuted) {
- ringerMode = RINGER_MODE_NORMAL;
- } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+ if (direction == AudioManager.ADJUST_LOWER) {
+ if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
if (mVolumePolicy.volumeDownToEnterSilent) {
final long diff = SystemClock.uptimeMillis()
- mLoweredFromNormalToVibrateTime;
@@ -6894,10 +6883,7 @@
result &= ~FLAG_ADJUST_VOLUME;
break;
case RINGER_MODE_SILENT:
- if (mIsSingleVolume && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
- // This is the case we were muted with the volume turned up
- ringerMode = RINGER_MODE_NORMAL;
- } else if (direction == AudioManager.ADJUST_RAISE
+ if (direction == AudioManager.ADJUST_RAISE
|| direction == AudioManager.ADJUST_TOGGLE_MUTE
|| direction == AudioManager.ADJUST_UNMUTE) {
if (!mVolumePolicy.volumeUpToExitSilent) {
@@ -12207,7 +12193,9 @@
//==========================================================================================
public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
- boolean isVolumeController, IMediaProjection projection) {
+ boolean isVolumeController, IMediaProjection projection,
+ AttributionSource attributionSource) {
+ Objects.requireNonNull(attributionSource);
AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
if (!isPolicyRegisterAllowed(policyConfig,
@@ -12228,7 +12216,8 @@
}
try {
AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
- isFocusPolicy, isTestFocusPolicy, isVolumeController, projection);
+ isFocusPolicy, isTestFocusPolicy, isVolumeController, projection,
+ attributionSource);
pcb.asBinder().linkToDeath(app, 0/*flags*/);
// logging after registration so we have the registration id
@@ -12371,7 +12360,8 @@
}
private boolean callerHasPermission(String permission) {
- return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
}
/** @return true if projection is a valid MediaProjection that can project audio. */
@@ -13200,6 +13190,7 @@
public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
private static final String TAG = "AudioPolicyProxy";
final IAudioPolicyCallback mPolicyCallback;
+ final AttributionSource mAttributionSource;
final boolean mHasFocusListener;
final boolean mIsVolumeController;
final HashMap<Integer, AudioDeviceArray> mUidDeviceAffinities =
@@ -13239,10 +13230,12 @@
AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
- boolean isVolumeController, IMediaProjection projection) {
+ boolean isVolumeController, IMediaProjection projection,
+ AttributionSource attributionSource) {
super(config);
setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
mPolicyCallback = token;
+ mAttributionSource = attributionSource;
mHasFocusListener = hasFocusListener;
mIsVolumeController = isVolumeController;
mProjection = projection;
@@ -13370,6 +13363,7 @@
if (android.media.audiopolicy.Flags.audioMixOwnership()) {
for (AudioMix mix : mixes) {
setMixRegistration(mix);
+ mix.setVirtualDeviceId(mAttributionSource.getDeviceId());
}
int result = mAudioSystem.registerPolicyMixes(mixes, true);
@@ -13393,6 +13387,9 @@
@AudioSystem.AudioSystemError int connectMixes() {
final long identity = Binder.clearCallingIdentity();
try {
+ for (AudioMix mix : mMixes) {
+ mix.setVirtualDeviceId(mAttributionSource.getDeviceId());
+ }
return mAudioSystem.registerPolicyMixes(mMixes, true);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -13406,6 +13403,9 @@
Objects.requireNonNull(mixesToUpdate);
Objects.requireNonNull(updatedMixingRules);
+ for (AudioMix mix : mixesToUpdate) {
+ mix.setVirtualDeviceId(mAttributionSource.getDeviceId());
+ }
if (mixesToUpdate.length != updatedMixingRules.length) {
Log.e(TAG, "Provided list of audio mixes to update and corresponding mixing rules "
+ "have mismatching length (mixesToUpdate.length = " + mixesToUpdate.length
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index c507300..3d4801b 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -831,6 +831,7 @@
break;
case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
+ case BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS:
mClientReceiver.onDialogDismissed(reason);
break;
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 506b456..62c21cf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -256,10 +256,10 @@
// For BP, BiometricService will add the authToken to Keystore.
if (!isBiometricPrompt() && mIsStrongBiometric) {
final int result = KeyStore.getInstance().addAuthToken(byteToken);
- if (result != KeyStore.NO_ERROR) {
+ if (result != 0) {
Slog.d(TAG, "Error adding auth token : " + result);
} else {
- Slog.d(TAG, "addAuthToken: " + result);
+ Slog.d(TAG, "addAuthToken succeeded");
}
} else {
Slog.d(TAG, "Skipping addAuthToken");
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index fb826c8..11db183 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -895,7 +895,13 @@
for (int i = 0; i < mFaceSensors.size(); i++) {
final Sensor sensor = mFaceSensors.valueAt(i);
final int sensorId = mFaceSensors.keyAt(i);
- PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
+ final PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(
+ sensorId);
+ if (performanceTracker != null) {
+ performanceTracker.incrementHALDeathCount();
+ } else {
+ Slog.w(getTag(), "Performance tracker is null. Not counting HAL death.");
+ }
sensor.onBinderDied();
}
});
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index c04c47e..9290f8a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -954,7 +954,13 @@
for (int i = 0; i < mFingerprintSensors.size(); i++) {
final Sensor sensor = mFingerprintSensors.valueAt(i);
final int sensorId = mFingerprintSensors.keyAt(i);
- PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
+ final PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(
+ sensorId);
+ if (performanceTracker != null) {
+ performanceTracker.incrementHALDeathCount();
+ } else {
+ Slog.w(getTag(), "Performance tracker is null. Not counting HAL death.");
+ }
sensor.onBinderDied();
}
});
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b7ece2ea..5905b7d 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -366,7 +366,6 @@
private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
- private final INetworkManagementService mNms;
private final INetd mNetd;
@VisibleForTesting
@GuardedBy("this")
@@ -626,7 +625,6 @@
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
mDeps = deps;
- mNms = netService;
mNetd = netd;
mUserId = userId;
mLooper = looper;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 04e7f77..9950d8f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -894,6 +894,7 @@
@Nullable
private HdrBrightnessData mHdrBrightnessData;
+ // Null if low brightness mode is disabled - in config or by flag.
@Nullable
public LowBrightnessData mLowBrightnessData;
@@ -1063,6 +1064,9 @@
* @return The brightness mapping nits array.
*/
public float[] getNits() {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mNits;
+ }
return mNits;
}
@@ -1071,7 +1075,11 @@
*
* @return The backlight mapping value array.
*/
+ @VisibleForTesting
public float[] getBacklight() {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mBacklight;
+ }
return mBacklight;
}
@@ -1083,9 +1091,26 @@
* @return backlight value on the HAL scale of 0-1
*/
public float getBacklightFromBrightness(float brightness) {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mBrightnessToBacklight.interpolate(brightness);
+ }
return mBrightnessToBacklightSpline.interpolate(brightness);
}
+ private float getBrightnessFromBacklight(float brightness) {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mBacklightToBrightness.interpolate(brightness);
+ }
+ return mBacklightToBrightnessSpline.interpolate(brightness);
+ }
+
+ private Spline getBacklightToBrightnessSpline() {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mBacklightToBrightness;
+ }
+ return mBacklightToBrightnessSpline;
+ }
+
/**
* Calculates the nits value for the specified backlight value if a mapping exists.
*
@@ -1093,6 +1118,14 @@
* exits.
*/
public float getNitsFromBacklight(float backlight) {
+ if (mLowBrightnessData != null) {
+ if (mLowBrightnessData.mBacklightToNits == null) {
+ return INVALID_NITS;
+ }
+ backlight = Math.max(backlight, mBacklightMinimum);
+ return mLowBrightnessData.mBacklightToNits.interpolate(backlight);
+ }
+
if (mBacklightToNitsSpline == null) {
return INVALID_NITS;
}
@@ -1100,6 +1133,20 @@
return mBacklightToNitsSpline.interpolate(backlight);
}
+ private float getBacklightFromNits(float nits) {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mNitsToBacklight.interpolate(nits);
+ }
+ return mNitsToBacklightSpline.interpolate(nits);
+ }
+
+ private Spline getNitsToBacklightSpline() {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mNitsToBacklight;
+ }
+ return mNitsToBacklightSpline;
+ }
+
/**
* @return true if there is sdrHdrRatioMap, false otherwise.
*/
@@ -1126,13 +1173,13 @@
float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
float hdrNits = nits * ratio;
- if (mNitsToBacklightSpline == null) {
+ if (getNitsToBacklightSpline() == null) {
return PowerManager.BRIGHTNESS_INVALID;
}
- float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
+ float hdrBacklight = getBacklightFromNits(hdrNits);
hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
- float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);
+ float hdrBrightness = getBrightnessFromBacklight(hdrBacklight);
if (DEBUG) {
Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
@@ -1154,6 +1201,9 @@
* @return brightness array
*/
public float[] getBrightness() {
+ if (mLowBrightnessData != null) {
+ return mLowBrightnessData.mBrightness;
+ }
return mBrightness;
}
@@ -1987,7 +2037,8 @@
+ "mHdrBrightnessData= " + mHdrBrightnessData + "\n"
+ "mBrightnessCapForWearBedtimeMode= " + mBrightnessCapForWearBedtimeMode
+ "\n"
- + (mLowBrightnessData != null ? mLowBrightnessData.toString() : "")
+ + "mLowBrightnessData:" + (mLowBrightnessData != null
+ ? mLowBrightnessData.toString() : "null")
+ "}";
}
@@ -2588,9 +2639,9 @@
// A negative value means that there's no threshold
mLowDisplayBrightnessThresholds[i] = thresholdNits;
} else {
- float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
+ float thresholdBacklight = getBacklightFromNits(thresholdNits);
mLowDisplayBrightnessThresholds[i] =
- mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
+ getBrightnessFromBacklight(thresholdBacklight);
}
mLowAmbientBrightnessThresholds[i] = lowerThresholdDisplayBrightnessPoints
@@ -2639,9 +2690,9 @@
// A negative value means that there's no threshold
mHighDisplayBrightnessThresholds[i] = thresholdNits;
} else {
- float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
+ float thresholdBacklight = getBacklightFromNits(thresholdNits);
mHighDisplayBrightnessThresholds[i] =
- mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
+ getBrightnessFromBacklight(thresholdBacklight);
}
mHighAmbientBrightnessThresholds[i] = higherThresholdDisplayBrightnessPoints
@@ -2658,7 +2709,7 @@
loadAutoBrightnessBrighteningLightDebounceIdle(autoBrightness);
loadAutoBrightnessDarkeningLightDebounceIdle(autoBrightness);
mDisplayBrightnessMapping = new DisplayBrightnessMappingConfig(mContext, mFlags,
- autoBrightness, mBacklightToBrightnessSpline);
+ autoBrightness, getBacklightToBrightnessSpline());
loadEnableAutoBrightness(autoBrightness);
}
@@ -2832,17 +2883,10 @@
// These splines are used to convert from the system brightness value to the HAL backlight
// value
private void createBacklightConversionSplines() {
- if (mLowBrightnessData != null) {
- mBrightnessToBacklightSpline = mLowBrightnessData.mBrightnessToBacklight;
- mBacklightToBrightnessSpline = mLowBrightnessData.mBacklightToBrightness;
- mBacklightToNitsSpline = mLowBrightnessData.mBacklightToNits;
- mNitsToBacklightSpline = mLowBrightnessData.mNitsToBacklight;
- mNits = mLowBrightnessData.mNits;
- mBrightness = mLowBrightnessData.mBrightness;
- mBacklight = mLowBrightnessData.mBacklight;
- return;
- }
+
+ // Create original brightness splines - not using low brightness mode arrays - this is
+ // so that we can continue to log the original brightness splines.
mBrightness = new float[mBacklight.length];
for (int i = 0; i < mBrightness.length; i++) {
@@ -2884,7 +2928,7 @@
+ mBacklightMaximum);
}
mHbmData.transitionPoint =
- mBacklightToBrightnessSpline.interpolate(transitionPointBacklightScale);
+ getBrightnessFromBacklight(transitionPointBacklightScale);
final HbmTiming hbmTiming = hbm.getTiming_all();
mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
@@ -2953,7 +2997,7 @@
continue;
}
luxToTransitionPointMap.put(lux,
- mBacklightToBrightnessSpline.interpolate(maxBrightness));
+ getBrightnessFromBacklight(maxBrightness));
}
if (!luxToTransitionPointMap.isEmpty()) {
mLuxThrottlingData.put(mappedType, luxToTransitionPointMap);
@@ -3048,7 +3092,7 @@
private void loadAutoBrightnessConfigsFromConfigXml() {
mDisplayBrightnessMapping = new DisplayBrightnessMappingConfig(mContext, mFlags,
- /* autoBrightnessConfig= */ null, mBacklightToBrightnessSpline);
+ /* autoBrightnessConfig= */ null, getBacklightToBrightnessSpline());
}
private void loadBrightnessChangeThresholdsFromXml() {
@@ -3427,6 +3471,12 @@
throw new RuntimeException("Lux values should be in ascending order in the"
+ " idle screen refresh rate timeout config");
}
+
+ int timeout = point.getTimeout().intValue();
+ if (timeout < 0) {
+ throw new RuntimeException("The timeout value cannot be negative in"
+ + " idle screen refresh rate timeout config");
+ }
previousLux = newLux;
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 3b3a03b..86fab17 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -1103,7 +1103,8 @@
new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId,
mDisplayModeSpecs.allowGroupSwitching,
mDisplayModeSpecs.primary,
- mDisplayModeSpecs.appRequest)));
+ mDisplayModeSpecs.appRequest,
+ mDisplayModeSpecs.mIdleScreenRefreshRateConfig)));
}
}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 495ae87..572d32e 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -64,6 +64,8 @@
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -74,6 +76,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.utils.AmbientFilter;
@@ -184,6 +187,8 @@
private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
+ private final DisplayManagerFlags mDisplayManagerFlags;
+
private final boolean mDvrrSupported;
@@ -206,7 +211,7 @@
.isDisplaysRefreshRatesSynchronizationEnabled();
mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
-
+ mDisplayManagerFlags = displayManagerFlags;
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -374,7 +379,7 @@
final RefreshRateRanges ranges = new RefreshRateRanges(range, range);
return new DesiredDisplayModeSpecs(defaultMode.getModeId(),
/*allowGroupSwitching */ false,
- ranges, ranges);
+ ranges, ranges, mBrightnessObserver.getIdleScreenRefreshRateConfig());
}
boolean modeSwitchingDisabled =
@@ -422,7 +427,8 @@
appRequestSummary.maxPhysicalRefreshRate),
new RefreshRateRange(
appRequestSummary.minRenderFrameRate,
- appRequestSummary.maxRenderFrameRate)));
+ appRequestSummary.maxRenderFrameRate)),
+ mBrightnessObserver.getIdleScreenRefreshRateConfig());
}
}
@@ -764,6 +770,16 @@
public boolean allowGroupSwitching;
/**
+ * Represents the idle time of the screen after which the associated display's refresh rate
+ * is to be reduced to preserve power
+ * Defaults to null, meaning that the device is not configured to have a timeout based on
+ * the surrounding conditions
+ * -1 means that the current conditions require no timeout
+ */
+ @Nullable
+ public IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
+
+ /**
* The primary refresh rate ranges.
*/
public final RefreshRateRanges primary;
@@ -783,11 +799,13 @@
public DesiredDisplayModeSpecs(int baseModeId,
boolean allowGroupSwitching,
@NonNull RefreshRateRanges primary,
- @NonNull RefreshRateRanges appRequest) {
+ @NonNull RefreshRateRanges appRequest,
+ @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) {
this.baseModeId = baseModeId;
this.allowGroupSwitching = allowGroupSwitching;
this.primary = primary;
this.appRequest = appRequest;
+ this.mIdleScreenRefreshRateConfig = idleScreenRefreshRateConfig;
}
/**
@@ -797,9 +815,10 @@
public String toString() {
return String.format("baseModeId=%d allowGroupSwitching=%b"
+ " primary=%s"
- + " appRequest=%s",
+ + " appRequest=%s"
+ + " idleScreenRefreshRateConfig=%s",
baseModeId, allowGroupSwitching, primary.toString(),
- appRequest.toString());
+ appRequest.toString(), String.valueOf(mIdleScreenRefreshRateConfig));
}
/**
@@ -830,12 +849,18 @@
desiredDisplayModeSpecs.appRequest)) {
return false;
}
+
+ if (!Objects.equals(mIdleScreenRefreshRateConfig,
+ desiredDisplayModeSpecs.mIdleScreenRefreshRateConfig)) {
+ return false;
+ }
return true;
}
@Override
public int hashCode() {
- return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest);
+ return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest,
+ mIdleScreenRefreshRateConfig);
}
/**
@@ -853,6 +878,14 @@
appRequest.physical.max = other.appRequest.physical.max;
appRequest.render.min = other.appRequest.render.min;
appRequest.render.max = other.appRequest.render.max;
+
+ if (other.mIdleScreenRefreshRateConfig == null) {
+ mIdleScreenRefreshRateConfig = null;
+ } else {
+ mIdleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(
+ other.mIdleScreenRefreshRateConfig.timeoutMillis);
+ }
}
}
@@ -1543,12 +1576,20 @@
private float mAmbientLux = -1.0f;
private AmbientFilter mAmbientFilter;
+ /**
+ * The current timeout configuration. This value is used by surface flinger to track the
+ * time after which an idle screen's refresh rate is to be reduced.
+ */
+ @Nullable
+ private SurfaceControl.IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
+
private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private final Context mContext;
private final Injector mInjector;
private final Handler mHandler;
+
private final boolean mVsyncLowLightBlockingVoteEnabled;
private final IThermalEventListener.Stub mThermalListener =
@@ -1643,6 +1684,11 @@
return mRefreshRateInLowZone;
}
+ @VisibleForTesting
+ IdleScreenRefreshRateConfig getIdleScreenRefreshRateConfig() {
+ return mIdleScreenRefreshRateConfig;
+ }
+
private void loadLowBrightnessThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig,
boolean attemptReadFromFeatureParams) {
loadRefreshRateInHighZone(displayDeviceConfig, attemptReadFromFeatureParams);
@@ -2381,6 +2427,10 @@
// is interrupted by a new sensor event.
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
+
+ if (mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled()) {
+ updateIdleScreenRefreshRate(mAmbientLux);
+ }
}
@Override
@@ -2440,6 +2490,40 @@
}
};
}
+
+ private void updateIdleScreenRefreshRate(float ambientLux) {
+ List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
+ idleScreenRefreshRateTimeoutLuxThresholdPoints;
+ synchronized (mLock) {
+ if (mDefaultDisplayDeviceConfig == null || mDefaultDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint().isEmpty()) {
+ // Setting this to null will let surface flinger know that the idle timer is not
+ // configured in the display configs
+ mIdleScreenRefreshRateConfig = null;
+ return;
+ }
+
+ idleScreenRefreshRateTimeoutLuxThresholdPoints =
+ mDefaultDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ }
+ int newTimeout = -1;
+ for (IdleScreenRefreshRateTimeoutLuxThresholdPoint point :
+ idleScreenRefreshRateTimeoutLuxThresholdPoints) {
+ int newLux = point.getLux().intValue();
+ if (newLux <= ambientLux) {
+ newTimeout = point.getTimeout().intValue();
+ }
+ }
+ if (mIdleScreenRefreshRateConfig == null
+ || newTimeout != mIdleScreenRefreshRateConfig.timeoutMillis) {
+ mIdleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(newTimeout);
+ synchronized (mLock) {
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
+ }
+ }
}
private class UdfpsObserver extends IUdfpsRefreshRateRequestCallback.Stub {
diff --git a/services/core/java/com/android/server/feature/dropbox_flags.aconfig b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
index fee4bf3..14e964b 100644
--- a/services/core/java/com/android/server/feature/dropbox_flags.aconfig
+++ b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
@@ -2,6 +2,7 @@
flag{
name: "enable_read_dropbox_permission"
+ is_exported: true
namespace: "preload_safety"
description: "Feature flag for permission to Read dropbox data"
bug: "287512663"
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 3fafca8..96d4bda 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -143,6 +143,15 @@
}
@Override
+ public int peekSystemGrammaticalGenderByUserId(AttributionSource attributionSource,
+ int userId) {
+ return canGetSystemGrammaticalGender(attributionSource)
+ ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
+ attributionSource, userId)
+ : GRAMMATICAL_GENDER_NOT_SPECIFIED;
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 05b1cb69..468b902 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2604,6 +2604,19 @@
mBatteryController.notifyStylusGestureStarted(deviceId, eventTime);
}
+ // Native callback.
+ @SuppressWarnings("unused")
+ private int getPackageUid(String pkg) {
+ if (TextUtils.isEmpty(pkg)) {
+ return Process.INVALID_UID;
+ }
+ try {
+ return mContext.getPackageManager().getPackageUid(pkg, 0 /*flags*/);
+ } catch (PackageManager.NameNotFoundException e) {
+ return Process.INVALID_UID;
+ }
+ }
+
/**
* Flatten a map into a string list, with value positioned directly next to the
* key.
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index 23fe5cc..dbdac41 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -16,6 +16,8 @@
package com.android.server.inputmethod;
+import static com.android.text.flags.Flags.handwritingEndOfLineTap;
+
import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.NonNull;
@@ -30,6 +32,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
import android.view.BatchedInputEventReceiver;
@@ -66,6 +69,7 @@
// Use getHandwritingBufferSize() and not this value directly.
private static final int LONG_EVENT_BUFFER_SIZE = EVENT_BUFFER_SIZE * 20;
private static final long HANDWRITING_DELEGATION_IDLE_TIMEOUT_MS = 3000;
+ private static final long AFTER_STYLUS_UP_ALLOW_PERIOD_MS = 200L;
private final Context mContext;
// This must be the looper for the UiThread.
@@ -78,6 +82,7 @@
private InputEventReceiver mHandwritingEventReceiver;
private Runnable mInkWindowInitRunnable;
private boolean mRecordingGesture;
+ private boolean mRecordingGestureAfterStylusUp;
private int mCurrentDisplayId;
// when set, package names are used for handwriting delegation.
private @Nullable String mDelegatePackageName;
@@ -155,6 +160,15 @@
}
boolean isStylusGestureOngoing() {
+ if (mRecordingGestureAfterStylusUp && !mHandwritingBuffer.isEmpty()) {
+ // If it is less than AFTER_STYLUS_UP_ALLOW_PERIOD_MS after the stylus up event, return
+ // true so that handwriting can start.
+ MotionEvent lastEvent = mHandwritingBuffer.get(mHandwritingBuffer.size() - 1);
+ if (lastEvent.getActionMasked() == MotionEvent.ACTION_UP) {
+ return SystemClock.uptimeMillis() - lastEvent.getEventTime()
+ < AFTER_STYLUS_UP_ALLOW_PERIOD_MS;
+ }
+ }
return mRecordingGesture;
}
@@ -277,7 +291,7 @@
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
return null;
}
- if (!mRecordingGesture || mHandwritingBuffer.isEmpty()) {
+ if (!isStylusGestureOngoing()) {
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
return null;
}
@@ -300,6 +314,7 @@
mHandwritingEventReceiver.dispose();
mHandwritingEventReceiver = null;
mRecordingGesture = false;
+ mRecordingGestureAfterStylusUp = false;
if (mHandwritingSurface.isIntercepting()) {
throw new IllegalStateException(
@@ -362,6 +377,7 @@
clearPendingHandwritingDelegation();
}
mRecordingGesture = false;
+ mRecordingGestureAfterStylusUp = false;
}
private boolean onInputEvent(InputEvent ev) {
@@ -412,15 +428,20 @@
if ((TextUtils.isEmpty(mDelegatePackageName) || mDelegationConnectionlessFlow)
&& (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
mRecordingGesture = false;
- mHandwritingBuffer.clear();
- return;
+ if (handwritingEndOfLineTap() && action == MotionEvent.ACTION_UP) {
+ mRecordingGestureAfterStylusUp = true;
+ } else {
+ mHandwritingBuffer.clear();
+ return;
+ }
}
if (action == MotionEvent.ACTION_DOWN) {
+ clearBufferIfRecordingAfterStylusUp();
mRecordingGesture = true;
}
- if (!mRecordingGesture) {
+ if (!mRecordingGesture && !mRecordingGestureAfterStylusUp) {
return;
}
@@ -430,12 +451,20 @@
+ " The rest of the gesture will not be recorded.");
}
mRecordingGesture = false;
+ clearBufferIfRecordingAfterStylusUp();
return;
}
mHandwritingBuffer.add(MotionEvent.obtain(event));
}
+ private void clearBufferIfRecordingAfterStylusUp() {
+ if (mRecordingGestureAfterStylusUp) {
+ mHandwritingBuffer.clear();
+ mRecordingGestureAfterStylusUp = false;
+ }
+ }
+
static final class HandwritingSession {
private final int mRequestId;
private final InputChannel mHandwritingChannel;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 29cccdf..99c7397 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -119,6 +119,14 @@
}
/**
+ * Interface used to abstract {@code InputMethodBindingController} instantiation.
+ */
+ interface Creator {
+
+ InputMethodBindingController create();
+ }
+
+ /**
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d0a83a6..c406e17 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -303,8 +303,6 @@
@MultiUserUnawareField
private final InputMethodMenuController mMenuController;
@MultiUserUnawareField
- @NonNull private final InputMethodBindingController mBindingController;
- @MultiUserUnawareField
@NonNull private final AutofillSuggestionsController mAutofillController;
@GuardedBy("ImfLock.class")
@@ -465,12 +463,14 @@
@GuardedBy("ImfLock.class")
@Nullable
String getSelectedMethodIdLocked() {
- return mBindingController.getSelectedMethodId();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getSelectedMethodId();
}
@GuardedBy("ImfLock.class")
private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
- mBindingController.setSelectedMethodId(selectedMethodId);
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ userData.mBindingController.setSelectedMethodId(selectedMethodId);
}
/**
@@ -479,8 +479,8 @@
*/
@GuardedBy("ImfLock.class")
private int getSequenceNumberLocked() {
- final UserData monitor = UserData.getOrCreate(mCurrentUserId);
- return monitor.mSequence.getSequenceNumber();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mSequence.getSequenceNumber();
}
/**
@@ -550,7 +550,8 @@
@GuardedBy("ImfLock.class")
@Nullable
private String getCurIdLocked() {
- return mBindingController.getCurId();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getCurId();
}
/**
@@ -574,7 +575,8 @@
*/
@GuardedBy("ImfLock.class")
private boolean hasConnectionLocked() {
- return mBindingController.hasMainConnection();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.hasMainConnection();
}
/**
@@ -597,7 +599,8 @@
@GuardedBy("ImfLock.class")
@Nullable
private Intent getCurIntentLocked() {
- return mBindingController.getCurIntent();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getCurIntent();
}
/**
@@ -607,7 +610,8 @@
@GuardedBy("ImfLock.class")
@Nullable
IBinder getCurTokenLocked() {
- return mBindingController.getCurToken();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getCurToken();
}
/**
@@ -648,7 +652,8 @@
@GuardedBy("ImfLock.class")
@Nullable
IInputMethodInvoker getCurMethodLocked() {
- return mBindingController.getCurMethod();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getCurMethod();
}
/**
@@ -656,7 +661,8 @@
*/
@GuardedBy("ImfLock.class")
private int getCurMethodUidLocked() {
- return mBindingController.getCurMethodUid();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getCurMethodUid();
}
/**
@@ -665,7 +671,8 @@
*/
@GuardedBy("ImfLock.class")
private long getLastBindTimeLocked() {
- return mBindingController.getLastBindTime();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ return userData.mBindingController.getLastBindTime();
}
/**
@@ -1248,7 +1255,15 @@
mService.publishLocalService();
IInputMethodManager.Stub service;
if (Flags.useZeroJankProxy()) {
- service = new ZeroJankProxy(mService.mHandler::post, mService);
+ service =
+ new ZeroJankProxy(
+ mService.mHandler::post,
+ mService,
+ () -> {
+ synchronized (ImfLock.class) {
+ return mService.isInputShown();
+ }
+ });
} else {
service = mService;
}
@@ -1371,7 +1386,6 @@
// InputMethodSettingsRepository should be initialized before buildInputMethodListLocked
InputMethodSettingsRepository.initialize(mHandler, mContext);
AdditionalSubtypeMapRepository.initialize(mHandler, mContext);
- UserData.initialize(mHandler);
mCurrentUserId = mActivityManagerInternal.getCurrentUserId();
@@ -1384,19 +1398,17 @@
new HardwareKeyboardShortcutController(settings.getMethodMap(),
settings.getUserId());
mMenuController = new InputMethodMenuController(this);
- mBindingController =
- bindingControllerForTesting != null
- ? bindingControllerForTesting
- : new InputMethodBindingController(this);
mAutofillController = new AutofillSuggestionsController(this);
-
mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
mVisibilityApplier = new DefaultImeVisibilityApplier(this);
-
mClientController = new ClientController(mPackageManagerInternal);
synchronized (ImfLock.class) {
mClientController.addClientControllerCallback(c -> onClientRemoved(c));
mImeBindingState = ImeBindingState.newEmptyState();
+ UserData.initialize(mHandler,
+ /* bindingControllerCreator= */ () -> bindingControllerForTesting != null
+ ? bindingControllerForTesting
+ : new InputMethodBindingController(this));
}
mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
@@ -1732,9 +1744,11 @@
// Check if selected IME of current user supports handwriting.
if (userId == mCurrentUserId) {
- return mBindingController.supportsStylusHandwriting()
+ final UserData userData = UserData.getOrCreate(userId);
+ final InputMethodBindingController bindingController = userData.mBindingController;
+ return bindingController.supportsStylusHandwriting()
&& (!connectionless
- || mBindingController.supportsConnectionlessStylusHandwriting());
+ || bindingController.supportsConnectionlessStylusHandwriting());
}
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(
@@ -2063,7 +2077,8 @@
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
- if (mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ if (userData.mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
mHwController.setInkWindowInitializer(new InkWindowInitializer());
}
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
@@ -2178,13 +2193,14 @@
mCurEditorInfo = editorInfo;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
unverifiedTargetSdkVersion)) {
if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
invalidateAutofillSessionLocked();
- mBindingController.unbindCurrentMethod();
+ userData.mBindingController.unbindCurrentMethod();
return InputBindResult.NO_EDITOR;
}
@@ -2216,9 +2232,8 @@
}
}
- mBindingController.unbindCurrentMethod();
-
- return mBindingController.bindCurrentMethod();
+ userData.mBindingController.unbindCurrentMethod();
+ return userData.mBindingController.bindCurrentMethod();
}
/**
@@ -2481,7 +2496,8 @@
setSelectedMethodIdLocked(null);
// Callback before clean-up binding states.
onUnbindCurrentMethodByReset();
- mBindingController.unbindCurrentMethod();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ userData.mBindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
}
@@ -3113,7 +3129,8 @@
@Nullable String delegatorPackageName,
@NonNull IConnectionlessHandwritingCallback callback) throws RemoteException {
synchronized (ImfLock.class) {
- if (!mBindingController.supportsConnectionlessStylusHandwriting()) {
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ if (!userData.mBindingController.supportsConnectionlessStylusHandwriting()) {
Slog.w(TAG, "Connectionless stylus handwriting mode unsupported by IME.");
callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED);
return;
@@ -3179,9 +3196,10 @@
+ " startStylusHandwriting()");
return false;
}
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
final long ident = Binder.clearCallingIdentity();
try {
- if (!mBindingController.supportsStylusHandwriting()) {
+ if (!userData.mBindingController.supportsStylusHandwriting()) {
Slog.w(TAG,
"Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
return false;
@@ -3360,7 +3378,8 @@
mVisibilityStateComputer.requestImeVisibility(windowToken, true);
// Ensure binding the connection when IME is going to show.
- mBindingController.setCurrentMethodVisible();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ userData.mBindingController.setCurrentMethodVisible();
final IInputMethodInvoker curMethod = getCurMethodLocked();
ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
if (curMethod != null) {
@@ -3463,7 +3482,8 @@
} else {
ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
}
- mBindingController.setCurrentMethodNotVisible();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ userData.mBindingController.setCurrentMethodNotVisible();
mVisibilityStateComputer.clearImeShowFlags();
// Cancel existing statsToken for show IME as we got a hide request.
ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
@@ -3745,7 +3765,8 @@
// Note that we can trust client's display ID as long as it matches
// to the display ID obtained from the window.
if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
- mBindingController.unbindCurrentMethod();
+ final UserData userData = UserData.getOrCreate(userId);
+ userData.mBindingController.unbindCurrentMethod();
}
}
}
@@ -4201,6 +4222,7 @@
}, mHandler);
}
+ @GuardedBy("ImfLock.class")
private void addStylusDeviceIdLocked(int deviceId) {
if (mStylusIds == null) {
mStylusIds = new IntArray();
@@ -4211,8 +4233,10 @@
mStylusIds.add(deviceId);
// a new Stylus is detected. If IME supports handwriting, and we don't have
// handwriting initialized, lets do it now.
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ final InputMethodBindingController bindingController = userData.mBindingController;
if (!mHwController.getCurrentRequestId().isPresent()
- && mBindingController.supportsStylusHandwriting()) {
+ && bindingController.supportsStylusHandwriting()) {
scheduleResetStylusHandwriting();
}
}
@@ -4788,7 +4812,8 @@
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
- if (mBindingController.supportsStylusHandwriting()
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ if (userData.mBindingController.supportsStylusHandwriting()
&& getCurMethodLocked() != null && hasSupportedStylusLocked()) {
Slog.d(TAG, "Initializing Handwriting Spy");
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
@@ -4813,11 +4838,12 @@
if (curMethod == null || mImeBindingState.mFocusedWindow == null) {
return true;
}
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
final HandwritingModeController.HandwritingSession session =
mHwController.startHandwritingSession(
msg.arg1 /*requestId*/,
msg.arg2 /*pid*/,
- mBindingController.getCurMethodUid(),
+ userData.mBindingController.getCurMethodUid(),
mImeBindingState.mFocusedWindow);
if (session == null) {
Slog.e(TAG,
@@ -5111,7 +5137,8 @@
@GuardedBy("ImfLock.class")
void sendOnNavButtonFlagsChangedLocked() {
- final IInputMethodInvoker curMethod = mBindingController.getCurMethod();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ final IInputMethodInvoker curMethod = userData.mBindingController.getCurMethod();
if (curMethod == null) {
// No need to send the data if the IME is not yet bound.
return;
@@ -5868,9 +5895,10 @@
p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
mImeBindingState.dump(" ", p);
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
p.println(" mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
+ " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
- + mBindingController.isVisibleBound());
+ + userData.mBindingController.isVisibleBound());
p.println(" mCurToken=" + getCurTokenLocked());
p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
p.println(" mCurHostInputToken=" + mCurHostInputToken);
@@ -6364,7 +6392,8 @@
if (userId == mCurrentUserId) {
hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
- mBindingController.unbindCurrentMethod();
+ final UserData userData = UserData.getOrCreate(mCurrentUserId);
+ userData.mBindingController.unbindCurrentMethod();
// Enable default IMEs, disable others
var toDisable = settings.getEnabledInputMethodList();
diff --git a/services/core/java/com/android/server/inputmethod/UserData.java b/services/core/java/com/android/server/inputmethod/UserData.java
index fc2a422..8e20611 100644
--- a/services/core/java/com/android/server/inputmethod/UserData.java
+++ b/services/core/java/com/android/server/inputmethod/UserData.java
@@ -28,8 +28,10 @@
final class UserData {
- @NonNull
- private static final SparseArray<UserData> sPerUserMonitor = new SparseArray<>();
+ private static SparseArray<UserData> sUserData;
+
+ @GuardedBy("ImfLock.class")
+ private static InputMethodBindingController.Creator sBindingControllerCreator;
@UserIdInt
final int mUserId;
@@ -37,24 +39,33 @@
@GuardedBy("ImfLock.class")
final Sequence mSequence = new Sequence();
+ @NonNull
+ final InputMethodBindingController mBindingController;
+
/**
* Not intended to be instantiated.
*/
- private UserData(int userId) {
+ private UserData(int userId,
+ InputMethodBindingController bindingController) {
mUserId = userId;
+ mBindingController = bindingController;
}
@GuardedBy("ImfLock.class")
static UserData getOrCreate(@UserIdInt int userId) {
- UserData monitor = sPerUserMonitor.get(userId);
- if (monitor == null) {
- monitor = new UserData(userId);
- sPerUserMonitor.put(userId, monitor);
+ UserData userData = sUserData.get(userId);
+ if (userData == null) {
+ userData = new UserData(userId, sBindingControllerCreator.create());
+ sUserData.put(userId, userData);
}
- return monitor;
+ return userData;
}
- static void initialize(Handler handler) {
+ @GuardedBy("ImfLock.class")
+ static void initialize(Handler handler,
+ InputMethodBindingController.Creator bindingControllerCreator) {
+ sUserData = new SparseArray<>();
+ sBindingControllerCreator = bindingControllerCreator;
final UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserLifecycleListener(
@@ -64,7 +75,7 @@
final int userId = user.id;
handler.post(() -> {
synchronized (ImfLock.class) {
- sPerUserMonitor.remove(userId);
+ sUserData.remove(userId);
}
});
}
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index 396192e..31ce630 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -46,7 +46,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.util.ExceptionUtils;
import android.util.Slog;
import android.view.WindowManager;
import android.view.inputmethod.CursorAnchorInfo;
@@ -77,6 +76,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.function.BooleanSupplier;
/**
* A proxy that processes all {@link IInputMethodManager} calls asynchronously.
@@ -86,10 +86,12 @@
private final IInputMethodManager mInner;
private final Executor mExecutor;
+ private final BooleanSupplier mIsInputShown;
- ZeroJankProxy(Executor executor, IInputMethodManager inner) {
+ ZeroJankProxy(Executor executor, IInputMethodManager inner, BooleanSupplier isInputShown) {
mInner = inner;
mExecutor = executor;
+ mIsInputShown = isInputShown;
}
private void offload(ThrowingRunnable r) {
@@ -163,8 +165,19 @@
int lastClickTooType, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason)
throws RemoteException {
- offload(() -> mInner.showSoftInput(client, windowToken, statsToken, flags, lastClickTooType,
- resultReceiver, reason));
+ offload(
+ () -> {
+ if (!mInner.showSoftInput(
+ client,
+ windowToken,
+ statsToken,
+ flags,
+ lastClickTooType,
+ resultReceiver,
+ reason)) {
+ sendResultReceiverFailure(resultReceiver);
+ }
+ });
return true;
}
@@ -173,11 +186,24 @@
@Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)
throws RemoteException {
- offload(() -> mInner.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver,
- reason));
+ offload(
+ () -> {
+ if (!mInner.hideSoftInput(
+ client, windowToken, statsToken, flags, resultReceiver, reason)) {
+ sendResultReceiverFailure(resultReceiver);
+ }
+ });
return true;
}
+ private void sendResultReceiverFailure(ResultReceiver resultReceiver) {
+ resultReceiver.send(
+ mIsInputShown.getAsBoolean()
+ ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+ : InputMethodManager.RESULT_UNCHANGED_HIDDEN,
+ null);
+ }
+
@Override
@EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
public void hideSoftInputFromServerForTest() throws RemoteException {
@@ -415,14 +441,17 @@
private void sendOnStartInputResult(
IInputMethodClient client, InputBindResult res, int startInputSeq) {
- InputMethodManagerService service = (InputMethodManagerService) mInner;
- final ClientState cs = service.getClientState(client);
- if (cs != null && cs.mClient != null) {
- cs.mClient.onStartInputResult(res, startInputSeq);
- } else {
- // client is unbound.
- Slog.i(TAG, "Client that requested startInputOrWindowGainedFocus is no longer"
- + " bound. InputBindResult: " + res + " for startInputSeq: " + startInputSeq);
+ synchronized (ImfLock.class) {
+ InputMethodManagerService service = (InputMethodManagerService) mInner;
+ final ClientState cs = service.getClientState(client);
+ if (cs != null && cs.mClient != null) {
+ cs.mClient.onStartInputResult(res, startInputSeq);
+ } else {
+ // client is unbound.
+ Slog.i(TAG, "Client that requested startInputOrWindowGainedFocus is no longer"
+ + " bound. InputBindResult: " + res + " for startInputSeq: "
+ + startInputSeq);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index a608049..6e991b4 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.LOCATION_BYPASS;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -34,6 +35,7 @@
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -73,6 +75,7 @@
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.flags.Flags;
import android.location.provider.ForwardGeocodeRequest;
import android.location.provider.IGeocodeCallback;
import android.location.provider.IProviderRequestListener;
@@ -776,8 +779,19 @@
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
- LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
- PERMISSION_COARSE);
+ if (Flags.enableLocationBypass()) {
+ if (permissionLevel == PERMISSION_NONE) {
+ if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) {
+ LocationPermissions.enforceLocationPermission(
+ identity.getUid(), permissionLevel, PERMISSION_COARSE);
+ } else {
+ permissionLevel = PERMISSION_FINE;
+ }
+ }
+ } else {
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
+ PERMISSION_COARSE);
+ }
// clients in the system process must have an attribution tag set
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
@@ -805,8 +819,19 @@
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
- LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
- PERMISSION_COARSE);
+ if (Flags.enableLocationBypass()) {
+ if (permissionLevel == PERMISSION_NONE) {
+ if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) {
+ LocationPermissions.enforceLocationPermission(
+ identity.getUid(), permissionLevel, PERMISSION_COARSE);
+ } else {
+ permissionLevel = PERMISSION_FINE;
+ }
+ }
+ } else {
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
+ PERMISSION_COARSE);
+ }
// clients in the system process should have an attribution tag set
if (identity.getPid() == Process.myPid() && attributionTag == null) {
@@ -830,8 +855,19 @@
AppOpsManager.toReceiverId(pendingIntent));
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
- LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
- PERMISSION_COARSE);
+ if (Flags.enableLocationBypass()) {
+ if (permissionLevel == PERMISSION_NONE) {
+ if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) {
+ LocationPermissions.enforceLocationPermission(
+ identity.getUid(), permissionLevel, PERMISSION_COARSE);
+ } else {
+ permissionLevel = PERMISSION_FINE;
+ }
+ }
+ } else {
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
+ PERMISSION_COARSE);
+ }
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
@@ -982,8 +1018,19 @@
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
- LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
- PERMISSION_COARSE);
+ if (Flags.enableLocationBypass()) {
+ if (permissionLevel == PERMISSION_NONE) {
+ if (mContext.checkCallingPermission(LOCATION_BYPASS) != PERMISSION_GRANTED) {
+ LocationPermissions.enforceLocationPermission(
+ identity.getUid(), permissionLevel, PERMISSION_COARSE);
+ } else {
+ permissionLevel = PERMISSION_FINE;
+ }
+ }
+ } else {
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
+ PERMISSION_COARSE);
+ }
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 40e538b..542a29a 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -16,6 +16,7 @@
package com.android.server.location.provider;
+import static android.Manifest.permission.LOCATION_BYPASS;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.app.compat.CompatChanges.isChangeEnabled;
@@ -51,6 +52,7 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AlarmManager.OnAlarmListener;
+import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.Context;
@@ -66,6 +68,7 @@
import android.location.LocationResult;
import android.location.LocationResult.BadLocationException;
import android.location.altitude.AltitudeConverter;
+import android.location.flags.Flags;
import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
@@ -106,6 +109,7 @@
import com.android.server.location.injector.AppForegroundHelper;
import com.android.server.location.injector.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.injector.AppOpsHelper;
+import com.android.server.location.injector.EmergencyHelper;
import com.android.server.location.injector.Injector;
import com.android.server.location.injector.LocationPermissionsHelper;
import com.android.server.location.injector.LocationPermissionsHelper.LocationPermissionsListener;
@@ -375,8 +379,13 @@
// we cache these values because checking/calculating on the fly is more expensive
@GuardedBy("mMultiplexerLock")
private boolean mPermitted;
+
+ @GuardedBy("mMultiplexerLock")
+ private boolean mBypassPermitted;
+
@GuardedBy("mMultiplexerLock")
private boolean mForeground;
+
@GuardedBy("mMultiplexerLock")
private LocationRequest mProviderLocationRequest;
@GuardedBy("mMultiplexerLock")
@@ -421,8 +430,8 @@
EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), mBaseRequest);
// initialization order is important as there are ordering dependencies
- mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
- getIdentity());
+ onLocationPermissionsChanged();
+ onBypassLocationPermissionsChanged(mEmergencyHelper.isInEmergency(0));
mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
mProviderLocationRequest = calculateProviderLocationRequest();
mIsUsingHighPower = isUsingHighPower();
@@ -491,7 +500,13 @@
public final boolean isPermitted() {
synchronized (mMultiplexerLock) {
- return mPermitted;
+ return mPermitted || mBypassPermitted;
+ }
+ }
+
+ public final boolean isOnlyBypassPermitted() {
+ synchronized (mMultiplexerLock) {
+ return mBypassPermitted && !mPermitted;
}
}
@@ -562,6 +577,33 @@
}
}
+ boolean onBypassLocationPermissionsChanged(boolean isInEmergency) {
+ synchronized (mMultiplexerLock) {
+ boolean bypassPermitted =
+ Flags.enableLocationBypass() && isInEmergency
+ && mContext.checkPermission(
+ LOCATION_BYPASS, mIdentity.getPid(), mIdentity.getUid())
+ == PERMISSION_GRANTED;
+ if (mBypassPermitted != bypassPermitted) {
+ if (D) {
+ Log.v(
+ TAG,
+ mName
+ + " provider package "
+ + getIdentity().getPackageName()
+ + " bypass permitted = "
+ + bypassPermitted);
+ }
+
+ mBypassPermitted = bypassPermitted;
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
@GuardedBy("mMultiplexerLock")
private boolean onLocationPermissionsChanged() {
boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
@@ -941,8 +983,11 @@
}
// note app ops
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
- getIdentity())) {
+ int op =
+ Flags.enableLocationBypass() && isOnlyBypassPermitted()
+ ? AppOpsManager.OP_EMERGENCY_LOCATION
+ : LocationPermissions.asAppOp(getPermissionLevel());
+ if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) {
if (D) {
Log.w(TAG,
mName + " provider registration " + getIdentity() + " noteOp denied");
@@ -1292,12 +1337,17 @@
}
// lastly - note app ops
- if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow(
- LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) {
- if (D) {
- Log.w(TAG, "noteOp denied for " + getIdentity());
+ if (fineLocationResult != null) {
+ int op =
+ Flags.enableLocationBypass() && isOnlyBypassPermitted()
+ ? AppOpsManager.OP_EMERGENCY_LOCATION
+ : LocationPermissions.asAppOp(getPermissionLevel());
+ if (!mAppOpsHelper.noteOpNoThrow(op, getIdentity())) {
+ if (D) {
+ Log.w(TAG, "noteOp denied for " + getIdentity());
+ }
+ fineLocationResult = null;
}
- fineLocationResult = null;
}
if (fineLocationResult != null) {
@@ -1399,6 +1449,7 @@
protected final ScreenInteractiveHelper mScreenInteractiveHelper;
protected final LocationUsageLogger mLocationUsageLogger;
protected final LocationFudger mLocationFudger;
+ protected final EmergencyHelper mEmergencyHelper;
private final PackageResetHelper mPackageResetHelper;
private final UserListener mUserChangedListener = this::onUserChanged;
@@ -1434,6 +1485,8 @@
this::onLocationPowerSaveModeChanged;
private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener =
this::onScreenInteractiveChanged;
+ private final EmergencyHelper.EmergencyStateChangedListener mEmergencyStateChangedListener =
+ this::onEmergencyStateChanged;
private final PackageResetHelper.Responder mPackageResetResponder =
new PackageResetHelper.Responder() {
@Override
@@ -1507,6 +1560,7 @@
mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
mLocationUsageLogger = injector.getLocationUsageLogger();
mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
+ mEmergencyHelper = injector.getEmergencyHelper();
mPackageResetHelper = injector.getPackageResetHelper();
mProvider = new MockableLocationProvider(mMultiplexerLock);
@@ -1757,8 +1811,17 @@
if (location != null) {
// lastly - note app ops
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
+ int op =
+ (Flags.enableLocationBypass()
+ && !mLocationPermissionsHelper.hasLocationPermissions(
+ permissionLevel, identity)
+ && mEmergencyHelper.isInEmergency(0)
+ && mContext.checkPermission(
+ LOCATION_BYPASS, identity.getPid(), identity.getUid())
+ == PERMISSION_GRANTED)
+ ? AppOpsManager.OP_EMERGENCY_LOCATION
+ : LocationPermissions.asAppOp(permissionLevel);
+ if (!mAppOpsHelper.noteOpNoThrow(op, identity)) {
return null;
}
@@ -2069,6 +2132,9 @@
mAppForegroundHelper.addListener(mAppForegroundChangedListener);
mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
+ if (Flags.enableLocationBypass()) {
+ mEmergencyHelper.addOnEmergencyStateChangedListener(mEmergencyStateChangedListener);
+ }
mPackageResetHelper.register(mPackageResetResponder);
}
@@ -2088,6 +2154,9 @@
mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener);
mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener);
+ if (Flags.enableLocationBypass()) {
+ mEmergencyHelper.removeOnEmergencyStateChangedListener(mEmergencyStateChangedListener);
+ }
mPackageResetHelper.unregister(mPackageResetResponder);
}
@@ -2466,6 +2535,12 @@
}
}
+ private void onEmergencyStateChanged() {
+ boolean inEmergency = mEmergencyHelper.isInEmergency(0);
+ updateRegistrations(
+ registration -> registration.onBypassLocationPermissionsChanged(inEmergency));
+ }
+
private void onBackgroundThrottlePackageWhitelistChanged() {
updateRegistrations(Registration::onProviderLocationRequestChanged);
}
diff --git a/services/core/java/com/android/server/media/AudioManagerRouteController.java b/services/core/java/com/android/server/media/AudioManagerRouteController.java
index 087f5a6..2439589 100644
--- a/services/core/java/com/android/server/media/AudioManagerRouteController.java
+++ b/services/core/java/com/android/server/media/AudioManagerRouteController.java
@@ -42,6 +42,7 @@
import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.media.BluetoothRouteController.NoOpBluetoothRouteController;
import java.util.HashMap;
@@ -57,8 +58,21 @@
*
* <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 BluetoothDeviceRoutesManager}, which depends on the
- * bluetooth stack ({@link BluetoothAdapter} and related classes).
+ * which are managed by {@link BluetoothDeviceRoutesManager}, which depends on the bluetooth stack
+ * ({@link BluetoothAdapter} and related classes).
+ *
+ * <p>This class runs as part of the system_server process, but depends on classes that may
+ * communicate with other processes, like bluetooth or audio server. And these other processes may
+ * require binder threads from system server. As a result, there are a few threading considerations
+ * to keep in mind:
+ *
+ * <ul>
+ * <li>Some of this class' internal state is synchronized using {@code this} as lock.
+ * <li>Binder threads may call into this class and run synchronized code.
+ * <li>As a result the above, in order to avoid deadlocks, calls to components that may call into
+ * other processes (like {@link AudioManager} or {@link BluetoothDeviceRoutesManager}) must
+ * not be synchronized nor occur on a binder thread.
+ * </ul>
*/
/* package */ final class AudioManagerRouteController implements DeviceRouteController {
private static final String TAG = SystemMediaRoute2Provider.TAG;
@@ -77,10 +91,6 @@
@NonNull private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener;
@NonNull private final BluetoothDeviceRoutesManager mBluetoothRouteController;
- @NonNull
- private final Map<String, MediaRoute2InfoHolder> mRouteIdToAvailableDeviceRoutes =
- new HashMap<>();
-
@NonNull private final AudioProductStrategy mStrategyForMedia;
@NonNull private final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallbackImpl();
@@ -91,7 +101,14 @@
private final AudioManager.OnDevicesForAttributesChangedListener
mOnDevicesForAttributesChangedListener = this::onDevicesForAttributesChangedListener;
- @NonNull private MediaRoute2Info mSelectedRoute;
+ @GuardedBy("this")
+ @NonNull
+ private final Map<String, MediaRoute2InfoHolder> mRouteIdToAvailableDeviceRoutes =
+ new HashMap<>();
+
+ @GuardedBy("this")
+ @NonNull
+ private MediaRoute2Info mSelectedRoute;
// TODO: b/305199571 - Support nullable btAdapter and strategyForMedia which, when null, means
// no support for transferring to inactive bluetooth routes and transferring to any routes
@@ -170,7 +187,7 @@
@RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Override
- public synchronized void transferTo(@Nullable String routeId) {
+ public void transferTo(@Nullable String routeId) {
if (routeId == null) {
// This should never happen: This branch should only execute when the matching bluetooth
// route controller is not the no-op one.
@@ -179,11 +196,17 @@
Slog.e(TAG, "Unexpected call to AudioPoliciesDeviceRouteController#transferTo(null)");
return;
}
- MediaRoute2InfoHolder mediaRoute2InfoHolder = mRouteIdToAvailableDeviceRoutes.get(routeId);
+ MediaRoute2InfoHolder mediaRoute2InfoHolder;
+ synchronized (this) {
+ mediaRoute2InfoHolder = mRouteIdToAvailableDeviceRoutes.get(routeId);
+ }
if (mediaRoute2InfoHolder == null) {
Slog.w(TAG, "transferTo: Ignoring transfer request to unknown route id : " + routeId);
return;
}
+ // TODO: b/329929065 - Push audio manager and bluetooth operations to the handler, so that
+ // they don't run on a binder thread, so as to prevent possible deadlocks (these operations
+ // may need system_server binder threads to complete).
if (mediaRoute2InfoHolder.mCorrespondsToInactiveBluetoothRoute) {
// By default, the last connected device is the active route so we don't need to apply a
// routing audio policy.
@@ -206,7 +229,7 @@
Manifest.permission.QUERY_AUDIO_STATE
})
@Override
- public synchronized boolean updateVolume(int volume) {
+ public boolean updateVolume(int volume) {
// TODO: b/305199571 - Optimize so that we only update the volume of the selected route. We
// don't need to rebuild all available routes.
rebuildAvailableRoutesAndNotify();
@@ -231,7 +254,7 @@
Manifest.permission.MODIFY_AUDIO_ROUTING,
Manifest.permission.QUERY_AUDIO_STATE
})
- private synchronized void rebuildAvailableRoutesAndNotify() {
+ private void rebuildAvailableRoutesAndNotify() {
rebuildAvailableRoutes();
mOnDeviceRouteChangedListener.onDeviceRouteChanged();
}
@@ -241,7 +264,7 @@
Manifest.permission.MODIFY_AUDIO_ROUTING,
Manifest.permission.QUERY_AUDIO_STATE
})
- private synchronized void rebuildAvailableRoutes() {
+ private void rebuildAvailableRoutes() {
List<AudioDeviceAttributes> attributesOfSelectedOutputDevices =
mAudioManager.getDevicesForAttributes(MEDIA_USAGE_AUDIO_ATTRIBUTES);
int selectedDeviceAttributesType;
@@ -260,8 +283,43 @@
selectedDeviceAttributesType = attributesOfSelectedOutputDevices.get(0).getType();
}
- AudioDeviceInfo[] audioDeviceInfos =
- mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ updateAvailableRoutes(
+ selectedDeviceAttributesType,
+ /* audioDeviceInfos= */ mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS),
+ /* availableBluetoothRoutes= */ mBluetoothRouteController
+ .getAvailableBluetoothRoutes(),
+ /* musicVolume= */ mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
+ /* musicMaxVolume= */ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+ /* isVolumeFixed= */ mAudioManager.isVolumeFixed());
+ }
+
+ /**
+ * Updates route and session info using the given information from {@link AudioManager}.
+ *
+ * <p>Synchronization is limited to this method in order to avoid calling into {@link
+ * AudioManager} or {@link BluetoothDeviceRoutesManager} while holding a lock that may also be
+ * acquired by binder threads. See class javadoc for more details.
+ *
+ * @param selectedDeviceAttributesType The {@link AudioDeviceInfo#getType() type} that
+ * corresponds to the currently selected route.
+ * @param audioDeviceInfos The available audio outputs as obtained from {@link
+ * AudioManager#getDevices}.
+ * @param availableBluetoothRoutes The available bluetooth routes as obtained from {@link
+ * BluetoothDeviceRoutesManager#getAvailableBluetoothRoutes()}.
+ * @param musicVolume The volume of the music stream as obtained from {@link
+ * AudioManager#getStreamVolume}.
+ * @param musicMaxVolume The max volume of the music stream as obtained from {@link
+ * AudioManager#getStreamMaxVolume}.
+ * @param isVolumeFixed Whether the volume is fixed as obtained from {@link
+ * AudioManager#isVolumeFixed()}.
+ */
+ private synchronized void updateAvailableRoutes(
+ int selectedDeviceAttributesType,
+ AudioDeviceInfo[] audioDeviceInfos,
+ List<MediaRoute2Info> availableBluetoothRoutes,
+ int musicVolume,
+ int musicMaxVolume,
+ boolean isVolumeFixed) {
mRouteIdToAvailableDeviceRoutes.clear();
MediaRoute2InfoHolder newSelectedRouteHolder = null;
for (AudioDeviceInfo audioDeviceInfo : audioDeviceInfos) {
@@ -301,7 +359,8 @@
newSelectedRouteHolder = mRouteIdToAvailableDeviceRoutes.values().iterator().next();
}
MediaRoute2InfoHolder selectedRouteHolderWithUpdatedVolumeInfo =
- newSelectedRouteHolder.copyWithVolumeInfoFromAudioManager(mAudioManager);
+ newSelectedRouteHolder.copyWithVolumeInfo(
+ musicVolume, musicMaxVolume, isVolumeFixed);
mRouteIdToAvailableDeviceRoutes.put(
newSelectedRouteHolder.mMediaRoute2Info.getId(),
selectedRouteHolderWithUpdatedVolumeInfo);
@@ -309,7 +368,7 @@
// We only add those BT routes that we have not already obtained from audio manager (which
// are active).
- mBluetoothRouteController.getAvailableBluetoothRoutes().stream()
+ availableBluetoothRoutes.stream()
.filter(it -> !mRouteIdToAvailableDeviceRoutes.containsKey(it.getId()))
.map(MediaRoute2InfoHolder::createForInactiveBluetoothRoute)
.forEach(
@@ -430,17 +489,16 @@
mCorrespondsToInactiveBluetoothRoute = correspondsToInactiveBluetoothRoute;
}
- public MediaRoute2InfoHolder copyWithVolumeInfoFromAudioManager(
- AudioManager mAudioManager) {
+ public MediaRoute2InfoHolder copyWithVolumeInfo(
+ int musicVolume, int musicMaxVolume, boolean isVolumeFixed) {
MediaRoute2Info routeInfoWithVolumeInfo =
new MediaRoute2Info.Builder(mMediaRoute2Info)
.setVolumeHandling(
- mAudioManager.isVolumeFixed()
+ isVolumeFixed
? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
- .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
- .setVolumeMax(
- mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .setVolume(musicVolume)
+ .setVolumeMax(musicMaxVolume)
.build();
return new MediaRoute2InfoHolder(
routeInfoWithVolumeInfo,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 5d415c2..67d3fe9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -662,7 +662,9 @@
}
@Override
- public void notifyProviderUpdated(MediaRoute2ProviderInfo providerInfo) {
+ public void notifyProviderUpdated(@NonNull MediaRoute2ProviderInfo providerInfo) {
+ Objects.requireNonNull(providerInfo, "providerInfo must not be null");
+
for (MediaRoute2Info route : providerInfo.getRoutes()) {
if (route.isSystemRoute()) {
throw new SecurityException(
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index fcca94b..178eb71 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -145,6 +145,10 @@
new ComponentName(serviceInfo.packageName, serviceInfo.name),
isSelfScanOnlyProvider,
mUserId);
+ Slog.i(
+ TAG,
+ "Enabling proxy for MediaRoute2ProviderService: "
+ + proxy.mComponentName);
proxy.start(/* rebindIfDisconnected= */ false);
mProxies.add(targetIndex++, proxy);
mCallback.onAddProviderService(proxy);
@@ -162,6 +166,9 @@
if (targetIndex < mProxies.size()) {
for (int i = mProxies.size() - 1; i >= targetIndex; i--) {
MediaRoute2ProviderServiceProxy proxy = mProxies.get(i);
+ Slog.i(
+ TAG,
+ "Disabling proxy for MediaRoute2ProviderService: " + proxy.mComponentName);
mCallback.onRemoveProviderService(proxy);
mProxies.remove(proxy);
proxy.stop();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 51a8aef..ae6a7e9 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1022,7 +1022,7 @@
// Uid and package name are shared across all manager records in the list.
boolean isAppOpAllowed =
- mAppOpsManager.unsafeCheckOp(
+ mAppOpsManager.unsafeCheckOpNoThrow(
AppOpsManager.OPSTR_MEDIA_ROUTING_CONTROL,
record.mOwnerUid,
record.mOwnerPackageName)
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index a9a8272..5b3934e 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -687,27 +687,20 @@
private static String toVolumeControlTypeString(
@VolumeProvider.ControlType int volumeControlType) {
- switch (volumeControlType) {
- case VOLUME_CONTROL_FIXED:
- return "FIXED";
- case VOLUME_CONTROL_RELATIVE:
- return "RELATIVE";
- case VOLUME_CONTROL_ABSOLUTE:
- return "ABSOLUTE";
- default:
- return TextUtils.formatSimple("unknown(%d)", volumeControlType);
- }
+ return switch (volumeControlType) {
+ case VOLUME_CONTROL_FIXED -> "FIXED";
+ case VOLUME_CONTROL_RELATIVE -> "RELATIVE";
+ case VOLUME_CONTROL_ABSOLUTE -> "ABSOLUTE";
+ default -> TextUtils.formatSimple("unknown(%d)", volumeControlType);
+ };
}
private static String toVolumeTypeString(@PlaybackInfo.PlaybackType int volumeType) {
- switch (volumeType) {
- case PLAYBACK_TYPE_LOCAL:
- return "LOCAL";
- case PLAYBACK_TYPE_REMOTE:
- return "REMOTE";
- default:
- return TextUtils.formatSimple("unknown(%d)", volumeType);
- }
+ return switch (volumeType) {
+ case PLAYBACK_TYPE_LOCAL -> "LOCAL";
+ case PLAYBACK_TYPE_REMOTE -> "REMOTE";
+ default -> TextUtils.formatSimple("unknown(%d)", volumeType);
+ };
}
@Override
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index f7210dd..319947a 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -646,6 +646,8 @@
return;
}
+ // TODO: b/310145678 - Post this to mHandler once mHandler does not run on the main
+ // thread.
updateVolume();
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 25095ed..22f5332 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1214,16 +1214,14 @@
return false;
}
final int previousProcState = previousInfo.procState;
- if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
- != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
- // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
- // BACKGROUND chain may change.
- return true;
- }
if ((previousProcState <= TOP_THRESHOLD_STATE)
- != (newProcState <= TOP_THRESHOLD_STATE)) {
- // Proc-state change crossed TOP_THRESHOLD_STATE: Network rules for the
- // LOW_POWER_STANDBY chain may change.
+ || (newProcState <= TOP_THRESHOLD_STATE)) {
+ // If the proc-state change crossed TOP_THRESHOLD_STATE, network rules for the
+ // LOW_POWER_STANDBY chain may change, so we need to evaluate the transition.
+ // In addition, we always process changes when the new process state is
+ // TOP_THRESHOLD_STATE or below, to avoid situations where the TOP app ends up
+ // waiting for NPMS to finish processing newProcStateSeq, even when it was
+ // redundant (b/327303931).
return true;
}
if ((previousProcState <= FOREGROUND_THRESHOLD_STATE)
@@ -1232,6 +1230,12 @@
// different chains may change.
return true;
}
+ if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+ != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
+ // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
+ // BACKGROUND chain may change.
+ return true;
+ }
final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
if ((previousInfo.capability & networkCapabilities)
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index d0e95dd..669cdaa 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -4,3 +4,4 @@
jsharkey@android.com
sudheersai@google.com
yamasani@google.com
+suprabh@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e80c79a8..9fcdfdd 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -11924,6 +11924,9 @@
if (record != null && (record.getSbn().getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
boolean isAppForeground = pkg != null && packageImportance == IMPORTANCE_FOREGROUND;
+
+ // Lifetime extended notifications don't need to alert on state change.
+ record.setPostSilently(true);
mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(),
record, isAppForeground,
mPostNotificationTrackerFactory.newTracker(null)));
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 4f3cdbc..50ca984 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -310,6 +310,7 @@
parser.getAttributeInt(null, ATT_VISIBILITY, DEFAULT_VISIBILITY),
parser.getAttributeBoolean(null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
bubblePref);
+ r.bubblePreference = bubblePref;
r.priority = parser.getAttributeInt(null, ATT_PRIORITY, DEFAULT_PRIORITY);
r.visibility = parser.getAttributeInt(null, ATT_VISIBILITY, DEFAULT_VISIBILITY);
r.showBadge = parser.getAttributeBoolean(null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
@@ -676,7 +677,7 @@
* @param bubblePreference whether bubbles are allowed.
*/
public void setBubblesAllowed(String pkg, int uid, int bubblePreference) {
- boolean changed = false;
+ boolean changed;
synchronized (mPackagePreferences) {
PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid);
changed = p.bubblePreference != bubblePreference;
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 37023e1..953300a 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -163,7 +163,7 @@
}
@Override
- public void getVersion(RemoteCallback remoteCallback) throws RemoteException {
+ public void getVersion(RemoteCallback remoteCallback) {
Slog.i(TAG, "OnDeviceIntelligenceManagerInternal getVersion");
Objects.requireNonNull(remoteCallback);
mContext.enforceCallingOrSelfPermission(
@@ -244,7 +244,7 @@
@Override
public void requestFeatureDownload(Feature feature,
- ICancellationSignal cancellationSignal,
+ AndroidFuture cancellationSignalFuture,
IDownloadCallback downloadCallback) throws RemoteException {
Slog.i(TAG, "OnDeviceIntelligenceManagerInternal requestFeatureDownload");
Objects.requireNonNull(feature);
@@ -261,16 +261,17 @@
ensureRemoteIntelligenceServiceInitialized();
mRemoteOnDeviceIntelligenceService.run(
service -> service.requestFeatureDownload(Binder.getCallingUid(), feature,
- cancellationSignal,
+ cancellationSignalFuture,
downloadCallback));
}
@Override
public void requestTokenInfo(Feature feature,
- Bundle request, ICancellationSignal cancellationSignal,
+ Bundle request,
+ AndroidFuture cancellationSignalFuture,
ITokenInfoCallback tokenInfoCallback) throws RemoteException {
- Slog.i(TAG, "OnDeviceIntelligenceManagerInternal prepareFeatureProcessing");
+ Slog.i(TAG, "OnDeviceIntelligenceManagerInternal requestTokenInfo");
Objects.requireNonNull(feature);
Objects.requireNonNull(request);
Objects.requireNonNull(tokenInfoCallback);
@@ -285,10 +286,11 @@
PersistableBundle.EMPTY);
}
ensureRemoteInferenceServiceInitialized();
+
mRemoteInferenceService.run(
service -> service.requestTokenInfo(Binder.getCallingUid(), feature,
request,
- cancellationSignal,
+ cancellationSignalFuture,
tokenInfoCallback));
}
@@ -296,8 +298,8 @@
public void processRequest(Feature feature,
Bundle request,
int requestType,
- ICancellationSignal cancellationSignal,
- IProcessingSignal processingSignal,
+ AndroidFuture cancellationSignalFuture,
+ AndroidFuture processingSignalFuture,
IResponseCallback responseCallback)
throws RemoteException {
Slog.i(TAG, "OnDeviceIntelligenceManagerInternal processRequest");
@@ -316,7 +318,7 @@
mRemoteInferenceService.run(
service -> service.processRequest(Binder.getCallingUid(), feature, request,
requestType,
- cancellationSignal, processingSignal,
+ cancellationSignalFuture, processingSignalFuture,
responseCallback));
}
@@ -324,8 +326,8 @@
public void processRequestStreaming(Feature feature,
Bundle request,
int requestType,
- ICancellationSignal cancellationSignal,
- IProcessingSignal processingSignal,
+ AndroidFuture cancellationSignalFuture,
+ AndroidFuture processingSignalFuture,
IStreamingResponseCallback streamingCallback) throws RemoteException {
Slog.i(TAG, "OnDeviceIntelligenceManagerInternal processRequestStreaming");
Objects.requireNonNull(feature);
@@ -343,7 +345,7 @@
mRemoteInferenceService.run(
service -> service.processRequestStreaming(Binder.getCallingUid(), feature,
request, requestType,
- cancellationSignal, processingSignal,
+ cancellationSignalFuture, processingSignalFuture,
streamingCallback));
}
@@ -356,7 +358,7 @@
};
}
- private void ensureRemoteIntelligenceServiceInitialized() throws RemoteException {
+ private void ensureRemoteIntelligenceServiceInitialized() {
synchronized (mLock) {
if (mRemoteOnDeviceIntelligenceService == null) {
String serviceName = getServiceNames()[0];
@@ -388,25 +390,15 @@
public void updateProcessingState(
Bundle processingState,
IProcessingUpdateStatusCallback callback) {
- try {
- ensureRemoteInferenceServiceInitialized();
- mRemoteInferenceService.run(
- service -> service.updateProcessingState(
- processingState, callback));
- } catch (RemoteException unused) {
- try {
- callback.onFailure(
- OnDeviceIntelligenceException.PROCESSING_UPDATE_STATUS_CONNECTION_FAILED,
- "Received failure invoking the remote processing service.");
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to send failure status.", ex);
- }
- }
+ ensureRemoteInferenceServiceInitialized();
+ mRemoteInferenceService.run(
+ service -> service.updateProcessingState(
+ processingState, callback));
}
};
}
- private void ensureRemoteInferenceServiceInitialized() throws RemoteException {
+ private void ensureRemoteInferenceServiceInitialized() {
synchronized (mLock) {
if (mRemoteInferenceService == null) {
String serviceName = getServiceNames()[1];
@@ -457,34 +449,38 @@
};
}
- private static void validateServiceElevated(String serviceName, boolean checkIsolated)
- throws RemoteException {
- if (TextUtils.isEmpty(serviceName)) {
- throw new IllegalArgumentException("Received null/empty service name : " + serviceName);
- }
- ComponentName serviceComponent = ComponentName.unflattenFromString(
- serviceName);
- ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
- serviceComponent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 0);
- if (serviceInfo != null) {
- if (!checkIsolated) {
- checkServiceRequiresPermission(serviceInfo,
- Manifest.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE);
- return;
+ private void validateServiceElevated(String serviceName, boolean checkIsolated) {
+ try {
+ if (TextUtils.isEmpty(serviceName)) {
+ throw new IllegalStateException(
+ "Remote service is not configured to complete the request");
}
+ ComponentName serviceComponent = ComponentName.unflattenFromString(
+ serviceName);
+ ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
+ serviceComponent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 0);
+ if (serviceInfo != null) {
+ if (!checkIsolated) {
+ checkServiceRequiresPermission(serviceInfo,
+ Manifest.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE);
+ return;
+ }
- checkServiceRequiresPermission(serviceInfo,
- Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE);
- if (!isIsolatedService(serviceInfo)) {
- throw new SecurityException(
- "Call required an isolated service, but the configured service: "
- + serviceName + ", is not isolated");
+ checkServiceRequiresPermission(serviceInfo,
+ Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE);
+ if (!isIsolatedService(serviceInfo)) {
+ throw new SecurityException(
+ "Call required an isolated service, but the configured service: "
+ + serviceName + ", is not isolated");
+ }
+ } else {
+ throw new IllegalStateException(
+ "Remote service is not configured to complete the request.");
}
- } else {
- throw new RuntimeException(
- "Could not find service info for serviceName: " + serviceName);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Could not fetch service info for remote services", e);
}
}
@@ -542,7 +538,8 @@
Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
synchronized (mLock) {
mTemporaryServiceNames = componentNames;
-
+ mRemoteOnDeviceIntelligenceService = null;
+ mRemoteInferenceService = null;
if (mTemporaryHandler == null) {
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
@Override
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 9480c8e..2005b17 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -137,6 +137,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.ondeviceintelligence.OnDeviceIntelligenceManagerInternal;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -4353,9 +4354,8 @@
if (Process.isSdkSandboxUid(uid)) {
uid = getBaseSdkSandboxUid();
}
- if (Process.isIsolatedUid(uid)
- && mPermissionManager.getHotwordDetectionServiceProvider() != null
- && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (isKnownIsolatedComputeApp(uid, callingUserId)) {
try {
uid = getIsolatedOwner(uid);
} catch (IllegalStateException e) {
@@ -4363,7 +4363,6 @@
Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
}
}
- final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
@@ -4399,9 +4398,7 @@
if (Process.isSdkSandboxUid(uid)) {
uid = getBaseSdkSandboxUid();
}
- if (Process.isIsolatedUid(uid)
- && mPermissionManager.getHotwordDetectionServiceProvider() != null
- && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
+ if (isKnownIsolatedComputeApp(uid, callingUserId)) {
try {
uid = getIsolatedOwner(uid);
} catch (IllegalStateException e) {
@@ -5802,6 +5799,43 @@
return getPackage(mService.getSdkSandboxPackageName()).getUid();
}
+
+ private boolean isKnownIsolatedComputeApp(int uid, int callingUserId) {
+ if (!Process.isIsolatedUid(uid)) {
+ return false;
+ }
+ final boolean isHotword =
+ mPermissionManager.getHotwordDetectionServiceProvider() != null
+ && uid
+ == mPermissionManager.getHotwordDetectionServiceProvider().getUid();
+ if (isHotword) {
+ return true;
+ }
+ OnDeviceIntelligenceManagerInternal onDeviceIntelligenceManagerInternal =
+ mInjector.getLocalService(OnDeviceIntelligenceManagerInternal.class);
+ if (onDeviceIntelligenceManagerInternal == null) {
+ return false;
+ }
+
+ String onDeviceIntelligencePackage =
+ onDeviceIntelligenceManagerInternal.getRemoteServicePackageName();
+ if (onDeviceIntelligencePackage == null) {
+ return false;
+ }
+
+ try {
+ if (getIsolatedOwner(uid) == getPackageUid(onDeviceIntelligencePackage, 0,
+ callingUserId)) {
+ return true;
+ }
+ } catch (IllegalStateException e) {
+ // If the owner uid doesn't exist, just use the current uid
+ Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+ }
+
+ return false;
+ }
+
@Nullable
@Override
public SharedUserApi getSharedUser(int sharedUserAppId) {
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 588c629..fd16221 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -542,7 +542,8 @@
final Computer snapshot = mPm.snapshotComputer();
for (final int affectedUserId : outInfo.mRemovedUsers) {
if (hadSuspendAppsPermission.get(affectedUserId)) {
- mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
+ mPm.unsuspendForSuspendingPackage(snapshot, packageName,
+ affectedUserId /*suspendingUserId*/, true /*inAllUsers*/);
mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
}
}
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 51793f6..c60f0af 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -46,7 +46,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApexStagedEvent;
-import android.content.pm.Flags;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageManager;
@@ -663,9 +662,7 @@
}
}, new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
- if (Flags.useArtServiceV2()) {
- StagedApexObserver.registerForStagedApexUpdates(artManager);
- }
+ StagedApexObserver.registerForStagedApexUpdates(artManager);
}
/**
@@ -750,9 +747,7 @@
& PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE)
!= 0;
/*@DexoptFlags*/ int extraFlags =
- ignoreDexoptProfile && Flags.useArtServiceV2()
- ? ArtFlags.FLAG_IGNORE_PROFILE
- : 0;
+ ignoreDexoptProfile ? ArtFlags.FLAG_IGNORE_PROFILE : 0;
DexoptParams params = dexoptOptions.convertToDexoptParams(extraFlags);
DexoptResult dexOptResult = getArtManagerLocal().dexoptPackage(
snapshot, packageName, params);
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 43075a2..c10196f 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -35,7 +35,6 @@
import android.app.AppOpsManager;
import android.content.pm.ArchivedPackageParcel;
import android.content.pm.DataLoaderType;
-import android.content.pm.Flags;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -951,7 +950,7 @@
// Only report external profile warnings when installing from adb. The goal is to warn app
// developers if they have provided bad external profiles, so it's not beneficial to report
// those warnings in the normal app install workflow.
- if (isInstallFromAdb() && Flags.useArtServiceV2()) {
+ if (isInstallFromAdb()) {
var externalProfileErrors = new LinkedHashSet<String>();
for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
for (DexContainerFileDexoptResult fileResult :
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c6bb99e..20b669b 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -18,12 +18,12 @@
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_ARCHIVE_ICON_OVERLAY;
import static android.app.AppOpsManager.OP_UNARCHIVAL_CONFIRMATION;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -555,12 +555,6 @@
return false;
}
- if (!mRoleManager
- .getRoleHoldersAsUser(
- RoleManager.ROLE_HOME, UserHandle.getUserHandleForUid(callingUid))
- .contains(callingPackage.getPackageName())) {
- return false;
- }
if (mContext.checkPermission(
Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL,
callingPid,
@@ -569,6 +563,13 @@
return true;
}
+ if (!mRoleManager
+ .getRoleHoldersAsUser(
+ RoleManager.ROLE_HOME, UserHandle.getUserHandleForUid(callingUid))
+ .contains(callingPackage.getPackageName())) {
+ return false;
+ }
+
// TODO(b/321988638): add option to disable with a flag
return mContext.checkPermission(
android.Manifest.permission.ACCESS_HIDDEN_PROFILES,
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 8da1683..7a72e70 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
@@ -45,6 +46,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
+import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -687,14 +689,17 @@
@Override
@Deprecated
public final void unsuspendAdminSuspendedPackages(int affectedUser) {
- final int suspendingUserId = affectedUser;
- mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
+ final int suspendingUserId =
+ crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : affectedUser;
+ mService.unsuspendForSuspendingPackage(
+ snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId, /* inAllUsers= */ false);
}
@Override
@Deprecated
public final boolean isAdminSuspendingAnyPackages(int userId) {
- final int suspendingUserId = userId;
+ final int suspendingUserId =
+ crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : userId;
return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d215822..9a2b98f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -3181,27 +3182,53 @@
callingMethod);
}
- final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
- final boolean allowedPackageUid = packageUid == callingUid;
- // TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
- final boolean allowedShell = callingUid == SHELL_UID
- && UserHandle.isSameApp(packageUid, callingUid);
+ if (crossUserSuspensionEnabled()) {
+ final int suspendingPackageUid =
+ snapshot.getPackageUid(suspender.packageName, 0, suspender.userId);
+ if (suspendingPackageUid != callingUid) {
+ throw new SecurityException("Suspender package %s doesn't match calling uid %d"
+ .formatted(suspender.packageName, callingUid));
+ }
+ if (targetUserId != suspender.userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingMethod);
+ }
+ } else {
+ // Here only SHELL can suspend across users
+ final int packageUid =
+ snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
+ final boolean allowedPackageUid = packageUid == callingUid;
+ final boolean allowedShell = callingUid == SHELL_UID
+ && UserHandle.isSameApp(packageUid, callingUid);
- if (!allowedShell && !allowedPackageUid) {
- throw new SecurityException("Suspending package " + suspender.packageName
- + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
+ if (!allowedShell && !allowedPackageUid) {
+ throw new SecurityException("Suspending package " + suspender.packageName
+ + " in user " + targetUserId + " does not belong to calling uid "
+ + callingUid);
+ }
}
}
+ /**
+ * @param inAllUsers Whether to unsuspend packages suspended by the given package in other
+ * users. This flag is only used when cross-user suspension is enabled.
+ */
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
- @UserIdInt int suspendingUserId) {
+ @UserIdInt int suspendingUserId, boolean inAllUsers) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
// this weird pre-collect of all packages.
final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
final Predicate<UserPackage> suspenderPredicate =
UserPackage.of(suspendingUserId, suspendingPackage)::equals;
- mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
- allPackages, suspenderPredicate, suspendingUserId);
+ if (!crossUserSuspensionEnabled() || !inAllUsers) {
+ mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
+ allPackages, suspenderPredicate, suspendingUserId);
+ } else {
+ for (int targetUserId: mUserManager.getUserIds()) {
+ mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(
+ computer, allPackages, suspenderPredicate, targetUserId);
+ }
+ }
}
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -4053,7 +4080,7 @@
// This app should not generally be allowed to get disabled by the UI, but
// if it ever does, we don't want to end up with some of the user's apps
// permanently suspended.
- unsuspendForSuspendingPackage(computer, packageName, userId);
+ unsuspendForSuspendingPackage(computer, packageName, userId, true /* inAllUsers */);
removeAllDistractingPackageRestrictions(computer, userId);
}
success = true;
@@ -4339,6 +4366,19 @@
}
mInstantAppRegistry.onUserRemoved(userId);
mPackageMonitorCallbackHelper.onUserRemoved(userId);
+ if (crossUserSuspensionEnabled()) {
+ cleanUpCrossUserSuspension(userId);
+ }
+ }
+
+ private void cleanUpCrossUserSuspension(int removedUser) {
+ final Computer computer = snapshotComputer();
+ var allPackages = computer.getAllAvailablePackageNames();
+ for (int targetUserId : mUserManager.getUserIds()) {
+ if (targetUserId == removedUser) continue;
+ mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
+ userPackage -> userPackage.userId == removedUser, targetUserId);
+ }
}
/**
@@ -4745,7 +4785,8 @@
if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
== PERMISSION_GRANTED) {
final Computer snapshot = snapshotComputer();
- unsuspendForSuspendingPackage(snapshot, packageName, userId);
+ unsuspendForSuspendingPackage(
+ snapshot, packageName, userId, true /* inAllUsers */);
removeAllDistractingPackageRestrictions(snapshot, userId);
synchronized (mLock) {
flushPackageRestrictionsAsUserInternalLocked(userId);
@@ -6239,7 +6280,9 @@
final boolean quarantined = ((flags & PackageManager.FLAG_SUSPEND_QUARANTINED) != 0)
&& Flags.quarantinedEnabled();
final Computer snapshot = snapshotComputer();
- final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
+ final UserPackage suspender = crossUserSuspensionEnabled()
+ ? UserPackage.of(suspendingUserId, suspendingPackage)
+ : UserPackage.of(targetUserId, suspendingPackage);
enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
targetUserId, "setPackagesSuspendedAsUser");
return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
@@ -6707,7 +6750,10 @@
@Override
public String[] setPackagesSuspendedByAdmin(
@UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
- final int suspendingUserId = userId;
+ // Suspension by admin isn't attributed to admin package but to the platform,
+ // Using USER_SYSTEM for consistency with other internal suspenders, like shell or root.
+ final int suspendingUserId =
+ crossUserSuspensionEnabled() ? UserHandle.USER_SYSTEM : userId;
final UserPackage suspender = UserPackage.of(
suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 12eb88e..b44042c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
@@ -1240,6 +1241,10 @@
for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
state.getSuspendParams().keyAt(j).packageName);
+ if (crossUserSuspensionEnabled()) {
+ proto.write(PackageProto.UserInfoProto.SUSPENDING_USER,
+ state.getSuspendParams().keyAt(j).userId);
+ }
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e35a169..f5ed8d4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static android.app.admin.flags.Flags.crossUserSuspensionEnabled;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -342,6 +343,7 @@
private static final String ATTR_DISTRACTION_FLAGS = "distraction_flags";
private static final String ATTR_SUSPENDED = "suspended";
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
+ private static final String ATTR_SUSPENDING_USER = "suspending-user";
private static final String ATTR_OPTIONAL = "optional";
/**
@@ -2051,7 +2053,20 @@
Slog.wtf(TAG, "No suspendingPackage found inside tag " + TAG_SUSPEND_PARAMS);
return null;
}
- final int suspendingUserId = userId;
+ int suspendingUserId;
+ if (crossUserSuspensionEnabled()) {
+ suspendingUserId = parser.getAttributeInt(
+ null, ATTR_SUSPENDING_USER, UserHandle.USER_NULL);
+ if (suspendingUserId == UserHandle.USER_NULL) {
+ suspendingUserId = switch (suspendingPackage) {
+ case "root", "com.android.shell", PLATFORM_PACKAGE_NAME
+ -> UserHandle.USER_SYSTEM;
+ default -> userId;
+ };
+ }
+ } else {
+ suspendingUserId = userId;
+ }
return Map.entry(
UserPackage.of(suspendingUserId, suspendingPackage),
SuspendParams.restoreFromXml(parser));
@@ -2418,6 +2433,10 @@
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
suspendingPackage.packageName);
+ if (crossUserSuspensionEnabled()) {
+ serializer.attributeInt(null, ATTR_SUSPENDING_USER,
+ suspendingPackage.userId);
+ }
final SuspendParams params =
ustate.getSuspendParams().valueAt(i);
if (params != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 12a5892..76bf8fd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -530,6 +530,14 @@
// TODO(b/178103325): Track sleep/requested sleep for every display.
volatile boolean mRequestedOrSleepingDefaultDisplay;
+ /**
+ * This is used to check whether to invoke {@link #updateScreenOffSleepToken} when screen is
+ * turned off. E.g. if it is false when screen is turned off and the display is swapping, it
+ * is expected that the screen will be on in a short time. Then it is unnecessary to acquire
+ * screen-off-sleep-token, so it can avoid intermediate visibility or lifecycle changes.
+ */
+ volatile boolean mIsGoingToSleepDefaultDisplay;
+
volatile boolean mRecentsVisible;
volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
volatile boolean mPictureInPictureVisible;
@@ -3500,7 +3508,7 @@
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.enterDesktop(getTargetDisplayIdForKeyEvent(event));
+ statusbar.moveFocusedTaskToDesktop(getTargetDisplayIdForKeyEvent(event));
logKeyboardSystemsEvent(event, KeyboardLogEvent.DESKTOP_MODE);
return true;
}
@@ -5470,6 +5478,15 @@
}
mRequestedOrSleepingDefaultDisplay = true;
+ mIsGoingToSleepDefaultDisplay = true;
+
+ // In case startedGoingToSleep is called after screenTurnedOff (the source caller is in
+ // order but the methods run on different threads) and updateScreenOffSleepToken was
+ // skipped. Then acquire sleep token if screen was off.
+ if (!mDefaultDisplayPolicy.isScreenOnFully() && !mDefaultDisplayPolicy.isScreenOnEarly()
+ && com.android.window.flags.Flags.skipSleepingWhenSwitchingDisplay()) {
+ updateScreenOffSleepToken(true /* acquire */, false /* isSwappingDisplay */);
+ }
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
@@ -5493,6 +5510,7 @@
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
mRequestedOrSleepingDefaultDisplay = false;
+ mIsGoingToSleepDefaultDisplay = false;
mDefaultDisplayPolicy.setAwake(false);
// We must get this work done here because the power manager will drop
@@ -5528,7 +5546,7 @@
}
EventLogTags.writeScreenToggled(1);
-
+ mIsGoingToSleepDefaultDisplay = false;
mDefaultDisplayPolicy.setAwake(true);
// Since goToSleep performs these functions synchronously, we must
@@ -5630,7 +5648,10 @@
if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off...");
if (displayId == DEFAULT_DISPLAY) {
- updateScreenOffSleepToken(true, isSwappingDisplay);
+ if (!isSwappingDisplay || mIsGoingToSleepDefaultDisplay
+ || !com.android.window.flags.Flags.skipSleepingWhenSwitchingDisplay()) {
+ updateScreenOffSleepToken(true /* acquire */, isSwappingDisplay);
+ }
mRequestedOrSleepingDefaultDisplay = false;
mDefaultDisplayPolicy.screenTurnedOff();
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/power/hint/Android.bp b/services/core/java/com/android/server/power/hint/Android.bp
new file mode 100644
index 0000000..8a98de6
--- /dev/null
+++ b/services/core/java/com/android/server/power/hint/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+ name: "power_hint_flags",
+ package: "com.android.server.power.hint",
+ srcs: [
+ "flags.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "power_hint_flags_lib",
+ aconfig_declarations: "power_hint_flags",
+}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index aa1a41e..3f1b1c1 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.power.hint;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.power.hint.Flags.powerhintThreadCleanup;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -26,9 +27,12 @@
import android.content.Context;
import android.hardware.power.WorkDuration;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IHintManager;
import android.os.IHintSession;
+import android.os.Looper;
+import android.os.Message;
import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
@@ -36,6 +40,8 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.Slog;
import android.util.SparseIntArray;
import android.util.StatsEvent;
@@ -46,20 +52,31 @@
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.utils.Slogf;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
/** An hint service implementation that runs in System Server process. */
public final class HintManagerService extends SystemService {
private static final String TAG = "HintManagerService";
private static final boolean DEBUG = false;
+
+ private static final int EVENT_CLEAN_UP_UID = 3;
+ @VisibleForTesting static final int CLEAN_UP_UID_DELAY_MILLIS = 1000;
+
+
@VisibleForTesting final long mHintSessionPreferredRate;
// Multi-level map storing all active AppHintSessions.
@@ -73,9 +90,15 @@
/** Lock to protect HAL handles and listen list. */
private final Object mLock = new Object();
+ @GuardedBy("mNonIsolatedTidsLock")
+ private final Map<Integer, Set<Long>> mNonIsolatedTids;
+
+ private final Object mNonIsolatedTidsLock = new Object();
+
@VisibleForTesting final MyUidObserver mUidObserver;
private final NativeWrapper mNativeWrapper;
+ private final CleanUpHandler mCleanUpHandler;
private final ActivityManagerInternal mAmInternal;
@@ -94,6 +117,13 @@
HintManagerService(Context context, Injector injector) {
super(context);
mContext = context;
+ if (powerhintThreadCleanup()) {
+ mCleanUpHandler = new CleanUpHandler(createCleanUpThread().getLooper());
+ mNonIsolatedTids = new HashMap<>();
+ } else {
+ mCleanUpHandler = null;
+ mNonIsolatedTids = null;
+ }
mActiveSessions = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
mNativeWrapper.halInit();
@@ -103,6 +133,13 @@
LocalServices.getService(ActivityManagerInternal.class));
}
+ private ServiceThread createCleanUpThread() {
+ final ServiceThread handlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_LOWEST, true /*allowIo*/);
+ handlerThread.start();
+ return handlerThread;
+ }
+
@VisibleForTesting
static class Injector {
NativeWrapper createNativeWrapper() {
@@ -306,7 +343,18 @@
public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
FgThread.getHandler().post(() -> {
synchronized (mCacheLock) {
- mProcStatesCache.put(uid, procState);
+ if (powerhintThreadCleanup()) {
+ final boolean before = isUidForeground(uid);
+ mProcStatesCache.put(uid, procState);
+ final boolean after = isUidForeground(uid);
+ if (before != after) {
+ final Message msg = mCleanUpHandler.obtainMessage(EVENT_CLEAN_UP_UID,
+ uid);
+ mCleanUpHandler.sendMessageDelayed(msg, CLEAN_UP_UID_DELAY_MILLIS);
+ }
+ } else {
+ mProcStatesCache.put(uid, procState);
+ }
}
boolean shouldAllowUpdate = isUidForeground(uid);
synchronized (mLock) {
@@ -314,9 +362,10 @@
if (tokenMap == null) {
return;
}
- for (ArraySet<AppHintSession> sessionSet : tokenMap.values()) {
- for (AppHintSession s : sessionSet) {
- s.onProcStateChanged(shouldAllowUpdate);
+ for (int i = tokenMap.size() - 1; i >= 0; i--) {
+ final ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(i);
+ for (int j = sessionSet.size() - 1; j >= 0; j--) {
+ sessionSet.valueAt(j).onProcStateChanged(shouldAllowUpdate);
}
}
}
@@ -324,52 +373,237 @@
}
}
+ final class CleanUpHandler extends Handler {
+ // status of processed tid used for caching
+ private static final int TID_NOT_CHECKED = 0;
+ private static final int TID_PASSED_CHECK = 1;
+ private static final int TID_EXITED = 2;
+
+ CleanUpHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == EVENT_CLEAN_UP_UID) {
+ if (hasEqualMessages(msg.what, msg.obj)) {
+ removeEqualMessages(msg.what, msg.obj);
+ final Message newMsg = obtainMessage(msg.what, msg.obj);
+ sendMessageDelayed(newMsg, CLEAN_UP_UID_DELAY_MILLIS);
+ return;
+ }
+ final int uid = (int) msg.obj;
+ boolean isForeground = mUidObserver.isUidForeground(uid);
+ // store all sessions in a list and release the global lock
+ // we don't need to worry about stale data or racing as the session is synchronized
+ // itself and will perform its own closed status check in setThreads call
+ final List<AppHintSession> sessions;
+ synchronized (mLock) {
+ final ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
+ mActiveSessions.get(uid);
+ if (tokenMap == null || tokenMap.isEmpty()) {
+ return;
+ }
+ sessions = new ArrayList<>(tokenMap.size());
+ for (int i = tokenMap.size() - 1; i >= 0; i--) {
+ final ArraySet<AppHintSession> set = tokenMap.valueAt(i);
+ for (int j = set.size() - 1; j >= 0; j--) {
+ sessions.add(set.valueAt(j));
+ }
+ }
+ }
+ final long[] durationList = new long[sessions.size()];
+ final int[] invalidTidCntList = new int[sessions.size()];
+ final SparseIntArray checkedTids = new SparseIntArray();
+ int[] totalTidCnt = new int[1];
+ for (int i = sessions.size() - 1; i >= 0; i--) {
+ final AppHintSession session = sessions.get(i);
+ final long start = System.nanoTime();
+ try {
+ final int invalidCnt = cleanUpSession(session, checkedTids, totalTidCnt);
+ final long elapsed = System.nanoTime() - start;
+ invalidTidCntList[i] = invalidCnt;
+ durationList[i] = elapsed;
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to clean up session " + session.mHalSessionPtr
+ + " for UID " + session.mUid);
+ }
+ }
+ logCleanUpMetrics(uid, invalidTidCntList, durationList, sessions.size(),
+ totalTidCnt[0], isForeground);
+ }
+ }
+
+ private void logCleanUpMetrics(int uid, int[] count, long[] durationNsList, int sessionCnt,
+ int totalTidCnt, boolean isForeground) {
+ int maxInvalidTidCnt = Integer.MIN_VALUE;
+ int totalInvalidTidCnt = 0;
+ for (int i = 0; i < count.length; i++) {
+ totalInvalidTidCnt += count[i];
+ maxInvalidTidCnt = Math.max(maxInvalidTidCnt, count[i]);
+ }
+ if (DEBUG || totalInvalidTidCnt > 0) {
+ Arrays.sort(durationNsList);
+ long totalDurationNs = 0;
+ for (int i = 0; i < durationNsList.length; i++) {
+ totalDurationNs += durationNsList[i];
+ }
+ int totalDurationUs = (int) TimeUnit.NANOSECONDS.toMicros(totalDurationNs);
+ int maxDurationUs = (int) TimeUnit.NANOSECONDS.toMicros(
+ durationNsList[durationNsList.length - 1]);
+ int minDurationUs = (int) TimeUnit.NANOSECONDS.toMicros(durationNsList[0]);
+ int avgDurationUs = (int) TimeUnit.NANOSECONDS.toMicros(
+ totalDurationNs / durationNsList.length);
+ int th90DurationUs = (int) TimeUnit.NANOSECONDS.toMicros(
+ durationNsList[(int) (durationNsList.length * 0.9)]);
+ Slog.d(TAG,
+ "Invalid tid found for UID" + uid + " in " + totalDurationUs + "us:\n\t"
+ + "count("
+ + " session: " + sessionCnt
+ + " totalTid: " + totalTidCnt
+ + " maxInvalidTid: " + maxInvalidTidCnt
+ + " totalInvalidTid: " + totalInvalidTidCnt + ")\n\t"
+ + "time per session("
+ + " min: " + minDurationUs + "us"
+ + " max: " + maxDurationUs + "us"
+ + " avg: " + avgDurationUs + "us"
+ + " 90%: " + th90DurationUs + "us" + ")\n\t"
+ + "isForeground: " + isForeground);
+ }
+ }
+
+ // This will check if each TID currently linked to the session still exists. If it's
+ // previously registered as not an isolated process, then it will run tkill(pid, tid, 0) to
+ // verify that it's still running under the same pid. Otherwise, it will run
+ // kill(tid, 0) to only check if it exists. The result will be cached in checkedTids
+ // map with tid as the key and checked status as value.
+ public int cleanUpSession(AppHintSession session, SparseIntArray checkedTids, int[] total) {
+ if (session.isClosed()) {
+ return 0;
+ }
+ final int pid = session.mPid;
+ final int[] tids = session.getTidsInternal();
+ if (total != null && total.length == 1) {
+ total[0] += tids.length;
+ }
+ final IntArray filtered = new IntArray(tids.length);
+ for (int i = 0; i < tids.length; i++) {
+ int tid = tids[i];
+ if (checkedTids.get(tid, 0) != TID_NOT_CHECKED) {
+ if (checkedTids.get(tid) == TID_PASSED_CHECK) {
+ filtered.add(tid);
+ }
+ continue;
+ }
+ // if it was registered as a non-isolated then we perform more restricted check
+ final boolean isNotIsolated;
+ synchronized (mNonIsolatedTidsLock) {
+ isNotIsolated = mNonIsolatedTids.containsKey(tid);
+ }
+ try {
+ if (isNotIsolated) {
+ Process.checkTid(pid, tid);
+ } else {
+ Process.checkPid(tid);
+ }
+ checkedTids.put(tid, TID_PASSED_CHECK);
+ filtered.add(tid);
+ } catch (NoSuchElementException e) {
+ checkedTids.put(tid, TID_EXITED);
+ } catch (Exception e) {
+ Slog.w(TAG, "Unexpected exception when checking TID " + tid + " under PID "
+ + pid + "(isolated: " + !isNotIsolated + ")", e);
+ // if anything unexpected happens then we keep it, but don't store it as checked
+ filtered.add(tid);
+ }
+ }
+ final int diff = tids.length - filtered.size();
+ if (diff > 0) {
+ synchronized (session) {
+ // in case thread list is updated during the cleanup then we skip updating
+ // the session but just return the number for reporting purpose
+ final int[] newTids = session.getTidsInternal();
+ if (newTids.length != tids.length) {
+ Slog.d(TAG, "Skipped cleaning up the session as new tids are added");
+ return diff;
+ }
+ Arrays.sort(newTids);
+ Arrays.sort(tids);
+ if (!Arrays.equals(newTids, tids)) {
+ Slog.d(TAG, "Skipped cleaning up the session as new tids are updated");
+ return diff;
+ }
+ Slog.d(TAG, "Cleaned up " + diff + " invalid tids for session "
+ + session.mHalSessionPtr + " with UID " + session.mUid + "\n\t"
+ + "before: " + Arrays.toString(tids) + "\n\t"
+ + "after: " + filtered);
+ final int[] filteredTids = filtered.toArray();
+ if (filteredTids.length == 0) {
+ session.mShouldForcePause = true;
+ if (session.mUpdateAllowed) {
+ session.pause();
+ }
+ } else {
+ session.setThreadsInternal(filteredTids, false);
+ }
+ }
+ }
+ return diff;
+ }
+ }
+
@VisibleForTesting
IHintManager.Stub getBinderServiceInstance() {
return mService;
}
// returns the first invalid tid or null if not found
- private Integer checkTidValid(int uid, int tgid, int [] tids) {
+ private Integer checkTidValid(int uid, int tgid, int [] tids, IntArray nonIsolated) {
// Make sure all tids belongs to the same UID (including isolated UID),
// tids can belong to different application processes.
List<Integer> isolatedPids = null;
- for (int threadId : tids) {
+ for (int i = 0; i < tids.length; i++) {
+ int tid = tids[i];
final String[] procStatusKeys = new String[] {
"Uid:",
"Tgid:"
};
long[] output = new long[procStatusKeys.length];
- Process.readProcLines("/proc/" + threadId + "/status", procStatusKeys, output);
+ Process.readProcLines("/proc/" + tid + "/status", procStatusKeys, output);
int uidOfThreadId = (int) output[0];
int pidOfThreadId = (int) output[1];
- // use PID check for isolated processes, use UID check for non-isolated processes.
- if (pidOfThreadId == tgid || uidOfThreadId == uid) {
+ // use PID check for non-isolated processes
+ if (nonIsolated != null && pidOfThreadId == tgid) {
+ nonIsolated.add(tid);
+ continue;
+ }
+ // use UID check for isolated processes.
+ if (uidOfThreadId == uid) {
continue;
}
// Only call into AM if the tid is either isolated or invalid
if (isolatedPids == null) {
// To avoid deadlock, do not call into AMS if the call is from system.
if (uid == Process.SYSTEM_UID) {
- return threadId;
+ return tid;
}
isolatedPids = mAmInternal.getIsolatedProcesses(uid);
if (isolatedPids == null) {
- return threadId;
+ return tid;
}
}
if (isolatedPids.contains(pidOfThreadId)) {
continue;
}
- return threadId;
+ return tid;
}
return null;
}
private String formatTidCheckErrMsg(int callingUid, int[] tids, Integer invalidTid) {
return "Tid" + invalidTid + " from list " + Arrays.toString(tids)
- + " doesn't belong to the calling application" + callingUid;
+ + " doesn't belong to the calling application " + callingUid;
}
@VisibleForTesting
@@ -387,7 +621,10 @@
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
try {
- final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids);
+ final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray(tids.length)
+ : null;
+ final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids,
+ nonIsolated);
if (invalidTid != null) {
final String errMsg = formatTidCheckErrMsg(callingUid, tids, invalidTid);
Slogf.w(TAG, errMsg);
@@ -396,6 +633,14 @@
long halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid, callingUid,
tids, durationNanos);
+ if (powerhintThreadCleanup()) {
+ synchronized (mNonIsolatedTidsLock) {
+ for (int i = nonIsolated.size() - 1; i >= 0; i--) {
+ mNonIsolatedTids.putIfAbsent(nonIsolated.get(i), new ArraySet<>());
+ mNonIsolatedTids.get(nonIsolated.get(i)).add(halSessionPtr);
+ }
+ }
+ }
if (halSessionPtr == 0) {
return null;
}
@@ -482,6 +727,7 @@
protected boolean mUpdateAllowed;
protected int[] mNewThreadIds;
protected boolean mPowerEfficient;
+ protected boolean mShouldForcePause;
private enum SessionModes {
POWER_EFFICIENCY,
@@ -498,6 +744,7 @@
mTargetDurationNanos = durationNanos;
mUpdateAllowed = true;
mPowerEfficient = false;
+ mShouldForcePause = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
updateHintAllowed(allowed);
try {
@@ -511,7 +758,7 @@
@VisibleForTesting
boolean updateHintAllowed(boolean allowed) {
synchronized (this) {
- if (allowed && !mUpdateAllowed) resume();
+ if (allowed && !mUpdateAllowed && !mShouldForcePause) resume();
if (!allowed && mUpdateAllowed) pause();
mUpdateAllowed = allowed;
return mUpdateAllowed;
@@ -521,7 +768,7 @@
@Override
public void updateTargetWorkDuration(long targetDurationNanos) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed) {
+ if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
return;
}
Preconditions.checkArgument(targetDurationNanos > 0, "Expected"
@@ -534,7 +781,7 @@
@Override
public void reportActualWorkDuration(long[] actualDurationNanos, long[] timeStampNanos) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed) {
+ if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
return;
}
Preconditions.checkArgument(actualDurationNanos.length != 0, "the count"
@@ -581,12 +828,25 @@
if (sessionSet.isEmpty()) tokenMap.remove(mToken);
if (tokenMap.isEmpty()) mActiveSessions.remove(mUid);
}
+ if (powerhintThreadCleanup()) {
+ synchronized (mNonIsolatedTidsLock) {
+ final int[] tids = getTidsInternal();
+ for (int tid : tids) {
+ if (mNonIsolatedTids.containsKey(tid)) {
+ mNonIsolatedTids.get(tid).remove(mHalSessionPtr);
+ if (mNonIsolatedTids.get(tid).isEmpty()) {
+ mNonIsolatedTids.remove(tid);
+ }
+ }
+ }
+ }
+ }
}
@Override
public void sendHint(@PerformanceHintManager.Session.Hint int hint) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed) {
+ if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
return;
}
Preconditions.checkArgument(hint >= 0, "the hint ID value should be"
@@ -596,33 +856,60 @@
}
public void setThreads(@NonNull int[] tids) {
+ setThreadsInternal(tids, true);
+ }
+
+ private void setThreadsInternal(int[] tids, boolean checkTid) {
+ if (tids.length == 0) {
+ throw new IllegalArgumentException("Thread id list can't be empty.");
+ }
+
synchronized (this) {
if (mHalSessionPtr == 0) {
return;
}
- if (tids.length == 0) {
- throw new IllegalArgumentException("Thread id list can't be empty.");
- }
- final int callingUid = Binder.getCallingUid();
- final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
- final long identity = Binder.clearCallingIdentity();
- try {
- final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids);
- if (invalidTid != null) {
- final String errMsg = formatTidCheckErrMsg(callingUid, tids, invalidTid);
- Slogf.w(TAG, errMsg);
- throw new SecurityException(errMsg);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
if (!mUpdateAllowed) {
Slogf.v(TAG, "update hint not allowed, storing tids.");
mNewThreadIds = tids;
+ mShouldForcePause = false;
return;
}
+ if (checkTid) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
+ final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray() : null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids,
+ nonIsolated);
+ if (invalidTid != null) {
+ final String errMsg = formatTidCheckErrMsg(callingUid, tids,
+ invalidTid);
+ Slogf.w(TAG, errMsg);
+ throw new SecurityException(errMsg);
+ }
+ if (powerhintThreadCleanup()) {
+ synchronized (mNonIsolatedTidsLock) {
+ for (int i = nonIsolated.size() - 1; i >= 0; i--) {
+ mNonIsolatedTids.putIfAbsent(nonIsolated.get(i),
+ new ArraySet<>());
+ mNonIsolatedTids.get(nonIsolated.get(i)).add(mHalSessionPtr);
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
mNativeWrapper.halSetThreads(mHalSessionPtr, tids);
mThreadIds = tids;
+ mNewThreadIds = null;
+ // if the update is allowed but the session is force paused by tid clean up, then
+ // it's waiting for this tid update to resume
+ if (mShouldForcePause) {
+ resume();
+ mShouldForcePause = false;
+ }
}
}
@@ -632,10 +919,24 @@
}
}
+ @VisibleForTesting
+ int[] getTidsInternal() {
+ synchronized (this) {
+ return mNewThreadIds != null ? Arrays.copyOf(mNewThreadIds, mNewThreadIds.length)
+ : Arrays.copyOf(mThreadIds, mThreadIds.length);
+ }
+ }
+
+ boolean isClosed() {
+ synchronized (this) {
+ return mHalSessionPtr == 0;
+ }
+ }
+
@Override
public void setMode(int mode, boolean enabled) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed) {
+ if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
return;
}
Preconditions.checkArgument(mode >= 0, "the mode Id value should be"
@@ -650,13 +951,13 @@
@Override
public void reportActualWorkDuration2(WorkDuration[] workDurations) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed) {
+ if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
return;
}
Preconditions.checkArgument(workDurations.length != 0, "the count"
+ " of work durations shouldn't be 0.");
- for (WorkDuration workDuration : workDurations) {
- validateWorkDuration(workDuration);
+ for (int i = 0; i < workDurations.length; i++) {
+ validateWorkDuration(workDurations[i]);
}
mNativeWrapper.halReportActualWorkDuration(mHalSessionPtr, workDurations);
}
@@ -743,6 +1044,7 @@
pw.println(prefix + "SessionTIDs: " + Arrays.toString(mThreadIds));
pw.println(prefix + "SessionTargetDurationNanos: " + mTargetDurationNanos);
pw.println(prefix + "SessionAllowed: " + mUpdateAllowed);
+ pw.println(prefix + "SessionForcePaused: " + mShouldForcePause);
pw.println(prefix + "PowerEfficient: " + (mPowerEfficient ? "true" : "false"));
}
}
diff --git a/services/core/java/com/android/server/power/hint/flags.aconfig b/services/core/java/com/android/server/power/hint/flags.aconfig
new file mode 100644
index 0000000..f4afcb1
--- /dev/null
+++ b/services/core/java/com/android/server/power/hint/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.power.hint"
+
+flag {
+ name: "powerhint_thread_cleanup"
+ namespace: "game"
+ description: "Feature flag for auto PowerHintSession dead thread cleanup"
+ bug: "296160319"
+}
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index b2e01c5..c42ccea 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "power_monitor_api"
+ is_exported: true
namespace: "backstage_power"
description: "Feature flag for ODPM API"
bug: "295027807"
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index f7c236a..2ff3861 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -267,7 +267,7 @@
void removeQsTile(ComponentName tile);
/**
- * Called when requested to enter desktop from an app.
+ * Called when requested to enter desktop from a focused app.
*/
- void enterDesktop(int displayId);
+ void moveFocusedTaskToDesktop(int displayId);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7b3e237..cca5beb 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -838,15 +838,17 @@
} catch (RemoteException ex) { }
}
}
+
@Override
- public void enterDesktop(int displayId) {
+ public void moveFocusedTaskToDesktop(int displayId) {
IStatusBar bar = mBar;
if (bar != null) {
try {
- bar.enterDesktop(displayId);
+ bar.moveFocusedTaskToDesktop(displayId);
} catch (RemoteException ex) { }
}
}
+
@Override
public void showMediaOutputSwitcher(String packageName) {
IStatusBar bar = mBar;
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index a25d67a..f3d7dd1 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -24,8 +24,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ConnectivityManager;
import android.net.IpSecTransformState;
import android.net.Network;
+import android.net.vcn.Flags;
import android.net.vcn.VcnManager;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -71,6 +73,7 @@
@NonNull private final Handler mHandler;
@NonNull private final PowerManager mPowerManager;
+ @NonNull private final ConnectivityManager mConnectivityManager;
@NonNull private final Object mCancellationToken = new Object();
@NonNull private final PacketLossCalculator mPacketLossCalculator;
@@ -98,6 +101,8 @@
mHandler = new Handler(getVcnContext().getLooper());
mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class);
+ mConnectivityManager =
+ getVcnContext().getContext().getSystemService(ConnectivityManager.class);
mPacketLossCalculator = deps.getPacketLossCalculator();
@@ -313,6 +318,13 @@
} else {
logInfo(logMsg);
onValidationResultReceivedInternal(true /* isFailed */);
+
+ if (Flags.validateNetworkOnIpsecLoss()) {
+ // Trigger re-validation of the underlying network; if it fails, the VCN will
+ // attempt to migrate away.
+ mConnectivityManager.reportNetworkConnectivity(
+ getNetwork(), false /* hasConnectivity */);
+ }
}
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index 1704aa1..4bacf3b 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -203,6 +203,11 @@
return mVcnContext;
}
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
// Override methods for AutoCloseable. Subclasses MUST call super when overriding this method
@Override
public void close() {
diff --git a/services/core/java/com/android/server/webkit/flags.aconfig b/services/core/java/com/android/server/webkit/flags.aconfig
index 1411acc..2afbcd6 100644
--- a/services/core/java/com/android/server/webkit/flags.aconfig
+++ b/services/core/java/com/android/server/webkit/flags.aconfig
@@ -2,6 +2,7 @@
flag {
name: "update_service_v2"
+ is_exported: true
namespace: "webview"
description: "Using a new version of the WebView update service"
bug: "308907090"
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 4189988..3f041cb 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -961,16 +961,37 @@
populateTransformationMatrix(windowState, matrix);
Region touchableRegion = mTempRegion3;
windowState.getTouchableRegion(touchableRegion);
- Rect touchableFrame = mTempRect1;
- touchableRegion.getBounds(touchableFrame);
- RectF windowFrame = mTempRectF;
- windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.getFrame().left,
- -windowState.getFrame().top);
- matrix.mapRect(windowFrame);
Region windowBounds = mTempRegion2;
- windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom);
+ if (Flags.useWindowOriginalTouchableRegionWhenMagnificationRecomputeBounds()) {
+ // For b/323366243, if using the bounds from touchableRegion.getBounds, in
+ // non-magnifiable windowBounds computation, part of the non-touchableRegion
+ // may be included into nonMagnifiedBounds. This will make users lose
+ // the magnification control on mis-included areas.
+ // Therefore, to prevent the above issue, we change to use the window exact
+ // touchableRegion in magnificationRegion computation.
+ // Like the original approach, the touchableRegion is in non-magnified display
+ // space, so first we need to offset the region by the windowFrames bounds, then
+ // apply the transform matrix to the region to get the exact region in magnified
+ // display space.
+ // TODO: For a long-term plan, since touchable regions provided by WindowState
+ // doesn't actually reflect the real touchable regions on display, we should
+ // delete the WindowState dependency and migrate to use the touchableRegion
+ // from WindowInfoListener data. (b/330653961)
+ touchableRegion.translate(-windowState.getFrame().left,
+ -windowState.getFrame().top);
+ applyMatrixToRegion(matrix, touchableRegion);
+ windowBounds.set(touchableRegion);
+ } else {
+ Rect touchableFrame = mTempRect1;
+ touchableRegion.getBounds(touchableFrame);
+ RectF windowFrame = mTempRectF;
+ windowFrame.set(touchableFrame);
+ windowFrame.offset(-windowState.getFrame().left,
+ -windowState.getFrame().top);
+ matrix.mapRect(windowFrame);
+ windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
+ (int) windowFrame.right, (int) windowFrame.bottom);
+ }
// Only update new regions
Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
@@ -1066,6 +1087,30 @@
|| windowType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
}
+ private void applyMatrixToRegion(Matrix matrix, Region region) {
+ // Since Matrix does not support mapRegion api, so we follow the Matrix#mapRect logic
+ // to apply the matrix to the given region.
+ // In Matrix#mapRect, the internal calculation is applying the transform matrix to
+ // rect's 4 corner points with the below calculation. (see SkMatrix::mapPoints)
+ // |A B C| |x| Ax+By+C Dx+Ey+F
+ // |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+ // |G H I| |1| Gx+Hy+I Gx+Hy+I
+ // For magnification usage, the matrix is created from
+ // WindowState#getTransformationMatrix. We can simplify the matrix calculation to be
+ // |scale 0 trans_x| |x|
+ // | 0 scale trans_y| |y| = (scale*x + trans_x, scale*y + trans_y)
+ // | 0 0 1 | |1|
+ // So, to follow the simplified matrix computation, we first scale the region with
+ // matrix.scale, then translate the region with matrix.trans_x and matrix.trans_y.
+ float[] transformArray = sTempFloats;
+ matrix.getValues(transformArray);
+ // For magnification transform matrix, the scale_x and scale_y are equal.
+ region.scale(transformArray[Matrix.MSCALE_X]);
+ region.translate(
+ (int) transformArray[Matrix.MTRANS_X],
+ (int) transformArray[Matrix.MTRANS_Y]);
+ }
+
private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) {
mTempLayer = 0;
mDisplayContent.forAllWindows((w) -> {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 59a56de..19f3449 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -149,6 +149,10 @@
private static final int WINDOW_STATE_MULTI_WINDOW = 4;
private static final int WINDOW_STATE_INVALID = -1;
+ // These should match AppStartOccurred.MultiWindowLaunchType in the atoms.proto
+ private static final int MULTI_WINDOW_LAUNCH_TYPE_UNSPECIFIED = 0;
+ private static final int MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR = 1;
+
/**
* If a launching activity isn't visible within this duration when the device is sleeping, e.g.
* keyguard is locked, its transition info will be dropped.
@@ -329,6 +333,8 @@
@Nullable Runnable mPendingFullyDrawn;
/** Non-null if the trace is active. */
@Nullable String mLaunchTraceName;
+ /** Whether this transition info is for an activity that is a part of multi-window. */
+ int mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_UNSPECIFIED;
/** @return Non-null if there will be a window drawn event for the launch. */
@Nullable
@@ -477,6 +483,7 @@
final int activityRecordIdHashCode;
final boolean relaunched;
final long timestampNs;
+ final int multiWindowLaunchType;
private TransitionInfoSnapshot(TransitionInfo info) {
this(info, info.mLastLaunchedActivity, INVALID_DELAY);
@@ -507,6 +514,7 @@
this.windowsFullyDrawnDelayMs = windowsFullyDrawnDelayMs;
relaunched = info.mRelaunched;
timestampNs = info.mLaunchingState.mStartRealtimeNs;
+ multiWindowLaunchType = info.mMultiWindowLaunchType;
}
@WaitResult.LaunchState int getLaunchState() {
@@ -744,6 +752,10 @@
return;
}
+ // Look at all other transition infos and mark them as a split pair if they belong to
+ // adjacent tasks
+ updateSplitPairLaunches(newInfo);
+
if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
// A new launch sequence has begun. Start tracking it.
mTransitionInfoList.add(newInfo);
@@ -769,6 +781,36 @@
}
}
+ /**
+ * Updates all transition infos including the given {@param info} if they are a part of a
+ * split pair launch.
+ */
+ private void updateSplitPairLaunches(@NonNull TransitionInfo info) {
+ final Task launchedActivityTask = info.mLastLaunchedActivity.getTask();
+ final Task adjacentToLaunchedTask = launchedActivityTask.getAdjacentTask();
+ if (adjacentToLaunchedTask == null) {
+ // Not a part of a split pair
+ return;
+ }
+ for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+ final TransitionInfo otherInfo = mTransitionInfoList.get(i);
+ if (otherInfo == info) {
+ continue;
+ }
+ final Task otherTask = otherInfo.mLastLaunchedActivity.getTask();
+ // The adjacent task is the split root in which activities are started
+ if (otherTask.isDescendantOf(adjacentToLaunchedTask)) {
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, "Found adjacent tasks t1=" + launchedActivityTask.mTaskId
+ + " t2=" + otherTask.mTaskId);
+ }
+ // These tasks are adjacent, so mark them as such
+ info.mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR;
+ otherInfo.mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR;
+ }
+ }
+ }
+
private void scheduleCheckActivityToBeDrawnIfSleeping(@NonNull ActivityRecord r) {
if (r.mDisplayContent.isSleeping()) {
// It is unknown whether the activity can be drawn or not, e.g. it depends on the
@@ -1168,7 +1210,8 @@
packageState,
false, // is_xr_activity
firstLaunch,
- 0L /* TODO: stoppedDuration */);
+ 0L /* TODO: stoppedDuration */,
+ info.multiWindowLaunchType);
// Reset the stopped state to avoid reporting stopped again
if (info.processRecord != null) {
info.processRecord.setWasStoppedLogged(true);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 060f1c8..6af496f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5682,29 +5682,6 @@
throw e;
}
- /**
- * Sets the corresponding {@link DisplayArea} information for the process global
- * configuration. To be called when we need to show IME on a different {@link DisplayArea}
- * or display.
- *
- * @param pid The process id associated with the IME window.
- * @param imeContainer The DisplayArea that contains the IME window.
- */
- void onImeWindowSetOnDisplayArea(final int pid, @NonNull final DisplayArea imeContainer) {
- if (pid == MY_PID || pid < 0) {
- ProtoLog.w(WM_DEBUG_CONFIGURATION,
- "Trying to update display configuration for system/invalid process.");
- return;
- }
- final WindowProcessController process = mProcessMap.getProcess(pid);
- if (process == null) {
- ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
- + "configuration for invalid process, pid=%d", pid);
- return;
- }
- process.registerDisplayAreaConfigurationListener(imeContainer);
- }
-
@Override
public void setRunningRemoteTransitionDelegate(IApplicationThread delegate) {
final TransitionController controller = getTransitionController();
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 48d78f5..7144445 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -422,7 +422,6 @@
// Searching previous
final ActivityRecord prevActivity = currentTask.getActivity((below) -> !below.finishing,
currentActivity, false /*includeBoundary*/, true /*traverseTopToBottom*/);
-
final TaskFragment currTF = currentActivity.getTaskFragment();
if (currTF != null && currTF.asTask() == null) {
// The currentActivity is embedded, search for the candidate previous activities.
@@ -431,13 +430,34 @@
outPrevActivities.add(prevActivity);
return true;
}
- if (currTF.getAdjacentTaskFragment() != null) {
- // The two TFs are adjacent (visually displayed side-by-side), search if any
- // activity below the lowest one
- // If companion, those two TF will be closed together.
- if (currTF.getCompanionTaskFragment() != null) {
+ if (currTF.getAdjacentTaskFragment() == null) {
+ final TaskFragment nextTF = findNextTaskFragment(currentTask, currTF);
+ if (isSecondCompanionToFirst(currTF, nextTF)) {
+ // TF is isStacked, search bottom activity from companion TF.
+ //
+ // Sample hierarchy: search for underPrevious if any.
+ // Current TF
+ // Companion TF (bottomActivityInCompanion)
+ // Bottom Activity not inside companion TF (underPrevious)
+ // find bottom activity in Companion TF.
+ final ActivityRecord bottomActivityInCompanion = nextTF.getActivity(
+ (below) -> !below.finishing, false /* traverseTopToBottom */);
+ final ActivityRecord underPrevious = currentTask.getActivity(
+ (below) -> !below.finishing, bottomActivityInCompanion,
+ false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ if (underPrevious != null) {
+ outPrevActivities.add(underPrevious);
+ addPreviousAdjacentActivityIfExist(underPrevious, outPrevActivities);
+ }
+ return true;
+ }
+ } else {
+ // If adjacent TF has companion to current TF, those two TF will be closed together.
+ final TaskFragment adjacentTF = currTF.getAdjacentTaskFragment();
+ if (isSecondCompanionToFirst(currTF, adjacentTF)) {
+ // The two TFs are adjacent (visually displayed side-by-side), search if any
+ // activity below the lowest one.
final WindowContainer commonParent = currTF.getParent();
- final TaskFragment adjacentTF = currTF.getAdjacentTaskFragment();
final TaskFragment lowerTF = commonParent.mChildren.indexOf(currTF)
< commonParent.mChildren.indexOf(adjacentTF)
? currTF : adjacentTF;
@@ -451,25 +471,6 @@
// Unable to predict if no companion, it can only close current activity and make
// prev Activity full screened.
return false;
- } else if (currTF.getCompanionTaskFragment() != null) {
- // TF is isStacked, search bottom activity from companion TF.
- //
- // Sample hierarchy: search for underPrevious if any.
- // Current TF
- // Companion TF (bottomActivityInCompanion)
- // Bottom Activity not inside companion TF (underPrevious)
- final TaskFragment companionTF = currTF.getCompanionTaskFragment();
- // find bottom activity in Companion TF.
- final ActivityRecord bottomActivityInCompanion = companionTF.getActivity(
- (below) -> !below.finishing, false /* traverseTopToBottom */);
- final ActivityRecord underPrevious = currentTask.getActivity(
- (below) -> !below.finishing, bottomActivityInCompanion,
- false /*includeBoundary*/, true /*traverseTopToBottom*/);
- if (underPrevious != null) {
- outPrevActivities.add(underPrevious);
- addPreviousAdjacentActivityIfExist(underPrevious, outPrevActivities);
- }
- return true;
}
}
@@ -484,6 +485,24 @@
return true;
}
+ private static TaskFragment findNextTaskFragment(@NonNull Task currentTask,
+ @NonNull TaskFragment topTF) {
+ final int topIndex = currentTask.mChildren.indexOf(topTF);
+ if (topIndex <= 0) {
+ return null;
+ }
+ final WindowContainer next = currentTask.mChildren.get(topIndex - 1);
+ return next.asTaskFragment();
+ }
+
+ /**
+ * Whether the second TF has set companion to first TF.
+ * When set, the second TF will be removed by organizer if the first TF is removed.
+ */
+ private static boolean isSecondCompanionToFirst(TaskFragment first, TaskFragment second) {
+ return second != null && second.getCompanionTaskFragment() == first;
+ }
+
private static void addPreviousAdjacentActivityIfExist(@NonNull ActivityRecord prevActivity,
@NonNull ArrayList<ActivityRecord> outPrevActivities) {
final TaskFragment prevTF = prevActivity.getTaskFragment();
@@ -748,6 +767,10 @@
if (!isMonitoringTransition() || targets.isEmpty()) {
return;
}
+ if (mAnimationHandler.hasTargetDetached()) {
+ mNavigationMonitor.cancelBackNavigating("targetDetached");
+ return;
+ }
for (int i = targets.size() - 1; i >= 0; --i) {
final WindowContainer wc = targets.get(i).mContainer;
if (wc.asActivityRecord() == null && wc.asTask() == null
@@ -1122,6 +1145,21 @@
|| containTarget(openApps, false /* open */));
}
+ /**
+ * Check if any animation target is detached, possibly due to app crash.
+ */
+ boolean hasTargetDetached() {
+ if (!mComposed) {
+ return false;
+ }
+ for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) {
+ if (!mOpenAnimAdaptor.mAdaptors[i].mTarget.isAttached()) {
+ return true;
+ }
+ }
+ return !mCloseAdaptor.mTarget.isAttached();
+ }
+
@Override
public String toString() {
return "AnimationTargets{"
@@ -1659,6 +1697,10 @@
}
private static void restoreLaunchBehind(@NonNull ActivityRecord activity) {
+ if (!activity.isAttached()) {
+ // The activity was detached from hierarchy.
+ return;
+ }
activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
// Restore the launch-behind state.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eb1f052..fe280cb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4171,11 +4171,6 @@
*/
void setInputMethodWindowLocked(WindowState win) {
mInputMethodWindow = win;
- // Update display configuration for IME process.
- if (mInputMethodWindow != null) {
- final int imePid = mInputMethodWindow.mSession.mPid;
- mAtmService.onImeWindowSetOnDisplayArea(imePid, mImeWindowsContainer);
- }
mInsetsStateController.getImeSourceProvider().setWindowContainer(win,
mDisplayPolicy.getImeSourceFrameProvider(), null);
computeImeTarget(true /* updateImeTarget */);
@@ -5102,7 +5097,9 @@
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- prepareSurfaces();
+ if (!com.android.window.flags.Flags.removePrepareSurfaceInPlacement()) {
+ prepareSurfaces();
+ }
// This should be called after the insets have been dispatched to clients and we have
// committed finish drawing windows.
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index dd77a69..3f24545 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -22,6 +22,7 @@
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -130,6 +131,7 @@
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.server.wm.utils.OptPropFactory;
import com.android.server.wm.utils.OptPropFactory.OptProp;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -350,7 +352,6 @@
isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
mIsOverrideRespectRequestedOrientationEnabled =
isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
-
}
/** Cleans up {@link Letterbox} if it exists.*/
@@ -714,6 +715,25 @@
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
}
+ /**
+ * Whether activity is eligible for camera compatibility free-form treatment.
+ *
+ * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
+ * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
+ * provides changes to the camera and display orientation signals to match those expected on a
+ * portrait device in that orientation (for example, on a standard phone).
+ *
+ * <p>The treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Property gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override.
+ * </ul>
+ */
+ boolean shouldApplyFreeformTreatmentForCameraCompat() {
+ return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
+ OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+ }
+
private boolean isCameraCompatTreatmentActive() {
DisplayContent displayContent = mActivityRecord.mDisplayContent;
if (displayContent == null) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 30134d8..e157318 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -283,14 +283,14 @@
int lastSyncSeqId, ClientWindowFrames outFrames,
MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outSyncSeqIdBundle) {
+ Bundle outBundle) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags, seq,
lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outSyncSeqIdBundle);
+ outActiveControls, outBundle);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4c282bd..18d2718 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6822,8 +6822,8 @@
* A decor surface is requested by a {@link TaskFragmentOrganizer} and is placed below children
* windows in the Task except for own Activities and TaskFragments in fully trusted mode. The
* decor surface is created and shared with the client app with
- * {@link android.window.TaskFragmentOperation#OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE} and
- * be removed with
+ * {@link android.window.TaskFragmentOperation#OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE}
+ * and be removed with
* {@link android.window.TaskFragmentOperation#OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE}.
*
* When boosted with
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 66c2e53..319e2b0 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2468,7 +2468,15 @@
for (WindowContainer<?> p = getAnimatableParent(wc); p != null;
p = getAnimatableParent(p)) {
final ChangeInfo parentChange = changes.get(p);
- if (parentChange == null || !parentChange.hasChanged()) break;
+ if (parentChange == null) {
+ break;
+ }
+ if (!parentChange.hasChanged()) {
+ // In case the target is collected after the parent has been changed, it could
+ // be too late to snapshot the parent change. Skip to see if there is any
+ // parent window further up to be considered as change parent.
+ continue;
+ }
if (p.mRemoteToken == null) {
// Intermediate parents must be those that has window to be managed by Shell.
continue;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2934574..f09ef96 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -154,6 +154,7 @@
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.window.flags.Flags.multiCrop;
+import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.Manifest;
import android.Manifest.permission;
@@ -304,6 +305,7 @@
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.AddToSurfaceSyncGroupResult;
import android.window.ClientWindowFrames;
import android.window.IGlobalDragListener;
@@ -794,6 +796,8 @@
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
private final Uri mImmersiveModeConfirmationsUri =
Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
+ private final Uri mDisableSecureWindowsUri =
+ Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS);
private final Uri mPolicyControlUri =
Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL);
private final Uri mForceDesktopModeOnExternalDisplaysUri = Settings.Global.getUriFor(
@@ -822,6 +826,8 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mImmersiveModeConfirmationsUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mDisableSecureWindowsUri, false, this,
+ UserHandle.USER_ALL);
resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(mForceDesktopModeOnExternalDisplaysUri, false, this,
UserHandle.USER_ALL);
@@ -876,6 +882,11 @@
return;
}
+ if (mDisableSecureWindowsUri.equals(uri)) {
+ updateDisableSecureWindows();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -895,6 +906,7 @@
void loadSettings() {
updateSystemUiSettings(false /* handleChange */);
updateMaximumObscuringOpacityForTouch();
+ updateDisableSecureWindows();
}
void updateMaximumObscuringOpacityForTouch() {
@@ -977,6 +989,28 @@
});
}
}
+
+ void updateDisableSecureWindows() {
+ if (!SystemProperties.getBoolean(SYSTEM_DEBUGGABLE, false)) {
+ return;
+ }
+
+ final boolean disableSecureWindows;
+ try {
+ disableSecureWindows = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.DISABLE_SECURE_WINDOWS, 0) != 0;
+ } catch (Settings.SettingNotFoundException e) {
+ return;
+ }
+ if (mDisableSecureWindows == disableSecureWindows) {
+ return;
+ }
+
+ synchronized (mGlobalLock) {
+ mDisableSecureWindows = disableSecureWindows;
+ mRoot.refreshSecureSurfaceState();
+ }
+ }
}
PowerManager mPowerManager;
@@ -1115,6 +1149,8 @@
private final ScreenRecordingCallbackController mScreenRecordingCallbackController;
+ private volatile boolean mDisableSecureWindows = false;
+
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
@@ -2213,7 +2249,7 @@
int lastSyncSeqId, ClientWindowFrames outFrames,
MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outSyncIdBundle) {
+ Bundle outBundle) {
if (outActiveControls != null) {
outActiveControls.set(null);
}
@@ -2328,9 +2364,12 @@
updateNonSystemOverlayWindowsVisibilityIfNeeded(
win, win.mWinAnimator.getShown());
}
- if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {
- winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
+ if (!setScPropertiesInClient()) {
+ if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {
+ winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC)
+ != 0);
+ }
}
// See if the DisplayWindowPolicyController wants to keep the activity on the window
if (displayContent.mDwpcHelper.hasController()
@@ -2544,6 +2583,13 @@
if (outFrames != null && outMergedConfiguration != null) {
win.fillClientWindowFramesAndConfiguration(outFrames, outMergedConfiguration,
false /* useLatestConfig */, shouldRelayout);
+ if (Flags.activityWindowInfoFlag() && outBundle != null
+ && win.mActivityRecord != null) {
+ final ActivityWindowInfo activityWindowInfo = win.mActivityRecord
+ .getActivityWindowInfo();
+ outBundle.putParcelable(IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO,
+ activityWindowInfo);
+ }
// Set resize-handled here because the values are sent back to the client.
win.onResizeHandled();
@@ -2573,7 +2619,7 @@
win.isVisible() /* visible */, false /* removed */);
}
- if (outSyncIdBundle != null) {
+ if (outBundle != null) {
final int maybeSyncSeqId;
if (win.syncNextBuffer() && viewVisibility == View.VISIBLE
&& win.mSyncSeqId > lastSyncSeqId) {
@@ -2582,7 +2628,7 @@
} else {
maybeSyncSeqId = -1;
}
- outSyncIdBundle.putInt("seqid", maybeSyncSeqId);
+ outBundle.putInt(IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID, maybeSyncSeqId);
}
if (configChanged) {
@@ -6897,6 +6943,7 @@
pw.print(mLastFinishedFreezeSource);
}
pw.println();
+ pw.print(" mDisableSecureWindows="); pw.println(mDisableSecureWindows);
mInputManagerCallback.dump(pw, " ");
mSnapshotController.dump(pw, " ");
@@ -10068,4 +10115,8 @@
mDragDropController.setGlobalDragListener(listener);
}
}
+
+ boolean getDisableSecureWindows() {
+ return mDisableSecureWindows;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d967cde..14ec41f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -23,7 +23,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
-import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_BOTTOM_OF_TASK;
@@ -1558,7 +1558,7 @@
}
break;
}
- case OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE: {
+ case OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE: {
taskFragment.getTask().moveOrCreateDecorSurfaceFor(taskFragment);
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c0cf97d..37b2d0e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -240,6 +240,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import android.window.OnBackInvokedCallbackInfo;
@@ -1898,6 +1899,10 @@
}
boolean isSecureLocked() {
+ if (mWmService.getDisableSecureWindows()) {
+ return false;
+ }
+
if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
return true;
}
@@ -3692,19 +3697,32 @@
markRedrawForSyncReported();
+ // App window resize may trigger Activity#onConfigurationChanged, so we need to update
+ // ActivityWindowInfo as well.
+ final IBinder activityToken;
+ final ActivityWindowInfo activityWindowInfo;
+ if (Flags.activityWindowInfoFlag() && mActivityRecord != null) {
+ activityToken = mActivityRecord.token;
+ activityWindowInfo = mActivityRecord.getActivityWindowInfo();
+ } else {
+ activityToken = null;
+ activityWindowInfo = null;
+ }
+
if (Flags.bundleClientTransactionFlag()) {
getProcess().scheduleClientTransactionItem(
WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw,
mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,
alwaysConsumeSystemBars, displayId,
- syncWithBuffers ? mSyncSeqId : -1, isDragResizing));
+ syncWithBuffers ? mSyncSeqId : -1, isDragResizing,
+ activityToken, activityWindowInfo));
onResizePostDispatched(drawPending, prevRotation, displayId);
} else {
// TODO(b/301870955): cleanup after launch
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId,
- syncWithBuffers ? mSyncSeqId : -1, isDragResizing);
+ syncWithBuffers ? mSyncSeqId : -1, isDragResizing, activityWindowInfo);
onResizePostDispatched(drawPending, prevRotation, displayId);
} catch (RemoteException e) {
// Cancel orientation change of this window to avoid blocking unfreeze display.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 7f7c249..a242d42 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -45,6 +45,7 @@
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
import static com.android.window.flags.Flags.secureWindowState;
+import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.content.Context;
import android.graphics.PixelFormat;
@@ -311,8 +312,10 @@
mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
flags, this, attrs.type);
- mSurfaceController.setColorSpaceAgnostic(w.getPendingTransaction(),
- (attrs.privateFlags & LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
+ if (!setScPropertiesInClient()) {
+ mSurfaceController.setColorSpaceAgnostic(w.getPendingTransaction(),
+ (attrs.privateFlags & LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
+ }
w.setHasSurface(true);
// The surface instance is changed. Make sure the input info can be applied to the
diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp
index 49a3ad3..054937f 100644
--- a/services/core/jni/com_android_server_am_OomConnection.cpp
+++ b/services/core/jni/com_android_server_am_OomConnection.cpp
@@ -44,6 +44,12 @@
* @throws java.lang.RuntimeException
*/
static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject) {
+ if (!memevent_listener.ok()) {
+ memevent_listener.deregisterAllEvents();
+ jniThrowRuntimeException(env, "Failed to initialize memevents listener");
+ return nullptr;
+ }
+
if (!memevent_listener.registerEvent(MEM_EVENT_OOM_KILL)) {
memevent_listener.deregisterAllEvents();
jniThrowRuntimeException(env, "listener failed to register to OOM events");
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 610fcb5..70224db 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -143,6 +143,7 @@
jmethodID getTouchCalibrationForInputDevice;
jmethodID notifyDropWindow;
jmethodID getParentSurfaceForPointers;
+ jmethodID getPackageUid;
} gServiceClassInfo;
static struct {
@@ -362,6 +363,7 @@
void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
const std::set<gui::Uid>& uids) override;
+ gui::Uid getPackageUid(std::string package) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -1116,6 +1118,21 @@
mInputManager->getMetricsCollector().notifyDeviceInteraction(deviceId, timestamp, uids);
}
+gui::Uid NativeInputManager::getPackageUid(std::string package) {
+ ATRACE_CALL();
+ JNIEnv* env = jniEnv();
+ ScopedLocalFrame localFrame(env);
+
+ ScopedLocalRef<jstring> javaPackage(env, env->NewStringUTF(package.c_str()));
+ const jint uid =
+ env->CallIntMethod(mServiceObj, gServiceClassInfo.getPackageUid, javaPackage.get());
+ if (checkAndClearExceptionFromCallback(env, "getPackageUid")) {
+ LOG(FATAL) << __func__ << ": Failed to get UID for package: " << package;
+ }
+
+ return gui::Uid{static_cast<uint32_t>(uid)};
+}
+
void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
const std::vector<float>& values) {
@@ -3101,6 +3118,8 @@
GET_METHOD_ID(gServiceClassInfo.getParentSurfaceForPointers, clazz,
"getParentSurfaceForPointers", "(I)J");
+ GET_METHOD_ID(gServiceClassInfo.getPackageUid, clazz, "getPackageUid", "(Ljava/lang/String;)I");
+
// InputDevice
FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 173cb36..cac42b1 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -112,7 +112,8 @@
Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS),
/*defaultProviderId=*/flattenedPrimaryProviders,
/*isShowAllOptionsRequested=*/ false),
- providerDataList);
+ providerDataList,
+ mRequestSessionMetric);
mClientCallback.onPendingIntent(mPendingIntent);
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index f5e1e41..24f6697 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -25,6 +25,7 @@
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.selection.DisabledProviderData;
+import android.credentials.selection.IntentCreationResult;
import android.credentials.selection.IntentFactory;
import android.credentials.selection.ProviderData;
import android.credentials.selection.RequestInfo;
@@ -37,6 +38,8 @@
import android.os.UserHandle;
import android.service.credentials.CredentialProviderInfoFactory;
+import com.android.server.credentials.metrics.RequestSessionMetric;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -159,7 +162,8 @@
* @param providerDataList the list of provider data from remote providers
*/
public PendingIntent createPendingIntent(
- RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
+ RequestInfo requestInfo, ArrayList<ProviderData> providerDataList,
+ RequestSessionMetric requestSessionMetric) {
List<CredentialProviderInfo> allProviders =
CredentialProviderInfoFactory.getCredentialProviderServices(
mContext,
@@ -174,10 +178,12 @@
.map(disabledProvider -> new DisabledProviderData(
disabledProvider.getComponentName().flattenToString())).toList();
- Intent intent;
- intent = IntentFactory.createCredentialSelectorIntent(
- mContext, requestInfo, providerDataList,
- new ArrayList<>(disabledProviderDataList), mResultReceiver);
+ IntentCreationResult intentCreationResult = IntentFactory
+ .createCredentialSelectorIntentForCredMan(mContext, requestInfo, providerDataList,
+ new ArrayList<>(disabledProviderDataList), mResultReceiver);
+ requestSessionMetric.collectUiConfigurationResults(
+ mContext, intentCreationResult, mUserId);
+ Intent intent = intentCreationResult.getIntent();
intent.setAction(UUID.randomUUID().toString());
//TODO: Create unique pending intent using request code and cancel any pre-existing pending
// intents
@@ -197,10 +203,15 @@
* of the pinned entry.
*
* @param requestInfo the information about the request
+ * @param requestSessionMetric the metric object for logging
*/
- public Intent createIntentForAutofill(RequestInfo requestInfo) {
- return IntentFactory.createCredentialSelectorIntentForAutofill(
- mContext, requestInfo, new ArrayList<>(),
- mResultReceiver);
+ public Intent createIntentForAutofill(RequestInfo requestInfo,
+ RequestSessionMetric requestSessionMetric) {
+ IntentCreationResult intentCreationResult = IntentFactory
+ .createCredentialSelectorIntentForAutofill(mContext, requestInfo, new ArrayList<>(),
+ mResultReceiver);
+ requestSessionMetric.collectUiConfigurationResults(
+ mContext, intentCreationResult, mUserId);
+ return intentCreationResult.getIntent();
}
}
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index eff53de..fd2a9a2 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -122,7 +122,8 @@
mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS),
- /*isShowAllOptionsRequested=*/ true));
+ /*isShowAllOptionsRequested=*/ true),
+ mRequestSessionMetric);
List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>();
for (ProviderData providerData : providerDataList) {
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 6513ae1a..d55d8ef 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -111,7 +111,8 @@
Manifest.permission
.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS),
/*isShowAllOptionsRequested=*/ false),
- providerDataList);
+ providerDataList,
+ mRequestSessionMetric);
mClientCallback.onPendingIntent(mPendingIntent);
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index bdea4f9..16bf1778 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -16,6 +16,7 @@
package com.android.server.credentials;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -68,17 +69,27 @@
*
* @return the uid of a given package
*/
- protected static int getPackageUid(Context context, ComponentName componentName) {
- int sessUid = -1;
- try {
- // Only for T and above, which is fine for our use case
- sessUid = context.getPackageManager().getApplicationInfo(
- componentName.getPackageName(),
- PackageManager.ApplicationInfoFlags.of(0)).uid;
- } catch (Throwable t) {
- Slog.i(TAG, "Couldn't find required uid");
+ protected static int getPackageUid(Context context, ComponentName componentName,
+ @UserIdInt int userId) {
+ if (componentName == null) {
+ return -1;
}
- return sessUid;
+ return getPackageUid(context, componentName.getPackageName(), userId);
+ }
+
+ /** Returns the package uid, or -1 if not found. */
+ public static int getPackageUid(Context context, String packageName,
+ @UserIdInt int userId) {
+ if (packageName == null) {
+ return -1;
+ }
+ try {
+ return context.getPackageManager().getPackageUidAsUser(packageName,
+ PackageManager.PackageInfoFlags.of(0), userId);
+ } catch (Throwable t) {
+ Slog.i(TAG, "Couldn't find uid for " + packageName + ": " + t);
+ return -1;
+ }
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index 6e8f7c8..e4b5c77 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -193,7 +193,8 @@
PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS),
/*isShowAllOptionsRequested=*/ false),
- providerDataList);
+ providerDataList,
+ mRequestSessionMetric);
} else {
return null;
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index c16e232..dfc08f0 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -153,7 +153,7 @@
mUserId = userId;
mComponentName = componentName;
mRemoteCredentialService = remoteCredentialService;
- mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName);
+ mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName, userId);
mProviderSessionMetric = new ProviderSessionMetric(
((RequestSession) mCallbacks).mRequestSessionMetric.getSessionIdTrackTwo());
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/OemUiUsageStatus.java b/services/credentials/java/com/android/server/credentials/metrics/OemUiUsageStatus.java
index 2fd3a86..80ce354 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/OemUiUsageStatus.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/OemUiUsageStatus.java
@@ -22,7 +22,12 @@
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_FINAL_NO_UID_REPORTED__OEM_UI_USAGE_STATUS__OEM_UI_USAGE_STATUS_SPECIFIED_BUT_NOT_FOUND;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_FINAL_NO_UID_REPORTED__OEM_UI_USAGE_STATUS__OEM_UI_USAGE_STATUS_SPECIFIED_BUT_NOT_ENABLED;
+import android.credentials.selection.IntentCreationResult;
+/**
+ * Result of attempting to use the config_oemCredentialManagerDialogComponent as the Credential
+ * Manager UI.
+ */
public enum OemUiUsageStatus {
UNKNOWN(CREDENTIAL_MANAGER_FINAL_NO_UID_REPORTED__OEM_UI_USAGE_STATUS__OEM_UI_USAGE_STATUS_UNKNOWN),
SUCCESS(CREDENTIAL_MANAGER_FINAL_NO_UID_REPORTED__OEM_UI_USAGE_STATUS__OEM_UI_USAGE_STATUS_SUCCESS),
@@ -39,4 +44,21 @@
public int getLoggingInt() {
return mLoggingInt;
}
+
+ /** Factory method. */
+ public static OemUiUsageStatus createFrom(IntentCreationResult.OemUiUsageStatus from) {
+ switch (from) {
+ case UNKNOWN:
+ return OemUiUsageStatus.UNKNOWN;
+ case SUCCESS:
+ return OemUiUsageStatus.SUCCESS;
+ case OEM_UI_CONFIG_NOT_SPECIFIED:
+ return OemUiUsageStatus.FAILURE_NOT_SPECIFIED;
+ case OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND:
+ return OemUiUsageStatus.FAILURE_SPECIFIED_BUT_NOT_FOUND;
+ case OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED:
+ return OemUiUsageStatus.FAILURE_SPECIFIED_BUT_NOT_ENABLED;
+ }
+ return OemUiUsageStatus.UNKNOWN;
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index a77bd3e..619a568 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -30,9 +30,12 @@
import static com.android.server.credentials.metrics.ApiName.GET_CREDENTIAL_VIA_REGISTRY;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
+import android.content.Context;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
+import android.credentials.selection.IntentCreationResult;
import android.credentials.selection.UserSelectionDialogResult;
import android.util.Slog;
@@ -270,6 +273,21 @@
}
}
+ /** Log results of the device Credential Manager UI configuration. */
+ public void collectUiConfigurationResults(Context context, IntentCreationResult result,
+ @UserIdInt int userId) {
+ try {
+ mChosenProviderFinalPhaseMetric.setOemUiUid(MetricUtilities.getPackageUid(
+ context, result.getOemUiPackageName(), userId));
+ mChosenProviderFinalPhaseMetric.setFallbackUiUid(MetricUtilities.getPackageUid(
+ context, result.getFallbackUiPackageName(), userId));
+ mChosenProviderFinalPhaseMetric.setOemUiUsageStatus(
+ OemUiUsageStatus.createFrom(result.getOemUiUsageStatus()));
+ } catch (Exception e) {
+ Slog.w(TAG, "Unexpected error during ui configuration result collection: " + e);
+ }
+ }
+
/**
* Allows encapsulating the overall final phase metric status from the chosen and final
* provider.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3b2a3dd..e202bbf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1230,10 +1230,6 @@
mSystemServiceManager.startService(ThermalManagerService.class);
t.traceEnd();
- t.traceBegin("StartHintManager");
- mSystemServiceManager.startService(HintManagerService.class);
- t.traceEnd();
-
// Now that the power manager has been started, let the activity manager
// initialize power management features.
t.traceBegin("InitPowerManagement");
@@ -1614,6 +1610,10 @@
t.traceEnd();
}
+ t.traceBegin("StartHintManager");
+ mSystemServiceManager.startService(HintManagerService.class);
+ t.traceEnd();
+
// Grants default permissions and defines roles
t.traceBegin("StartRoleManagerService");
LocalManagerRegistry.addManager(RoleServicePlatformHelper.class,
diff --git a/services/proguard.flags b/services/proguard.flags
index 88561b4..a01e7dc 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -54,7 +54,10 @@
-keep,allowoptimization,allowaccessmodification class android.app.admin.flags.FeatureFlagsImpl { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.input.NativeInputManagerService$NativeImpl { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.ThreadPriorityBooster { *; }
--keep,allowaccessmodification class android.app.admin.flags.Flags { *; }
+
+# Keep all aconfig Flag class as they might be statically referenced by other packages
+# An merge or inlining could lead to missing dependencies that cause run time errors
+-keepclassmembernames class android.**.Flags, com.android.**.Flags { public *; }
# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing)
-keep public class com.android.server.utils.Slogf { *; }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index b9c5b36..b4cf799 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -203,6 +203,7 @@
.thenReturn(new int[] {0});
when(mMockUserManagerInternal.getUserIds()).thenReturn(new int[] {0});
when(mMockActivityManagerInternal.isSystemReady()).thenReturn(true);
+ when(mMockActivityManagerInternal.getCurrentUserId()).thenReturn(mCallingUserId);
when(mMockPackageManagerInternal.getPackageUid(anyString(), anyLong(), anyInt()))
.thenReturn(Binder.getCallingUid());
when(mMockPackageManagerInternal.isSameApp(anyString(), anyLong(), anyInt(), anyInt()))
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
index cea65b5..9f46d0ba 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
@@ -198,7 +198,9 @@
@Test
public void startInputOrWindowGainedFocus_userNotRunning() throws RemoteException {
- when(mMockUserManagerInternal.isUserRunning(anyInt())).thenReturn(false);
+ // Run blockingly on ServiceThread to avoid that interfering with our stubbing.
+ mServiceThread.getThreadHandler().runWithScissors(
+ () -> when(mMockUserManagerInternal.isUserRunning(anyInt())).thenReturn(false), 0);
assertThat(
startInputOrWindowGainedFocus(
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index a4d1f5c..a28259d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1537,6 +1537,47 @@
}
@Test
+ public void testOffloadBlocker_turnON_screenOnBlocked() {
+ // set up.
+ int initState = Display.STATE_OFF;
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+ mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+ // start with OFF.
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(initState);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // go to ON.
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mDisplayOffloadSession).blockScreenOn(any(Runnable.class));
+ }
+
+ @Test
+ public void testOffloadBlocker_turnOFF_screenOnNotBlocked() {
+ // set up.
+ int initState = Display.STATE_ON;
+ mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+ // start with ON.
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(initState);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ // go to OFF.
+ dpr.policy = DisplayPowerRequest.POLICY_OFF;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mDisplayOffloadSession, never()).blockScreenOn(any(Runnable.class));
+ }
+
+ @Test
public void testBrightnessFromOffload() {
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 14de527..7fd96c5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -49,6 +49,7 @@
import android.view.Display;
import android.view.DisplayAddress;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -830,18 +831,20 @@
.get()
.getModeId();
+ IdleScreenRefreshRateConfig
+ idleScreenRefreshRateConfig = new SurfaceControl.IdleScreenRefreshRateConfig(500);
displayDevice.setDesiredDisplayModeSpecsLocked(
new DisplayModeDirector.DesiredDisplayModeSpecs(
/*baseModeId*/ baseModeId,
/*allowGroupSwitching*/ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
new SurfaceControl.DesiredDisplayModeSpecs(
/* baseModeId */ 0,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
// Change the display
@@ -862,12 +865,13 @@
baseModeId = displayDevice.getDisplayDeviceInfoLocked().supportedModes[0].getModeId();
+ idleScreenRefreshRateConfig = new SurfaceControl.IdleScreenRefreshRateConfig(600);
// The traversal request will call setDesiredDisplayModeSpecsLocked on the display device
displayDevice.setDesiredDisplayModeSpecsLocked(
new DisplayModeDirector.DesiredDisplayModeSpecs(
/*baseModeId*/ baseModeId,
/*allowGroupSwitching*/ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -877,7 +881,7 @@
new SurfaceControl.DesiredDisplayModeSpecs(
/* baseModeId */ 2,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
}
@@ -1319,7 +1323,8 @@
new SurfaceControl.DesiredDisplayModeSpecs(
/* defaultMode */ 0,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES,
+ new IdleScreenRefreshRateConfig(100)
);
private FakeDisplay(int port) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 3eced7f..3a59c84 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -75,6 +75,8 @@
import android.util.TypedValue;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -91,6 +93,7 @@
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.TestUtils;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.mode.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.mode.DisplayModeDirector.DesiredDisplayModeSpecs;
@@ -112,6 +115,7 @@
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -1405,6 +1409,81 @@
}
@Test
+ public void testIdleScreenTimeOnLuxChanges() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f, 120.f}, 0);
+ setPeakRefreshRate(120 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(120);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ // Set the DisplayDeviceConfig
+ DisplayDeviceConfig ddcMock = mock(DisplayDeviceConfig.class);
+ when(ddcMock.getDefaultHighBlockingZoneRefreshRate()).thenReturn(90);
+ when(ddcMock.getHighDisplayBrightnessThresholds()).thenReturn(new float[] { 200 });
+ when(ddcMock.getHighAmbientBrightnessThresholds()).thenReturn(new float[] { 8000 });
+ when(ddcMock.getDefaultLowBlockingZoneRefreshRate()).thenReturn(90);
+ when(ddcMock.getLowDisplayBrightnessThresholds()).thenReturn(new float[] {});
+ when(ddcMock.getLowAmbientBrightnessThresholds()).thenReturn(new float[] {});
+
+ director.defaultDisplayDeviceUpdated(ddcMock); // set the ddc
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ // Get the sensor listener so that we can give it new light sensor events
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener sensorListener = listenerCaptor.getValue();
+
+ // Disable the idle screen flag
+ when(mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled())
+ .thenReturn(false);
+
+ // Sensor reads 5 lux, with idleScreenRefreshRate timeout not configured
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 5));
+ waitForIdleSync();
+ assertEquals(null, director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Enable the idle screen flag
+ when(mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled())
+ .thenReturn(true);
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 8));
+ waitForIdleSync();
+ assertEquals(null, director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Configure DDC with idle screen timeout
+ when(ddcMock.getIdleScreenRefreshRateTimeoutLuxThresholdPoint())
+ .thenReturn(List.of(getIdleScreenRefreshRateTimeoutLuxThresholdPoint(6, 1000),
+ getIdleScreenRefreshRateTimeoutLuxThresholdPoint(100, 800)));
+
+ // Sensor reads 5 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 5));
+ waitForIdleSync();
+ assertEquals(new SurfaceControl.IdleScreenRefreshRateConfig(-1),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Sensor reads 50 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 50));
+ waitForIdleSync();
+ assertEquals(new IdleScreenRefreshRateConfig(1000),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Sensor reads 200 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 200));
+ waitForIdleSync();
+ assertEquals(new SurfaceControl.IdleScreenRefreshRateConfig(800),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ }
+
+ @Test
public void testLockFpsForHighZoneWithThermalCondition() throws Exception {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -1440,11 +1519,11 @@
// Get the display listener so that we can send it new brightness events
ArgumentCaptor<DisplayListener> displayListenerCaptor =
- ArgumentCaptor.forClass(DisplayListener.class);
+ ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
// Get the sensor listener so that we can give it new light sensor events
@@ -3746,4 +3825,14 @@
}
}
}
+
+ private IdleScreenRefreshRateTimeoutLuxThresholdPoint
+ getIdleScreenRefreshRateTimeoutLuxThresholdPoint(int lux, int timeout) {
+ IdleScreenRefreshRateTimeoutLuxThresholdPoint
+ idleScreenRefreshRateTimeoutLuxThresholdPoint =
+ new IdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ idleScreenRefreshRateTimeoutLuxThresholdPoint.setLux(BigInteger.valueOf(lux));
+ idleScreenRefreshRateTimeoutLuxThresholdPoint.setTimeout(BigInteger.valueOf(timeout));
+ return idleScreenRefreshRateTimeoutLuxThresholdPoint;
+ }
}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 6d3b8ac..4149e44 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -75,6 +75,7 @@
"compatibility-device-util-axt",
"flag-junit",
"am_flags_lib",
+ "device_policy_aconfig_flags_lib",
],
libs: [
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index c30ac2d..682569f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -26,6 +26,7 @@
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.RescueParty.LEVEL_FACTORY_RESET;
+import static com.android.server.RescueParty.RESCUE_LEVEL_FACTORY_RESET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -41,9 +42,11 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.ArraySet;
@@ -55,6 +58,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
@@ -69,6 +73,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -100,6 +105,9 @@
private static final int THROTTLING_DURATION_MIN = 10;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
private HashMap<String, String> mCrashRecoveryPropertiesMap;
@@ -267,6 +275,42 @@
}
@Test
+ public void testBootLoopDetectionWithExecutionForAllRescueLevelsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
+ noteBoot(1);
+ verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap);
+
+ noteBoot(2);
+ assertTrue(RescueParty.isRebootPropertySet());
+
+ noteBoot(3);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+
+ noteBoot(4);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+
+ noteBoot(5);
+ verifyOnlySettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteBoot(6);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
noteAppCrash(1, true);
@@ -292,6 +336,47 @@
}
@Test
+ public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevelsRecoverability() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(PERSISTENT_PACKAGE, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ final String[] expectedResetNamespaces = new String[]{NAMESPACE1};
+ final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
+ noteAppCrash(1, true);
+ verifyDeviceConfigReset(expectedResetNamespaces, verifiedTimesMap);
+
+ noteAppCrash(2, true);
+ verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap);
+
+ noteAppCrash(3, true);
+ assertTrue(RescueParty.isRebootPropertySet());
+
+ noteAppCrash(4, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+
+ noteAppCrash(5, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+
+ noteAppCrash(6, true);
+ verifyOnlySettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteAppCrash(7, true);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testNonPersistentAppOnlyPerformsFlagResets() {
noteAppCrash(1, false);
@@ -316,6 +401,45 @@
}
@Test
+ public void testNonPersistentAppOnlyPerformsFlagResetsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
+ any(Executor.class),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
+ // Record DeviceConfig accesses
+ DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.onDeviceConfigAccess(NON_PERSISTENT_PACKAGE, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
+ monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
+
+ final String[] expectedResetNamespaces = new String[]{NAMESPACE1};
+ final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
+ noteAppCrash(1, false);
+ verifyDeviceConfigReset(expectedResetNamespaces, verifiedTimesMap);
+
+ noteAppCrash(2, false);
+ verifyDeviceConfigReset(expectedAllResetNamespaces, verifiedTimesMap);
+
+ noteAppCrash(3, false);
+ assertFalse(RescueParty.isRebootPropertySet());
+
+ noteAppCrash(4, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ noteAppCrash(5, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ noteAppCrash(6, false);
+ verifyNoSettingsReset(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteAppCrash(7, false);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testNonPersistentAppCrashDetectionWithScopedResets() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -451,6 +575,19 @@
}
@Test
+ public void testIsRecoveryTriggeredRebootRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i + 1);
+ }
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteBoot(RESCUE_LEVEL_FACTORY_RESET + 1);
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompleted() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
@@ -469,6 +606,25 @@
}
@Test
+ public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompletedRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i + 1);
+ }
+ int mitigationCount = RESCUE_LEVEL_FACTORY_RESET + 1;
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteBoot(mitigationCount + 1);
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testThrottlingOnBootFailures() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -481,6 +637,19 @@
}
@Test
+ public void testThrottlingOnBootFailuresRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
+ setCrashRecoveryPropLastFactoryReset(beforeTimeout);
+ for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i);
+ }
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
public void testThrottlingOnAppCrash() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -493,6 +662,19 @@
}
@Test
+ public void testThrottlingOnAppCrashRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
+ setCrashRecoveryPropLastFactoryReset(beforeTimeout);
+ for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteAppCrash(i + 1, true);
+ }
+ assertFalse(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
public void testNotThrottlingAfterTimeoutOnBootFailures() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -503,6 +685,20 @@
}
assertTrue(RescueParty.isRecoveryTriggeredReboot());
}
+
+ @Test
+ public void testNotThrottlingAfterTimeoutOnBootFailuresRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
+ setCrashRecoveryPropLastFactoryReset(afterTimeout);
+ for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i);
+ }
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ }
+
@Test
public void testNotThrottlingAfterTimeoutOnAppCrash() {
setCrashRecoveryPropAttemptingReboot(false);
@@ -516,6 +712,19 @@
}
@Test
+ public void testNotThrottlingAfterTimeoutOnAppCrashRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ setCrashRecoveryPropAttemptingReboot(false);
+ long now = System.currentTimeMillis();
+ long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
+ setCrashRecoveryPropLastFactoryReset(afterTimeout);
+ for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteAppCrash(i + 1, true);
+ }
+ assertTrue(RescueParty.isRecoveryTriggeredReboot());
+ }
+
+ @Test
public void testNativeRescuePartyResets() {
doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
@@ -531,6 +740,7 @@
@Test
public void testExplicitlyEnablingAndDisablingRescue() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
@@ -543,6 +753,7 @@
@Test
public void testDisablingRescueByDeviceConfigFlag() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
@@ -568,6 +779,20 @@
}
@Test
+ public void testDisablingFactoryResetByDeviceConfigFlagRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
+
+ for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i + 1);
+ }
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+
+ // Restore the property value initialized in SetUp()
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
+ }
+
+ @Test
public void testHealthCheckLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -594,6 +819,46 @@
}
@Test
+ public void testHealthCheckLevelsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+ // Ensure that no action is taken for cases where the failure reason is unknown
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+
+ // Ensure the correct user impact is returned for each mitigation count.
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 6),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+
+ assertEquals(observer.onHealthCheckFailed(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 7),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+ }
+
+ @Test
public void testBootLoopLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -606,6 +871,19 @@
}
@Test
+ public void testBootLoopLevelsRecoverabilityDetection() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+ assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_20);
+ assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_LEVEL_71);
+ assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_LEVEL_75);
+ assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ assertEquals(observer.onBootLoop(6), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ }
+
+ @Test
public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -727,11 +1005,26 @@
private void verifySettingsResets(int resetMode, String[] resetNamespaces,
HashMap<String, Integer> configResetVerifiedTimesMap) {
+ verifyOnlySettingsReset(resetMode);
+ verifyDeviceConfigReset(resetNamespaces, configResetVerifiedTimesMap);
+ }
+
+ private void verifyOnlySettingsReset(int resetMode) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
eq(resetMode), anyInt()));
- // Verify DeviceConfig resets
+ }
+
+ private void verifyNoSettingsReset(int resetMode) {
+ verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
+ resetMode, UserHandle.USER_SYSTEM), never());
+ verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
+ eq(resetMode), anyInt()), never());
+ }
+
+ private void verifyDeviceConfigReset(String[] resetNamespaces,
+ Map<String, Integer> configResetVerifiedTimesMap) {
if (resetNamespaces == null) {
verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never());
} else {
@@ -818,9 +1111,16 @@
// mock properties in BootThreshold
try {
- mSpyBootThreshold = spy(watchdog.new BootThreshold(
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
mCrashRecoveryPropertiesMap = new HashMap<>();
doAnswer((Answer<Integer>) invocationOnMock -> {
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 420af86..1b2c0e4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -41,6 +41,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
@@ -57,6 +58,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.ApplicationExitInfo;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
@@ -239,6 +241,7 @@
mConstants.TIMEOUT = 200;
mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500;
+ mConstants.MAX_FROZEN_OUTGOING_BROADCASTS = 10;
}
@After
@@ -2368,6 +2371,34 @@
verifyScheduleReceiver(times(1), receiverYellowApp, timeTick);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DEFER_OUTGOING_BROADCASTS)
+ public void testKillProcess_excessiveOutgoingBroadcastsWhileCached() throws Exception {
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ setProcessFreezable(callerApp, true /* pendingFreeze */, false /* frozen */);
+ waitForIdle();
+
+ final int count = mConstants.MAX_FROZEN_OUTGOING_BROADCASTS + 1;
+ for (int i = 0; i < count; ++i) {
+ final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK + "_" + i);
+ enqueueBroadcast(makeBroadcastRecord(timeTick, callerApp, List.of(
+ makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
+ }
+ // Verify that we invoke the call to freeze the caller app.
+ verify(mAms.mOomAdjuster.mCachedAppOptimizer, atLeastOnce())
+ .freezeAppAsyncImmediateLSP(callerApp);
+
+ // Verify that the caller process is killed
+ assertTrue(callerApp.isKilled());
+ verify(mProcessList).noteAppKill(same(callerApp),
+ eq(ApplicationExitInfo.REASON_OTHER),
+ eq(ApplicationExitInfo.SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED),
+ any(String.class));
+
+ waitForIdle();
+ assertNull(mAms.getProcessRecordLocked(PACKAGE_BLUE, getUidForPackage(PACKAGE_BLUE)));
+ }
+
private long getReceiverScheduledTime(@NonNull BroadcastRecord r, @NonNull Object receiver) {
for (int i = 0; i < r.receivers.size(); ++i) {
if (isReceiverEquals(receiver, r.receivers.get(i))) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
index 97b7af8..680ab16 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -36,7 +36,6 @@
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -185,8 +184,8 @@
doReturn(false).when(mAms.mAtmInternal).hasSystemAlertWindowPermission(anyInt(), anyInt(),
any());
doReturn(true).when(mAms.mOomAdjuster.mCachedAppOptimizer).useFreezer();
- doNothing().when(mAms.mOomAdjuster.mCachedAppOptimizer).freezeAppAsyncInternalLSP(
- any(), anyLong(), anyBoolean(), anyBoolean());
+ doNothing().when(mAms.mOomAdjuster.mCachedAppOptimizer).freezeAppAsyncAtEarliestLSP(
+ any());
doReturn(false).when(mAms.mAppProfiler).updateLowMemStateLSP(anyInt(), anyInt(),
anyInt(), anyLong());
@@ -503,7 +502,7 @@
if (clientApp.isFreezable()) {
verify(mAms.mOomAdjuster.mCachedAppOptimizer,
times(Flags.serviceBindingOomAdjPolicy() ? 1 : 0))
- .freezeAppAsyncInternalLSP(eq(clientApp), eq(0L), anyBoolean(), anyBoolean());
+ .freezeAppAsyncAtEarliestLSP(eq(clientApp));
clearInvocations(mAms.mOomAdjuster.mCachedAppOptimizer);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java
index 20e198c..f6f4eae 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java
@@ -16,14 +16,19 @@
package com.android.server.backup;
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningInfo;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +43,8 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
@@ -51,22 +58,30 @@
public class PackageManagerBackupAgentTest {
private static final String EXISTING_PACKAGE_NAME = "com.android.wallpaperbackup";
+ private static final int EXISTING_PACKAGE_VERSION = 1;
+
private static final int USER_ID = 0;
@Rule public TemporaryFolder folder = new TemporaryFolder();
- private PackageManager mPackageManager;
+ @Mock private PackageManager mPackageManager;
+
private PackageManagerBackupAgent mPackageManagerBackupAgent;
private ImmutableList<PackageInfo> mPackages;
private File mBackupData, mOldState, mNewState;
@Before
public void setUp() throws Exception {
- mPackageManager = getApplicationContext().getPackageManager();
+ MockitoAnnotations.initMocks(this);
PackageInfo existingPackageInfo =
- mPackageManager.getPackageInfoAsUser(
- EXISTING_PACKAGE_NAME, PackageManager.GET_SIGNING_CERTIFICATES, USER_ID);
+ createPackage(EXISTING_PACKAGE_NAME, EXISTING_PACKAGE_VERSION);
+ Signature sig = new Signature(new byte[256]);
+ existingPackageInfo.signingInfo =
+ new SigningInfo(new SigningDetails(new Signature[] {sig}, 1, null, null));
+ when(mPackageManager.getPackageInfoAsUser(eq(EXISTING_PACKAGE_NAME), anyInt(), anyInt()))
+ .thenReturn(existingPackageInfo);
+
mPackages = ImmutableList.of(existingPackageInfo);
mPackageManagerBackupAgent =
new PackageManagerBackupAgent(mPackageManager, mPackages, USER_ID);
@@ -196,6 +211,30 @@
assertThat(mNewState.length()).isEqualTo(0);
}
+ @Test
+ public void onRestore_legacyBackupWithMissingSignature_restoresBackup() throws Exception {
+ PackageInfo pkgWithoutSigs = createPackage("pkg.no.sigs", 1);
+ pkgWithoutSigs.signingInfo =
+ new SigningInfo(new SigningDetails(new Signature[0], 1, null, null));
+ when(mPackageManager.getPackageInfoAsUser(
+ eq(pkgWithoutSigs.packageName), anyInt(), anyInt()))
+ .thenReturn(pkgWithoutSigs);
+ ImmutableList<PackageInfo> packages =
+ ImmutableList.<PackageInfo>builder().addAll(mPackages).add(pkgWithoutSigs).build();
+ mPackageManagerBackupAgent =
+ new PackageManagerBackupAgent(mPackageManager, packages, USER_ID);
+ // A legacy backup is one without an ancestral record version. Ancestral record versions
+ // are always written however, so we'll need to delete it from the backup data before
+ // restoring.
+ runBackupAgentOnBackup();
+ deleteKeyFromBackupData(mBackupData, PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY);
+
+ runBackupAgentOnRestore(); // should not fail or timeout
+
+ assertThat(mPackageManagerBackupAgent.getRestoredPackages())
+ .containsExactly(EXISTING_PACKAGE_NAME);
+ }
+
private void runBackupAgentOnBackup() throws Exception {
try (ParcelFileDescriptor oldStateDescriptor = openForReading(mOldState);
ParcelFileDescriptor backupDataDescriptor = openForWriting(mBackupData);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
index ca73091..7f1a0bb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
@@ -110,7 +110,7 @@
}
@Override
- public EmergencyHelper getEmergencyHelper() {
+ public FakeEmergencyHelper getEmergencyHelper() {
return mEmergencyHelper;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 32878b3..0928264 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -16,6 +16,9 @@
package com.android.server.location.provider;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.LOCATION_BYPASS;
import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
@@ -1170,6 +1173,63 @@
}
@Test
+ public void testProviderRequest_IgnoreLocationSettings_LocationBypass() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS);
+
+ doReturn(PackageManager.PERMISSION_GRANTED)
+ .when(mContext)
+ .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid());
+ mInjector.getLocationPermissionsHelper()
+ .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION);
+ mInjector.getLocationPermissionsHelper()
+ .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION);
+ mInjector
+ .getSettingsHelper()
+ .setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build());
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request =
+ new LocationRequest.Builder(1)
+ .setLocationSettingsIgnored(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ assertThat(mProvider.getRequest().isActive()).isFalse();
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings_LocationBypass_EmergencyCall() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LOCATION_BYPASS);
+
+ doReturn(PackageManager.PERMISSION_GRANTED)
+ .when(mContext)
+ .checkPermission(LOCATION_BYPASS, IDENTITY.getPid(), IDENTITY.getUid());
+ mInjector.getLocationPermissionsHelper()
+ .revokePermission(IDENTITY.getPackageName(), ACCESS_FINE_LOCATION);
+ mInjector.getLocationPermissionsHelper()
+ .revokePermission(IDENTITY.getPackageName(), ACCESS_COARSE_LOCATION);
+ mInjector.getEmergencyHelper().setInEmergency(true);
+ mInjector
+ .getSettingsHelper()
+ .setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(IDENTITY.getPackageName()).build());
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request =
+ new LocationRequest.Builder(1)
+ .setLocationSettingsIgnored(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
+ assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isTrue();
+ }
+
+ @Test
public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() {
mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
new PackageTagsList.Builder().add(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 53c460c..9d32ed8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -21,7 +21,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
-import static android.view.accessibility.Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG;
import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
@@ -885,7 +884,6 @@
}
@Test
- @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void testIsAccessibilityServiceWarningRequired_requiredByDefault() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info = mockAccessibilityServiceInfo(COMPONENT_NAME);
@@ -894,7 +892,6 @@
}
@Test
- @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void testIsAccessibilityServiceWarningRequired_notRequiredIfAlreadyEnabled() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(COMPONENT_NAME);
@@ -909,7 +906,6 @@
}
@Test
- @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void testIsAccessibilityServiceWarningRequired_notRequiredIfExistingShortcut() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(
@@ -930,9 +926,7 @@
}
@Test
- @RequiresFlagsEnabled({
- FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG,
- FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES})
+ @RequiresFlagsEnabled(FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES)
public void testIsAccessibilityServiceWarningRequired_notRequiredIfAllowlisted() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
index 6e8d6dc..f44879f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
@@ -470,6 +470,27 @@
}
@Test
+ public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
+ final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+ setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
+ final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+ // index 1 is focused. Let's use the next one for this test.
+ final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
+ setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
+ final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
+ USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
+
+ onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+ final List<AccessibilityWindowInfo> a11yWindows =
+ mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+ assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
+ assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
+ }
+
+ @Test
public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
assertNotEquals("new title",
toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 49583ef..a852677 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -1318,6 +1318,28 @@
}
@Test
+ public void testDismissedReasonMoreOptions_whilePaused_invokeHalCancel() throws Exception {
+ setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+ invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */, null /* authenticators */);
+
+ mBiometricService.mAuthSession.mSensorReceiver.onError(
+ SENSOR_ID_FACE,
+ getCookieForCurrentSession(mBiometricService.mAuthSession),
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ 0 /* vendorCode */);
+ mBiometricService.mAuthSession.mSysuiReceiver.onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
+ null /* credentialAttestation */);
+ waitForIdle();
+
+ verify(mReceiver1).onDialogDismissed(
+ eq(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS));
+ verify(mBiometricService.mSensors.get(0).impl)
+ .cancelAuthenticationFromService(any(), any(), anyLong());
+ }
+
+ @Test
public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception {
when(mContext.getResources().getString(anyInt())).thenReturn("test string");
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index a4628ee..4d1d17f 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -141,6 +141,7 @@
@Test
public void virtualDevice_hasCustomAudioInputSupport() throws Exception {
mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
+ mSetFlagsRule.enableFlags(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API);
VirtualDevice virtualDevice =
new VirtualDevice(
@@ -150,6 +151,10 @@
assertThat(virtualDevice.hasCustomAudioInputSupport()).isFalse();
when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_AUDIO)).thenReturn(DEVICE_POLICY_CUSTOM);
+ when(mVirtualDevice.hasCustomAudioInputSupport()).thenReturn(false);
+ assertThat(virtualDevice.hasCustomAudioInputSupport()).isFalse();
+
+ when(mVirtualDevice.hasCustomAudioInputSupport()).thenReturn(true);
assertThat(virtualDevice.hasCustomAudioInputSupport()).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 1249707..3cab75b 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2315,10 +2315,11 @@
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
- // Doesn't cross any other threshold.
+ // Doesn't cross any threshold, but changes below TOP_THRESHOLD_STATE should always
+ // be processed
callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE - 1, testProcStateSeq++,
PROCESS_CAPABILITY_NONE);
- assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+ assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
}
@@ -2349,21 +2350,21 @@
int testProcStateSeq = 0;
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// First callback for uid.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_NONE);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with one network capability added.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with another network capability added.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
@@ -2371,11 +2372,21 @@
waitForUidEventHandlerIdle();
try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
// The same process-state with all capabilities, but no change in network capabilities.
- callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
PROCESS_CAPABILITY_ALL);
assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
}
waitForUidEventHandlerIdle();
+
+ callAndWaitOnUidStateChanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ PROCESS_CAPABILITY_ALL);
+ try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+ // No change in capabilities, but TOP_THRESHOLD_STATE change should always be processed.
+ callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+ PROCESS_CAPABILITY_ALL);
+ assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+ }
+ waitForUidEventHandlerIdle();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 66599e9..510e7c4 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -17,6 +17,8 @@
package com.android.server.power.hint;
+import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertArrayEquals;
@@ -45,6 +47,9 @@
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Log;
import com.android.server.FgThread;
@@ -54,11 +59,13 @@
import com.android.server.power.hint.HintManagerService.NativeWrapper;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -71,7 +78,7 @@
* Tests for {@link com.android.server.power.hint.HintManagerService}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:HintManagerServiceTest
+ * atest FrameworksServicesTests:HintManagerServiceTest
*/
public class HintManagerServiceTest {
private static final String TAG = "HintManagerServiceTest";
@@ -110,9 +117,15 @@
makeWorkDuration(2L, 13L, 2L, 8L, 0L),
};
- @Mock private Context mContext;
- @Mock private HintManagerService.NativeWrapper mNativeWrapperMock;
- @Mock private ActivityManagerInternal mAmInternalMock;
+ @Mock
+ private Context mContext;
+ @Mock
+ private HintManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock
+ private ActivityManagerInternal mAmInternalMock;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
private HintManagerService mService;
@@ -122,12 +135,11 @@
when(mNativeWrapperMock.halGetHintSessionPreferredRate())
.thenReturn(DEFAULT_HINT_PREFERRED_RATE);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_A),
- eq(DEFAULT_TARGET_DURATION))).thenReturn(1L);
+ eq(DEFAULT_TARGET_DURATION))).thenReturn(1L);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_B),
- eq(DEFAULT_TARGET_DURATION))).thenReturn(2L);
+ eq(DEFAULT_TARGET_DURATION))).thenReturn(2L);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_C),
- eq(0L))).thenReturn(1L);
- when(mAmInternalMock.getIsolatedProcesses(anyInt())).thenReturn(null);
+ eq(0L))).thenReturn(1L);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
}
@@ -434,6 +446,163 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_POWERHINT_THREAD_CLEANUP)
+ public void testCleanupDeadThreads() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ CountDownLatch stopLatch1 = new CountDownLatch(1);
+ int threadCount = 3;
+ int[] tids1 = createThreads(threadCount, stopLatch1);
+ long sessionPtr1 = 111;
+ when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(tids1),
+ eq(DEFAULT_TARGET_DURATION))).thenReturn(sessionPtr1);
+ AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSession(token, tids1, DEFAULT_TARGET_DURATION);
+ assertNotNull(session1);
+
+ // for test only to avoid conflicting with any real thread that exists on device
+ int isoProc1 = -100;
+ int isoProc2 = 9999;
+ when(mAmInternalMock.getIsolatedProcesses(eq(UID))).thenReturn(List.of(0));
+
+ CountDownLatch stopLatch2 = new CountDownLatch(1);
+ int[] tids2 = createThreads(threadCount, stopLatch2);
+ int[] tids2WithIsolated = Arrays.copyOf(tids2, tids2.length + 2);
+ int[] expectedTids2 = Arrays.copyOf(tids2, tids2.length + 1);
+ expectedTids2[tids2.length] = isoProc1;
+ tids2WithIsolated[threadCount] = isoProc1;
+ tids2WithIsolated[threadCount + 1] = isoProc2;
+ long sessionPtr2 = 222;
+ when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(tids2WithIsolated),
+ eq(DEFAULT_TARGET_DURATION))).thenReturn(sessionPtr2);
+ AppHintSession session2 = (AppHintSession) service.getBinderServiceInstance()
+ .createHintSession(token, tids2WithIsolated, DEFAULT_TARGET_DURATION);
+ assertNotNull(session2);
+
+ // trigger clean up through UID state change by making the process background
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
+ CLEAN_UP_UID_DELAY_MILLIS));
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
+ // the new TIDs pending list should be updated
+ assertArrayEquals(session2.getTidsInternal(), expectedTids2);
+ reset(mNativeWrapperMock);
+
+ // this should resume and update the threads so those never-existed invalid isolated
+ // processes should be cleaned up
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+ // wait for the async uid state change to trigger resume and setThreads
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
+ verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr2), eq(expectedTids2));
+ reset(mNativeWrapperMock);
+
+ // let all session 1 threads to exit and the cleanup should force pause the session
+ stopLatch1.countDown();
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
+ CLEAN_UP_UID_DELAY_MILLIS));
+ verify(mNativeWrapperMock, times(1)).halPauseHintSession(eq(sessionPtr1));
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
+ // all hints will have no effect as the session is force paused while proc in foreground
+ verifyAllHintsEnabled(session1, false);
+ verifyAllHintsEnabled(session2, true);
+ reset(mNativeWrapperMock);
+
+ // in foreground, set new tids for session 1 then it should be resumed and all hints allowed
+ stopLatch1 = new CountDownLatch(1);
+ tids1 = createThreads(threadCount, stopLatch1);
+ session1.setThreads(tids1);
+ verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr1), eq(tids1));
+ verify(mNativeWrapperMock, times(1)).halResumeHintSession(eq(sessionPtr1));
+ verifyAllHintsEnabled(session1, true);
+ reset(mNativeWrapperMock);
+
+ // let all session 1 and 2 non isolated threads to exit
+ stopLatch1.countDown();
+ stopLatch2.countDown();
+ expectedTids2 = new int[]{isoProc1};
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
+ CLEAN_UP_UID_DELAY_MILLIS));
+ verify(mNativeWrapperMock, times(1)).halPauseHintSession(eq(sessionPtr1));
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
+ verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
+ // in background, set threads for session 1 then it should not be force paused next time
+ session1.setThreads(SESSION_TIDS_A);
+ // the new TIDs pending list should be updated
+ assertArrayEquals(session1.getTidsInternal(), SESSION_TIDS_A);
+ assertArrayEquals(session2.getTidsInternal(), expectedTids2);
+ verifyAllHintsEnabled(session1, false);
+ verifyAllHintsEnabled(session2, false);
+ reset(mNativeWrapperMock);
+
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
+ CLEAN_UP_UID_DELAY_MILLIS));
+ verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr1),
+ eq(SESSION_TIDS_A));
+ verify(mNativeWrapperMock, times(1)).halSetThreads(eq(sessionPtr2),
+ eq(expectedTids2));
+ verifyAllHintsEnabled(session1, true);
+ verifyAllHintsEnabled(session2, true);
+ }
+
+ private void verifyAllHintsEnabled(AppHintSession session, boolean verifyEnabled) {
+ session.reportActualWorkDuration2(new WorkDuration[]{makeWorkDuration(1, 3, 2, 1, 1000)});
+ session.reportActualWorkDuration(new long[]{1}, new long[]{2});
+ session.updateTargetWorkDuration(3);
+ session.setMode(0, true);
+ session.sendHint(1);
+ if (verifyEnabled) {
+ verify(mNativeWrapperMock, times(1)).halReportActualWorkDuration(
+ eq(session.mHalSessionPtr), any());
+ verify(mNativeWrapperMock, times(1)).halSetMode(eq(session.mHalSessionPtr), anyInt(),
+ anyBoolean());
+ verify(mNativeWrapperMock, times(1)).halUpdateTargetWorkDuration(
+ eq(session.mHalSessionPtr), anyLong());
+ verify(mNativeWrapperMock, times(1)).halSendHint(eq(session.mHalSessionPtr), anyInt());
+ } else {
+ verify(mNativeWrapperMock, never()).halReportActualWorkDuration(
+ eq(session.mHalSessionPtr), any());
+ verify(mNativeWrapperMock, never()).halSetMode(eq(session.mHalSessionPtr), anyInt(),
+ anyBoolean());
+ verify(mNativeWrapperMock, never()).halUpdateTargetWorkDuration(
+ eq(session.mHalSessionPtr), anyLong());
+ verify(mNativeWrapperMock, never()).halSendHint(eq(session.mHalSessionPtr), anyInt());
+ }
+ }
+
+ private int[] createThreads(int threadCount, CountDownLatch stopLatch)
+ throws InterruptedException {
+ int[] tids = new int[threadCount];
+ AtomicInteger k = new AtomicInteger(0);
+ CountDownLatch latch = new CountDownLatch(threadCount);
+ for (int j = 0; j < threadCount; j++) {
+ Thread thread = new Thread(() -> {
+ try {
+ tids[k.getAndIncrement()] = android.os.Process.myTid();
+ latch.countDown();
+ stopLatch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ thread.start();
+ }
+ latch.await();
+ return tids;
+ }
+
+ @Test
public void testSetMode() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();
@@ -457,7 +626,8 @@
// Set session to background, then the duration would not be updated.
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
- FgThread.getHandler().runWithScissors(() -> { }, 500);
+ FgThread.getHandler().runWithScissors(() -> {
+ }, 500);
assertFalse(service.mUidObserver.isUidForeground(a.mUid));
a.setMode(0, true);
verify(mNativeWrapperMock, never()).halSetMode(anyLong(), anyInt(), anyBoolean());
@@ -519,7 +689,10 @@
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
service.mUidObserver.onUidStateChanged(UID,
ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
- LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
+ // let the cleanup work proceed
+ LockSupport.parkNanos(
+ TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
+ CLEAN_UP_UID_DELAY_MILLIS));
}
Log.d(TAG, "notifier thread min " + min + " max " + max + " avg " + sum / count);
service.mUidObserver.onUidGone(UID, true);
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/power/hint/TEST_MAPPING
new file mode 100644
index 0000000..2d5df07
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/hint/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "postsubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.power.hint"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
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 99ab405..06a4ac9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5862,6 +5862,7 @@
assertThat(captor.getValue().getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
+ assertThat(captor.getValue().shouldPostSilently()).isTrue();
}
@Test
@@ -8603,6 +8604,7 @@
assertThat(captor.getValue().getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
+ assertThat(captor.getValue().shouldPostSilently()).isTrue();
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bfc47fd..cee6cdb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3962,6 +3962,20 @@
}
@Test
+ public void testReadXml_existingPackage_bubblePrefsRestored() throws Exception {
+ mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL);
+ assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O));
+
+ mXmlHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE);
+ assertEquals(BUBBLE_PREFERENCE_NONE, mXmlHelper.getBubblePreference(PKG_O, UID_O));
+
+ ByteArrayOutputStream stream = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
+ loadStreamXml(stream, true, UserHandle.USER_ALL);
+
+ assertEquals(BUBBLE_PREFERENCE_ALL, mXmlHelper.getBubblePreference(PKG_O, UID_O));
+ }
+
+ @Test
public void testUpdateNotificationChannel_fixedPermission() {
List<UserInfo> users = ImmutableList.of(new UserInfo(UserHandle.USER_SYSTEM, "user0", 0));
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
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 29467f2..a80e2f8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -16,10 +16,14 @@
package com.android.server.policy;
+import static android.view.Display.DEFAULT_DISPLAY;
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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -33,18 +37,27 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.PowerManager;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.SmallTest;
+import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.DisplayPolicy;
+import com.android.server.wm.DisplayRotation;
+import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
import org.junit.Before;
@@ -64,16 +77,27 @@
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
PhoneWindowManager mPhoneWindowManager;
+ private ActivityTaskManagerInternal mAtmInternal;
+ private Context mContext;
@Before
public void setUp() {
mPhoneWindowManager = spy(new PhoneWindowManager());
spyOn(ActivityManager.getService());
+ mContext = getInstrumentation().getTargetContext();
+ spyOn(mContext);
+ mAtmInternal = mock(ActivityTaskManagerInternal.class);
+ LocalServices.addService(ActivityTaskManagerInternal.class, mAtmInternal);
+ mPhoneWindowManager.mActivityTaskManagerInternal = mAtmInternal;
+ LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
}
@After
public void tearDown() {
reset(ActivityManager.getService());
+ reset(mContext);
+ LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
}
@Test
@@ -99,6 +123,60 @@
}
@Test
+ public void testScreenTurnedOff() {
+ mSetFlagsRule.enableFlags(com.android.window.flags.Flags
+ .FLAG_SKIP_SLEEPING_WHEN_SWITCHING_DISPLAY);
+ doNothing().when(mPhoneWindowManager).updateSettings(any());
+ doNothing().when(mPhoneWindowManager).initializeHdmiState();
+ final boolean[] isScreenTurnedOff = { false };
+ final DisplayPolicy displayPolicy = mock(DisplayPolicy.class);
+ doAnswer(invocation -> isScreenTurnedOff[0] = true).when(displayPolicy).screenTurnedOff();
+ doAnswer(invocation -> !isScreenTurnedOff[0]).when(displayPolicy).isScreenOnEarly();
+ doAnswer(invocation -> !isScreenTurnedOff[0]).when(displayPolicy).isScreenOnFully();
+
+ mPhoneWindowManager.mDefaultDisplayPolicy = displayPolicy;
+ mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class);
+ final ActivityTaskManagerInternal.SleepTokenAcquirer tokenAcquirer =
+ mock(ActivityTaskManagerInternal.SleepTokenAcquirer.class);
+ doReturn(tokenAcquirer).when(mAtmInternal).createSleepTokenAcquirer(anyString());
+ final PowerManager pm = mock(PowerManager.class);
+ doReturn(true).when(pm).isInteractive();
+ doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
+
+ mContext.getMainThreadHandler().runWithScissors(() -> mPhoneWindowManager.init(
+ new PhoneWindowManager.Injector(mContext,
+ mock(WindowManagerPolicy.WindowManagerFuncs.class))), 0);
+ assertThat(isScreenTurnedOff[0]).isFalse();
+ assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isFalse();
+
+ // Skip sleep-token for non-sleep-screen-off.
+ clearInvocations(tokenAcquirer);
+ mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */);
+ verify(tokenAcquirer, never()).acquire(anyInt(), anyBoolean());
+ assertThat(isScreenTurnedOff[0]).isTrue();
+
+ // Apply sleep-token for sleep-screen-off.
+ mPhoneWindowManager.startedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */);
+ assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isTrue();
+ mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */);
+ verify(tokenAcquirer).acquire(eq(DEFAULT_DISPLAY), eq(true));
+
+ mPhoneWindowManager.finishedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */);
+ assertThat(mPhoneWindowManager.mIsGoingToSleepDefaultDisplay).isFalse();
+
+ // Simulate unexpected reversed order: screenTurnedOff -> startedGoingToSleep. The sleep
+ // token can still be acquired.
+ isScreenTurnedOff[0] = false;
+ clearInvocations(tokenAcquirer);
+ mPhoneWindowManager.screenTurnedOff(DEFAULT_DISPLAY, true /* isSwappingDisplay */);
+ verify(tokenAcquirer, never()).acquire(anyInt(), anyBoolean());
+ assertThat(displayPolicy.isScreenOnEarly()).isFalse();
+ assertThat(displayPolicy.isScreenOnFully()).isFalse();
+ mPhoneWindowManager.startedGoingToSleep(DEFAULT_DISPLAY, 0 /* reason */);
+ verify(tokenAcquirer).acquire(eq(DEFAULT_DISPLAY), eq(false));
+ }
+
+ @Test
public void testCheckAddPermission_withoutAccessibilityOverlay_noAccessibilityAppOpLogged() {
mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
@@ -130,11 +208,8 @@
private void mockStartDockOrHome() throws Exception {
doNothing().when(ActivityManager.getService()).stopAppSwitches();
- ActivityTaskManagerInternal mMockActivityTaskManagerInternal =
- mock(ActivityTaskManagerInternal.class);
- when(mMockActivityTaskManagerInternal.startHomeOnDisplay(
+ when(mAtmInternal.startHomeOnDisplay(
anyInt(), anyString(), anyInt(), anyBoolean(), anyBoolean())).thenReturn(false);
- mPhoneWindowManager.mActivityTaskManagerInternal = mMockActivityTaskManagerInternal;
mPhoneWindowManager.mUserManagerInternal = mock(UserManagerInternal.class);
}
}
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 daa5a5a..beafeec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3346,7 +3346,7 @@
} else {
verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(),
insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(),
- anyBoolean());
+ anyBoolean(), any());
}
assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
}
@@ -3416,6 +3416,7 @@
// Remove window during transition, so it is requested to hide, but won't be committed until
// the transition is finished.
app.mActivityRecord.onRemovedFromDisplay();
+ app.mActivityRecord.prepareSurfaces();
assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord));
assertFalse(app.mActivityRecord.isVisibleRequested());
@@ -3433,6 +3434,7 @@
public void testInClosingAnimation_visibilityCommitted_hideSurface() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
makeWindowVisibleAndDrawn(app);
+ app.mActivityRecord.prepareSurfaces();
// Put the activity in close transition.
mDisplayContent.mOpeningApps.clear();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index b9e87dc..363ae14 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -291,13 +291,22 @@
assertTrue(predictable);
outPrevActivities.clear();
- // Stacked + companion => predict for previous task
+ // Stacked + top companion to bottom but bottom didn't => predict for previous activity
tf2.setCompanionTaskFragment(tf1);
predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ tf2.setCompanionTaskFragment(null);
+ outPrevActivities.clear();
+
+ // Stacked + next companion to top => predict for previous task
+ tf1.setCompanionTaskFragment(tf2);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
assertTrue(outPrevActivities.isEmpty());
assertTrue(predictable);
- tf2.setCompanionTaskFragment(null);
+ tf1.setCompanionTaskFragment(null);
// Adjacent + no companion => unable to predict
// TF1 | TF2
@@ -314,11 +323,13 @@
// Adjacent + companion => predict for previous task
tf1.setCompanionTaskFragment(tf2);
- tf2.setCompanionTaskFragment(tf1);
predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
outPrevActivities);
assertTrue(outPrevActivities.isEmpty());
assertTrue(predictable);
+ tf1.setCompanionTaskFragment(null);
+
+ tf2.setCompanionTaskFragment(tf1);
predictable = BackNavigationController.getAnimatablePrevActivities(task, prevAr,
outPrevActivities);
assertTrue(outPrevActivities.isEmpty());
@@ -361,18 +372,27 @@
tf3.setAdjacentTaskFragment(null);
final TaskFragment tf4 = createTaskFragmentWithActivity(task);
- // Stacked + companion => predict for previous activity below companion.
+ // Stacked + next companion to top => predict for previous activity below companion.
// Tf4
// TF3
// TF2
// TF1
- tf4.setCompanionTaskFragment(tf3);
tf3.setCompanionTaskFragment(tf4);
topAr = tf4.getTopMostActivity();
predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
outPrevActivities);
assertTrue(outPrevActivities.contains(tf2.getTopMostActivity()));
assertTrue(predictable);
+ outPrevActivities.clear();
+ tf3.setCompanionTaskFragment(null);
+
+ // Stacked + top companion to next but next one didn't => predict for previous activity.
+ tf4.setCompanionTaskFragment(tf3);
+ topAr = tf4.getTopMostActivity();
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(tf3.getTopMostActivity()));
+ assertTrue(predictable);
}
@Test
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 4e360d0..2c88ed2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1068,16 +1068,6 @@
mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
}
- @SetupWindows(addWindows = W_INPUT_METHOD)
- @Test
- public void testInputMethodSet_listenOnDisplayAreaConfigurationChanged() {
- spyOn(mAtm);
- mDisplayContent.setInputMethodWindowLocked(mImeWindow);
-
- verify(mAtm).onImeWindowSetOnDisplayArea(
- mImeWindow.mSession.mPid, mDisplayContent.getImeContainer());
- }
-
@Test
public void testAllowsTopmostFullscreenOrientation() {
final DisplayContent dc = createNewDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
index 0a59ae1..137ef5e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
@@ -29,6 +29,8 @@
import androidx.test.filters.SmallTest;
+import com.android.window.flags.Flags;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
@@ -142,12 +144,20 @@
private void verifyStableInsets(DisplayInfo di, int left, int top,
int right, int bottom) {
+ if (Flags.insetsDecoupledConfiguration()) {
+ // TODO: update the verification to match the new behavior.
+ return;
+ }
mErrorCollector.checkThat("stableInsets", getStableInsets(di),
equalTo(new Rect(left, top, right, bottom)));
}
private void verifyNonDecorInsets(DisplayInfo di, int left, int top,
int right, int bottom) {
+ if (Flags.insetsDecoupledConfiguration()) {
+ // TODO: update the verification to match the new behavior.
+ return;
+ }
mErrorCollector.checkThat("nonDecorInsets",
getNonDecorInsets(di), equalTo(new Rect(left, top, right, bottom)));
}
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 4e4bbfe..5aabea3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -21,6 +21,7 @@
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -63,6 +64,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
+import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -101,11 +103,11 @@
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
- /**
+/**
* Test class for {@link LetterboxUiControllerTest}.
*
* Build/Install/Run:
- * atest WmTests:LetterboxUiControllerTest
+ * atest WmTests:LetterboxUiControllerTest
*/
@SmallTest
@Presubmit
@@ -466,10 +468,48 @@
assertTrue(mController.shouldForceRotateForCameraCompat());
}
+ // shouldApplyFreeformTreatmentForCameraCompat
+
+ @Test
+ public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
+ mSetFlagsRule.disableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertTrue(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
@Test
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
- WindowInsets.Type.navigationBars());
+ WindowInsets.Type.navigationBars());
taskbar.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
final Rect opaqueBounds = new Rect(0, 0, 500, 300);
@@ -726,7 +766,7 @@
throws Exception {
mDisplayContent.setIgnoreOrientationRequest(false);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -736,7 +776,7 @@
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -859,6 +899,7 @@
assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
}
+
@Test
public void testOverrideOrientationIfNeeded_respectOrientationRequestOverUserFullScreen() {
spyOn(mController);
@@ -1380,7 +1421,7 @@
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
- /* className */ "");
+ /* className */ "");
PackageManager pm = mWm.mContext.getPackageManager();
spyOn(pm);
doReturn(property).when(pm).getProperty(eq(propertyName), anyString());
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 897a3da..52485ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -25,7 +25,7 @@
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
-import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_BOTTOM_OF_TASK;
@@ -1835,7 +1835,7 @@
final TaskFragment tf = createTaskFragment(task);
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
- OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE).build();
+ OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE).build();
mTransaction.addTaskFragmentOperation(tf.getFragmentToken(), operation);
assertApplyTransactionAllowed(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 3f8acc6..37de51e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -28,6 +28,7 @@
import android.view.InsetsState;
import android.view.ScrollCaptureResponse;
import android.view.inputmethod.ImeTracker;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import com.android.internal.os.IResultReceiver;
@@ -46,8 +47,8 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, InsetsState insetsState, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing)
- throws RemoteException {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, boolean dragResizing,
+ @Nullable ActivityWindowInfo activityWindowInfo) throws RemoteException {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 12f46df..48b12f7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -90,6 +90,7 @@
import android.util.MergedConfiguration;
import android.view.ContentRecordingSession;
import android.view.IWindow;
+import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -99,6 +100,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
import android.window.InputTransferToken;
import android.window.ScreenCapture;
@@ -1216,6 +1218,35 @@
mWm.reportKeepClearAreasChanged(session, window, new ArrayList<>(), new ArrayList<>());
}
+ @Test
+ public void testRelayout_appWindowSendActivityWindowInfo() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+ // Skip unnecessary operations of relayout.
+ spyOn(mWm.mWindowPlacerLocked);
+ doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
+
+ final Task task = createTask(mDisplayContent);
+ final WindowState win = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "appWindow");
+ mWm.mWindowMap.put(win.mClient.asBinder(), win);
+
+ final int w = 100;
+ final int h = 200;
+ final ClientWindowFrames outFrames = new ClientWindowFrames();
+ final MergedConfiguration outConfig = new MergedConfiguration();
+ final SurfaceControl outSurfaceControl = new SurfaceControl();
+ final InsetsState outInsetsState = new InsetsState();
+ final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
+ final Bundle outBundle = new Bundle();
+
+ mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0,
+ outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
+
+ final ActivityWindowInfo activityWindowInfo = outBundle.getParcelable(
+ IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO, ActivityWindowInfo.class);
+ assertEquals(win.mActivityRecord.getActivityWindowInfo(), activityWindowInfo);
+ }
+
class TestResultReceiver implements IResultReceiver {
public android.os.Bundle resultData;
private final IBinder mBinder = mock(IBinder.class);
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 c8ad4bd..e20f822 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -804,7 +804,8 @@
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
any() /* insetsState */, anyBoolean() /* forceLayout */,
anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
- anyInt() /* seqId */, anyBoolean() /* dragResizing */);
+ anyInt() /* seqId */, anyBoolean() /* dragResizing */,
+ any() /* activityWindowInfo */);
} catch (RemoteException ignored) {
}
win.reportResized();
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 883c702..e9da53a 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -968,22 +968,20 @@
stats.libSize += getDirBytes(new File(sourceDirName + "/lib/"));
// Get dexopt, current profle and reference profile sizes.
- if (SystemProperties.getBoolean("dalvik.vm.features.art_managed_file_stats", false)) {
- ArtManagedFileStats artManagedFileStats;
- try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
- artManagedFileStats =
- getArtManagerLocal().getArtManagedFileStats(snapshot, packageName);
- }
-
- stats.dexoptSize +=
- artManagedFileStats
- .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_DEXOPT_ARTIFACT);
- stats.refProfSize +=
- artManagedFileStats
- .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_REF_PROFILE);
- stats.curProfSize +=
- artManagedFileStats
- .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_CUR_PROFILE);
+ ArtManagedFileStats artManagedFileStats;
+ try (var snapshot = getPackageManagerLocal().withFilteredSnapshot()) {
+ artManagedFileStats =
+ getArtManagerLocal().getArtManagedFileStats(snapshot, packageName);
}
+
+ stats.dexoptSize +=
+ artManagedFileStats
+ .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_DEXOPT_ARTIFACT);
+ stats.refProfSize +=
+ artManagedFileStats
+ .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_REF_PROFILE);
+ stats.curProfSize +=
+ artManagedFileStats
+ .getTotalSizeBytesByType(ArtManagedFileStats.TYPE_CUR_PROFILE);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index ad7b9e6..96c3ed5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -184,7 +184,7 @@
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
// TODO: This may need to be a Handler(looper)
final ScheduledExecutorService mScheduledExecutorService;
- private final AppOpsManager mAppOpsManager;
+ final AppOpsManager mAppOpsManager;
final HotwordAudioStreamCopier mHotwordAudioStreamCopier;
final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
final IHotwordRecognitionStatusCallback mCallback;
@@ -201,7 +201,7 @@
/** Identity used for attributing app ops when delivering data to the Interactor. */
@Nullable
- private final Identity mVoiceInteractorIdentity;
+ final Identity mVoiceInteractorIdentity;
@GuardedBy("mLock")
ParcelFileDescriptor mCurrentAudioSink;
@GuardedBy("mLock")
@@ -926,7 +926,7 @@
* @param permission The identifier of the permission we want to check.
* @param reason The reason why we're requesting the permission, for auditing purposes.
*/
- private static void enforcePermissionForDataDelivery(@NonNull Context context,
+ protected static void enforcePermissionForDataDelivery(@NonNull Context context,
@NonNull Identity identity, @NonNull String permission, @NonNull String reason) {
final int status = PermissionUtil.checkPermissionForDataDelivery(context, identity,
permission, reason);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
index aef8e6f..0a66065 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
@@ -16,6 +16,10 @@
package com.android.server.voiceinteraction;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_ATTENTION_STATE;
import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_STREAMING_STATE;
@@ -24,6 +28,7 @@
import android.content.Context;
import android.media.AudioFormat;
import android.media.permission.Identity;
+import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -58,6 +63,14 @@
final class VisualQueryDetectorSession extends DetectorSession {
private static final String TAG = "VisualQueryDetectorSession";
+
+ private static final String VISUAL_QUERY_DETECTION_AUDIO_OP_MESSAGE =
+ "Providing query detection result from VisualQueryDetectionService to "
+ + "VoiceInteractionService";
+
+ private static final String VISUAL_QUERY_DETECTION_CAMERA_OP_MESSAGE =
+ "Providing query detection result from VisualQueryDetectionService to "
+ + "VoiceInteractionService";
private IVisualQueryDetectionAttentionListener mAttentionListener;
private boolean mEgressingData;
private boolean mQueryStreaming;
@@ -172,6 +185,22 @@
"Cannot stream queries without attention signals."));
return;
}
+ try {
+ enforcePermissionsForVisualQueryDelivery(RECORD_AUDIO, OP_RECORD_AUDIO,
+ VISUAL_QUERY_DETECTION_AUDIO_OP_MESSAGE);
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Ignoring #onQueryDetected due to a SecurityException", e);
+ try {
+ callback.onVisualQueryDetectionServiceFailure(
+ new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot stream queries without audio permission."));
+ } catch (RemoteException e1) {
+ notifyOnDetectorRemoteException();
+ throw e1;
+ }
+ return;
+ }
mQueryStreaming = true;
callback.onQueryDetected(partialQuery);
Slog.i(TAG, "Egressed from visual query detection process.");
@@ -202,6 +231,48 @@
+ "enabling the setting."));
return;
}
+
+ // Show camera icon if visual only accessibility data egresses
+ if (partialResult.getAccessibilityDetectionData() != null) {
+ try {
+ enforcePermissionsForVisualQueryDelivery(CAMERA, OP_CAMERA,
+ VISUAL_QUERY_DETECTION_CAMERA_OP_MESSAGE);
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Ignoring #onQueryDetected due to a SecurityException", e);
+ try {
+ callback.onVisualQueryDetectionServiceFailure(
+ new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot stream visual only accessibility data "
+ + "without camera permission."));
+ } catch (RemoteException e1) {
+ notifyOnDetectorRemoteException();
+ throw e1;
+ }
+ return;
+ }
+ }
+
+ // Show microphone icon if text query egresses
+ if (!partialResult.getPartialQuery().isEmpty()) {
+ try {
+ enforcePermissionsForVisualQueryDelivery(RECORD_AUDIO, OP_RECORD_AUDIO,
+ VISUAL_QUERY_DETECTION_AUDIO_OP_MESSAGE);
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Ignoring #onQueryDetected due to a SecurityException", e);
+ try {
+ callback.onVisualQueryDetectionServiceFailure(
+ new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot stream queries without audio permission."));
+ } catch (RemoteException e1) {
+ notifyOnDetectorRemoteException();
+ throw e1;
+ }
+ return;
+ }
+ }
+
mQueryStreaming = true;
callback.onResultDetected(partialResult);
Slog.i(TAG, "Egressed from visual query detection process.");
@@ -280,6 +351,20 @@
mEnableAccessibilityDataEgress = enable;
}
+ void enforcePermissionsForVisualQueryDelivery(String permission, int op, String msg) {
+ Binder.withCleanCallingIdentity(() -> {
+ synchronized (mLock) {
+ enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity,
+ permission, msg);
+ mAppOpsManager.noteOpNoThrow(
+ op, mVoiceInteractorIdentity.uid,
+ mVoiceInteractorIdentity.packageName,
+ mVoiceInteractorIdentity.attributionTag,
+ msg);
+ }
+ });
+ }
+
@SuppressWarnings("GuardedBy")
public void dumpLocked(String prefix, PrintWriter pw) {
super.dumpLocked(prefix, pw);
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
index 901daf8..f5688bf 100644
--- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -18,8 +18,13 @@
import android.annotation.NonNull;
import android.app.SystemServiceRegistry;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.SystemProperties;
import android.os.TelephonyServiceManager;
import android.telephony.euicc.EuiccCardManager;
import android.telephony.euicc.EuiccManager;
@@ -40,6 +45,16 @@
private TelephonyFrameworkInitializer() {
}
+ /**
+ * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags
+ * (e.g. {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before
+ * returning managers that depend on them. If the feature is missing,
+ * {@link Context#getSystemService} will return null.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ static final long ENABLE_CHECKING_TELEPHONY_FEATURES = 330583731;
+
private static volatile TelephonyServiceManager sTelephonyServiceManager;
/**
@@ -57,8 +72,23 @@
sTelephonyServiceManager = Preconditions.checkNotNull(telephonyServiceManager);
}
+ // Suppressing AndroidFrameworkCompatChange because we're querying vendor
+ // partition SDK level, not application's target SDK version (which BTW we
+ // also check through Compatibility framework a few lines below).
+ @SuppressWarnings("AndroidFrameworkCompatChange")
private static boolean hasSystemFeature(Context context, String feature) {
+ // Check release status of this change in behavior.
if (!Flags.minimalTelephonyManagersConditionalOnFeatures()) return true;
+
+ // Check SDK version of the vendor partition.
+ final int vendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
+ if (vendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) return true;
+
+ // Check SDK version of the client app.
+ if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES)) return true;
+
+ // Finally, check if the system feature is actually present.
return context.getPackageManager().hasSystemFeature(feature);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a047b97..69c47d43 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -15021,16 +15021,15 @@
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@FlaggedApi(android.permission.flags.Flags.FLAG_GET_EMERGENCY_ROLE_HOLDER_API_ENABLED)
- @NonNull
+ @Nullable
@SystemApi
public String getEmergencyAssistancePackageName() {
if (!isEmergencyAssistanceEnabled() || !isVoiceCapable()) {
throw new IllegalStateException("isEmergencyAssistanceEnabled() is false or device"
+ " not voice capable.");
}
- String emergencyRole = mContext.getSystemService(RoleManager.class)
+ return mContext.getSystemService(RoleManager.class)
.getEmergencyRoleHolder(mContext.getUserId());
- return Objects.requireNonNull(emergencyRole, "Emergency role holder must not be null");
}
/**
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index 9441fb5..36485c6 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -347,28 +347,6 @@
in IIntegerConsumer callback);
/**
- * Request to get whether satellite communication is allowed for the current location.
- *
- * @param resultCallback The callback to receive the error code result of the operation.
- * This must only be sent when the result is not
- * SatelliteResult#SATELLITE_RESULT_SUCCESS.
- * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
- * receive whether satellite communication is allowed for the current location.
- *
- * Valid result codes returned:
- * SatelliteResult:SATELLITE_RESULT_SUCCESS
- * SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
- * SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
- * SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
- * SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
- * SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
- * SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
- * SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
- */
- void requestIsSatelliteCommunicationAllowedForCurrentLocation(
- in IIntegerConsumer resultCallback, in IBooleanConsumer callback);
-
- /**
* Request to get the time after which the satellite will be visible. This is an int
* representing the duration in seconds after which the satellite will be visible.
* This will return 0 if the satellite is currently visible.
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index f17ff17..b7dc79f 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -194,17 +194,6 @@
}
@Override
- public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
- IIntegerConsumer resultCallback, IBooleanConsumer callback)
- throws RemoteException {
- executeMethodAsync(
- () -> SatelliteImplBase.this
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
- resultCallback, callback),
- "requestIsCommunicationAllowedForCurrentLocation");
- }
-
- @Override
public void requestTimeForNextSatelliteVisibility(IIntegerConsumer resultCallback,
IIntegerConsumer callback) throws RemoteException {
executeMethodAsync(
@@ -638,30 +627,6 @@
}
/**
- * Request to get whether satellite communication is allowed for the current location.
- *
- * @param resultCallback The callback to receive the error code result of the operation.
- * This must only be sent when the result is not
- * SatelliteResult#SATELLITE_RESULT_SUCCESS.
- * @param callback If the result is SatelliteResult#SATELLITE_RESULT_SUCCESS, the callback to
- * receive whether satellite communication is allowed for the current location.
- *
- * Valid result codes returned:
- * SatelliteResult:SATELLITE_RESULT_SUCCESS
- * SatelliteResult:SATELLITE_RESULT_SERVICE_ERROR
- * SatelliteResult:SATELLITE_RESULT_MODEM_ERROR
- * SatelliteResult:SATELLITE_RESULT_INVALID_MODEM_STATE
- * SatelliteResult:SATELLITE_RESULT_INVALID_ARGUMENTS
- * SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE
- * SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED
- * SatelliteResult:SATELLITE_RESULT_NO_RESOURCES
- */
- public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
- @NonNull IIntegerConsumer resultCallback, @NonNull IBooleanConsumer callback) {
- // stub implementation
- }
-
- /**
* Request to get the time after which the satellite will be visible. This is an int
* representing the duration in seconds after which the satellite will be visible.
* This will return 0 if the satellite is currently visible.
diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
index 5460e4e87..64dbe71 100644
--- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
+++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
@@ -43,6 +43,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -392,6 +393,7 @@
}
@Test
+ @Ignore("Can be enabled only after b/330536267 is ready")
public void testChoreographerDivisorRefreshRate() {
for (int divisor : new int[]{2, 3}) {
CountDownLatch continueLatch = new CountDownLatch(1);
@@ -420,6 +422,7 @@
}
@Test
+ @Ignore("Can be enabled only after b/330536267 is ready")
public void testChoreographerAttachedAfterSetFrameRate() {
Log.i(TAG, "starting testChoreographerAttachedAfterSetFrameRate");
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 caaee63..4d48276 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
@@ -30,10 +30,12 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+@Ignore // b/330376055: Write tests for functionality for both dVRR and MRR devices.
@RunWith(AndroidJUnit4.class)
public class SurfaceControlTest {
private static final String TAG = "SurfaceControlTest";
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index 0c60f28..ffed408 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -47,7 +47,7 @@
val bound = gameView.getVisibleBounds()
return uiDevice.swipe(
bound.centerX(),
- bound.top,
+ 0,
bound.centerX(),
bound.centerY(),
SWIPE_STEPS
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index e0e6c4c..2c5fdd3 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -28,8 +28,10 @@
static_libs: [
"junit",
"mockito-target-extended-minus-junit4",
+ "flag-junit",
"frameworks-base-testutils",
"androidx.test.rules",
+ "PlatformProperties",
"services.core",
"services.net",
"truth",
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
new file mode 100644
index 0000000..081da11
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.crashrecovery.flags.Flags;
+import android.net.ConnectivityModuleConnector;
+import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.DeviceConfig;
+import android.util.AtomicFile;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.RescueParty.RescuePartyObserver;
+import com.android.server.pm.ApexManager;
+import com.android.server.rollback.RollbackPackageHealthObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Test CrashRecovery, integration tests that include PackageWatchdog, RescueParty and
+ * RollbackPackageHealthObserver
+ */
+public class CrashRecoveryTest {
+ private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
+ "persist.device_config.configuration.disable_rescue_party";
+
+ private static final String APP_A = "com.package.a";
+ private static final String APP_B = "com.package.b";
+ private static final String APP_C = "com.package.c";
+ private static final long VERSION_CODE = 1L;
+ private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+
+ private static final RollbackInfo ROLLBACK_INFO_LOW = getRollbackInfo(APP_A, VERSION_CODE, 1,
+ PackageManager.ROLLBACK_USER_IMPACT_LOW);
+ private static final RollbackInfo ROLLBACK_INFO_HIGH = getRollbackInfo(APP_B, VERSION_CODE, 2,
+ PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+ private static final RollbackInfo ROLLBACK_INFO_MANUAL = getRollbackInfo(APP_C, VERSION_CODE, 3,
+ PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL);
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private final TestClock mTestClock = new TestClock();
+ private TestLooper mTestLooper;
+ private Context mSpyContext;
+ // Keep track of all created watchdogs to apply device config changes
+ private List<PackageWatchdog> mAllocatedWatchdogs;
+ @Mock
+ private ConnectivityModuleConnector mConnectivityModuleConnector;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private ApexManager mApexManager;
+ @Mock
+ RollbackManager mRollbackManager;
+ // Mock only sysprop apis
+ private PackageWatchdog.BootThreshold mSpyBootThreshold;
+ @Captor
+ private ArgumentCaptor<ConnectivityModuleHealthListener> mConnectivityModuleCallbackCaptor;
+ private MockitoSession mSession;
+ private HashMap<String, String> mSystemSettingsMap;
+ private HashMap<String, String> mCrashRecoveryPropertiesMap;
+
+ @Before
+ public void setUp() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ MockitoAnnotations.initMocks(this);
+ new File(InstrumentationRegistry.getContext().getFilesDir(),
+ "package-watchdog.xml").delete();
+ adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
+ mTestLooper = new TestLooper();
+ mSpyContext = spy(InstrumentationRegistry.getContext());
+ when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).then(inv -> {
+ final PackageInfo res = new PackageInfo();
+ res.packageName = inv.getArgument(0);
+ res.setLongVersionCode(VERSION_CODE);
+ return res;
+ });
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(SystemProperties.class)
+ .spyStatic(RescueParty.class)
+ .startMocking();
+ mSystemSettingsMap = new HashMap<>();
+
+ // Mock SystemProperties setter and various getters
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ String value = invocationOnMock.getArgument(1);
+
+ mSystemSettingsMap.put(key, value);
+ return null;
+ }
+ ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ int defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Integer.parseInt(storedValue);
+ }
+ ).when(() -> SystemProperties.getInt(anyString(), anyInt()));
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ long defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Long.parseLong(storedValue);
+ }
+ ).when(() -> SystemProperties.getLong(anyString(), anyLong()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ boolean defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+ }
+ ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+ SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(true), false);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT), false);
+
+ mAllocatedWatchdogs = new ArrayList<>();
+ RescuePartyObserver.reset();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ dropShellPermissions();
+ mSession.finishMocking();
+ // Clean up listeners since too many listeners will delay notifications significantly
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.removePropertyChangedListener();
+ }
+ mAllocatedWatchdogs.clear();
+ }
+
+ @Test
+ public void testBootLoopWithRescueParty() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(3);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(4);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(4);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(5);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(5);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(6);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(7);
+ }
+
+ @Test
+ public void testBootLoopWithRollbackPackageHealthObserver() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rollbackObserver).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+ ROLLBACK_INFO_MANUAL));
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rollbackObserver).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ }
+
+ @Test
+ public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ int bootCounter = 0;
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ bootCounter += 1;
+ }
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ verify(rollbackObserver).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+ ROLLBACK_INFO_MANUAL));
+
+ int bootLoopThreshold = PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - bootCounter;
+ for (int i = 0; i < bootLoopThreshold; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(3);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(4);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(4);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(5);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(5);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(6);
+ verify(rollbackObserver).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ // Update the list of available rollbacks after executing bootloop mitigation
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(6);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(7);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ }
+
+ RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
+ RollbackPackageHealthObserver rollbackObserver =
+ spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));
+ when(mSpyContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW,
+ ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL));
+ when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ watchdog.registerHealthObserver(rollbackObserver);
+ return rollbackObserver;
+ }
+
+ RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) {
+ setCrashRecoveryPropRescueBootCount(0);
+ RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext));
+ assertFalse(RescueParty.isRebootPropertySet());
+ watchdog.registerHealthObserver(rescuePartyObserver);
+ return rescuePartyObserver;
+ }
+
+ private static RollbackInfo getRollbackInfo(String packageName, long versionCode,
+ int rollbackId, int rollbackUserImpact) {
+ VersionedPackage appFrom = new VersionedPackage(packageName, versionCode + 1);
+ VersionedPackage appTo = new VersionedPackage(packageName, versionCode);
+ PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appFrom, appTo, null,
+ null, false, false, null);
+ RollbackInfo rollbackInfo = new RollbackInfo(rollbackId, List.of(packageRollbackInfo),
+ false, null, 111, rollbackUserImpact);
+ return rollbackInfo;
+ }
+
+ private void adoptShellPermissions(String... permissions) {
+ androidx.test.platform.app.InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ private void dropShellPermissions() {
+ androidx.test.platform.app.InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+
+ private PackageWatchdog createWatchdog() {
+ return createWatchdog(new TestController(), true /* withPackagesReady */);
+ }
+
+ private PackageWatchdog createWatchdog(TestController controller, boolean withPackagesReady) {
+ AtomicFile policyFile =
+ new AtomicFile(new File(mSpyContext.getFilesDir(), "package-watchdog.xml"));
+ Handler handler = new Handler(mTestLooper.getLooper());
+ PackageWatchdog watchdog =
+ new PackageWatchdog(mSpyContext, policyFile, handler, handler, controller,
+ mConnectivityModuleConnector, mTestClock);
+ mockCrashRecoveryProperties(watchdog);
+
+ // Verify controller is not automatically started
+ assertThat(controller.mIsEnabled).isFalse();
+ if (withPackagesReady) {
+ // Only capture the NetworkStack callback for the latest registered watchdog
+ reset(mConnectivityModuleConnector);
+ watchdog.onPackagesReady();
+ // Verify controller by default is started when packages are ready
+ assertThat(controller.mIsEnabled).isTrue();
+
+ verify(mConnectivityModuleConnector).registerHealthListener(
+ mConnectivityModuleCallbackCaptor.capture());
+ }
+ mAllocatedWatchdogs.add(watchdog);
+ return watchdog;
+ }
+
+ // Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
+ private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+ mCrashRecoveryPropertiesMap = new HashMap<>();
+
+ // mock properties in RescueParty
+ try {
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.attempting_factory_reset", "false");
+ return Boolean.parseBoolean(storedValue);
+ }).when(() -> RescueParty.isFactoryResetPropertySet());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ boolean value = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_factory_reset",
+ Boolean.toString(value));
+ return null;
+ }).when(() -> RescueParty.setFactoryResetProperty(anyBoolean()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.attempting_reboot", "false");
+ return Boolean.parseBoolean(storedValue);
+ }).when(() -> RescueParty.isRebootPropertySet());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ boolean value = invocationOnMock.getArgument(0);
+ setCrashRecoveryPropAttemptingReboot(value);
+ return null;
+ }).when(() -> RescueParty.setRebootProperty(anyBoolean()));
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("persist.crashrecovery.last_factory_reset", "0");
+ return Long.parseLong(storedValue);
+ }).when(() -> RescueParty.getLastFactoryResetTimeMs());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long value = invocationOnMock.getArgument(0);
+ setCrashRecoveryPropLastFactoryReset(value);
+ return null;
+ }).when(() -> RescueParty.setLastFactoryResetTimeMs(anyLong()));
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.max_rescue_level_attempted", "0");
+ return Integer.parseInt(storedValue);
+ }).when(() -> RescueParty.getMaxRescueLevelAttempted());
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int value = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.max_rescue_level_attempted",
+ Integer.toString(value));
+ return null;
+ }).when(() -> RescueParty.setMaxRescueLevelAttempted(anyInt()));
+
+ } catch (Exception e) {
+ // tests will fail, just printing the error
+ System.out.println("Error while mocking crashrecovery properties " + e.getMessage());
+ }
+
+ try {
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.rescue_boot_count", "0");
+ return Integer.parseInt(storedValue);
+ }).when(mSpyBootThreshold).getCount();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_count",
+ Integer.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setCount(anyInt());
+
+ doAnswer((Answer<Integer>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.boot_mitigation_count", "0");
+ return Integer.parseInt(storedValue);
+ }).when(mSpyBootThreshold).getMitigationCount();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ int count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_count",
+ Integer.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setMitigationCount(anyInt());
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.rescue_boot_start", "0");
+ return Long.parseLong(storedValue);
+ }).when(mSpyBootThreshold).getStart();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_start",
+ Long.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setStart(anyLong());
+
+ doAnswer((Answer<Long>) invocationOnMock -> {
+ String storedValue = mCrashRecoveryPropertiesMap
+ .getOrDefault("crashrecovery.boot_mitigation_start", "0");
+ return Long.parseLong(storedValue);
+ }).when(mSpyBootThreshold).getMitigationStart();
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ long count = invocationOnMock.getArgument(0);
+ mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_start",
+ Long.toString(count));
+ return null;
+ }).when(mSpyBootThreshold).setMitigationStart(anyLong());
+
+ Field mBootThresholdField = watchdog.getClass().getDeclaredField("mBootThreshold");
+ mBootThresholdField.setAccessible(true);
+ mBootThresholdField.set(watchdog, mSpyBootThreshold);
+ } catch (Exception e) {
+ // tests will fail, just printing the error
+ System.out.println("Error detected while spying BootThreshold" + e.getMessage());
+ }
+ }
+
+ private void setCrashRecoveryPropRescueBootCount(int count) {
+ mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_count",
+ Integer.toString(count));
+ }
+
+ private void setCrashRecoveryPropAttemptingReboot(boolean value) {
+ mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_reboot",
+ Boolean.toString(value));
+ }
+
+ private void setCrashRecoveryPropLastFactoryReset(long value) {
+ mCrashRecoveryPropertiesMap.put("persist.crashrecovery.last_factory_reset",
+ Long.toString(value));
+ }
+
+ private static class TestController extends ExplicitHealthCheckController {
+ TestController() {
+ super(null /* controller */);
+ }
+
+ private boolean mIsEnabled;
+ private List<String> mSupportedPackages = new ArrayList<>();
+ private List<String> mRequestedPackages = new ArrayList<>();
+ private Consumer<List<PackageConfig>> mSupportedConsumer;
+ private List<Set> mSyncRequests = new ArrayList<>();
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mIsEnabled = enabled;
+ if (!mIsEnabled) {
+ mSupportedPackages.clear();
+ }
+ }
+
+ @Override
+ public void setCallbacks(Consumer<String> passedConsumer,
+ Consumer<List<PackageConfig>> supportedConsumer, Runnable notifySyncRunnable) {
+ mSupportedConsumer = supportedConsumer;
+ }
+
+ @Override
+ public void syncRequests(Set<String> packages) {
+ mSyncRequests.add(packages);
+ mRequestedPackages.clear();
+ if (mIsEnabled) {
+ packages.retainAll(mSupportedPackages);
+ mRequestedPackages.addAll(packages);
+ List<PackageConfig> packageConfigs = new ArrayList<>();
+ for (String packageName: packages) {
+ packageConfigs.add(new PackageConfig(packageName, SHORT_DURATION));
+ }
+ mSupportedConsumer.accept(packageConfigs);
+ } else {
+ mSupportedConsumer.accept(Collections.emptyList());
+ }
+ }
+ }
+
+ private static class TestClock implements PackageWatchdog.SystemClock {
+ // Note 0 is special to the internal clock of PackageWatchdog. We need to start from
+ // a non-zero value in order not to disrupt the logic of PackageWatchdog.
+ private long mUpTimeMillis = 1;
+ @Override
+ public long uptimeMillis() {
+ return mUpTimeMillis;
+ }
+ }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 75284c7..4f27e06 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -36,11 +36,13 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
+import android.crashrecovery.flags.Flags;
import android.net.ConnectivityModuleConnector;
import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
import android.util.Xml;
@@ -54,11 +56,13 @@
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
+import com.android.server.PackageWatchdog.ObserverInternal;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -99,6 +103,10 @@
private static final String OBSERVER_NAME_4 = "observer4";
private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private final TestClock mTestClock = new TestClock();
private TestLooper mTestLooper;
private Context mSpyContext;
@@ -128,6 +136,7 @@
@Before
public void setUp() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
MockitoAnnotations.initMocks(this);
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
@@ -444,6 +453,7 @@
*/
@Test
public void testPackageFailureNotifyAllDifferentImpacts() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
@@ -488,6 +498,52 @@
assertThat(observerLowPackages).containsExactly(APP_A);
}
+ @Test
+ public void testPackageFailureNotifyAllDifferentImpactsRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+ TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ TestObserver observerMid = new TestObserver(OBSERVER_NAME_3,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ TestObserver observerLow = new TestObserver(OBSERVER_NAME_4,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+
+ // Start observing for all impact observers
+ watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerHigh, Arrays.asList(APP_A, APP_B, APP_C),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerMid, Arrays.asList(APP_A, APP_B),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerLow, Arrays.asList(APP_A),
+ SHORT_DURATION);
+
+ // Then fail all apps above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
+ new VersionedPackage(APP_B, VERSION_CODE),
+ new VersionedPackage(APP_C, VERSION_CODE),
+ new VersionedPackage(APP_D, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify least impact observers are notifed of package failures
+ List<String> observerNonePackages = observerNone.mMitigatedPackages;
+ List<String> observerHighPackages = observerHigh.mMitigatedPackages;
+ List<String> observerMidPackages = observerMid.mMitigatedPackages;
+ List<String> observerLowPackages = observerLow.mMitigatedPackages;
+
+ // APP_D failure observed by only observerNone is not caught cos its impact is none
+ assertThat(observerNonePackages).isEmpty();
+ // APP_C failure is caught by observerHigh cos it's the lowest impact observer
+ assertThat(observerHighPackages).containsExactly(APP_C);
+ // APP_B failure is caught by observerMid cos it's the lowest impact observer
+ assertThat(observerMidPackages).containsExactly(APP_B);
+ // APP_A failure is caught by observerLow cos it's the lowest impact observer
+ assertThat(observerLowPackages).containsExactly(APP_A);
+ }
+
/**
* Test package failure and least impact observers are notified successively.
* State transistions:
@@ -501,6 +557,7 @@
*/
@Test
public void testPackageFailureNotifyLeastImpactSuccessively() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
@@ -563,11 +620,76 @@
assertThat(observerSecond.mMitigatedPackages).isEmpty();
}
+ @Test
+ public void testPackageFailureNotifyLeastImpactSuccessivelyRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+ TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+
+ // Start observing for observerFirst and observerSecond with failure handling
+ watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION);
+ watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
+
+ // Then fail APP_A above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerFirst is notifed
+ assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+
+ // After observerFirst handles failure, next action it has is high impact
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_50;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerSecond is notifed cos it has least impact
+ assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerFirst.mMitigatedPackages).isEmpty();
+
+ // After observerSecond handles failure, it has no further actions
+ observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only observerFirst is notifed cos it has the only action
+ assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+
+ // After observerFirst handles failure, it too has no further actions
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+ observerFirst.mMitigatedPackages.clear();
+ observerSecond.mMitigatedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify no observer is notified cos no actions left
+ assertThat(observerFirst.mMitigatedPackages).isEmpty();
+ assertThat(observerSecond.mMitigatedPackages).isEmpty();
+ }
+
/**
* Test package failure and notifies only one observer even with observer impact tie.
*/
@Test
public void testPackageFailureNotifyOneSameImpact() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
@@ -588,6 +710,28 @@
assertThat(observer2.mMitigatedPackages).isEmpty();
}
+ @Test
+ public void testPackageFailureNotifyOneSameImpactRecoverabilityDetection() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+
+ // Start observing for observer1 and observer2 with failure handling
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+ // Then fail APP_A above the threshold
+ raiseFatalFailureAndDispatch(watchdog,
+ Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+ PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ // Verify only one observer is notifed
+ assertThat(observer1.mMitigatedPackages).containsExactly(APP_A);
+ assertThat(observer2.mMitigatedPackages).isEmpty();
+ }
+
/**
* Test package passing explicit health checks does not fail and vice versa.
*/
@@ -818,6 +962,7 @@
@Test
public void testNetworkStackFailure() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
final PackageWatchdog wd = createWatchdog();
// Start observing with failure handling
@@ -835,6 +980,25 @@
assertThat(observer.mMitigatedPackages).containsExactly(APP_A);
}
+ @Test
+ public void testNetworkStackFailureRecoverabilityDetection() {
+ final PackageWatchdog wd = createWatchdog();
+
+ // Start observing with failure handling
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ wd.startObservingHealth(observer, Collections.singletonList(APP_A), SHORT_DURATION);
+
+ // Notify of NetworkStack failure
+ mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A);
+
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify the NetworkStack observer is notified
+ assertThat(observer.mMitigatedPackages).isEmpty();
+ }
+
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerFailureCount() {
@@ -1045,6 +1209,7 @@
/** Ensure that boot loop mitigation is done when the number of boots meets the threshold. */
@Test
public void testBootLoopDetection_meetsThreshold() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
watchdog.registerHealthObserver(bootObserver);
@@ -1054,6 +1219,16 @@
assertThat(bootObserver.mitigatedBootLoop()).isTrue();
}
+ @Test
+ public void testBootLoopDetection_meetsThresholdRecoverability() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isTrue();
+ }
/**
* Ensure that boot loop mitigation is not done when the number of boots does not meet the
@@ -1071,10 +1246,43 @@
}
/**
+ * Ensure that boot loop mitigation is not done when the number of boots does not meet the
+ * threshold.
+ */
+ @Test
+ public void testBootLoopDetection_doesNotMeetThresholdRecoverabilityLowImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isFalse();
+ }
+
+ /**
+ * Ensure that boot loop mitigation is not done when the number of boots does not meet the
+ * threshold.
+ */
+ @Test
+ public void testBootLoopDetection_doesNotMeetThresholdRecoverabilityHighImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver.mitigatedBootLoop()).isFalse();
+ }
+
+ /**
* Ensure that boot loop mitigation is done for the observer with the lowest user impact
*/
@Test
public void testBootLoopMitigationDoneForLowestUserImpact() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1);
bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
@@ -1089,11 +1297,28 @@
assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
}
+ @Test
+ public void testBootLoopMitigationDoneForLowestUserImpactRecoverability() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1);
+ bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10);
+ TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2);
+ bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver1);
+ watchdog.registerHealthObserver(bootObserver2);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD; i++) {
+ watchdog.noteBoot();
+ }
+ assertThat(bootObserver1.mitigatedBootLoop()).isTrue();
+ assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
+ }
+
/**
* Ensure that the correct mitigation counts are sent to the boot loop observer.
*/
@Test
public void testMultipleBootLoopMitigation() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
PackageWatchdog watchdog = createWatchdog();
TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
watchdog.registerHealthObserver(bootObserver);
@@ -1114,6 +1339,64 @@
assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
}
+ @Test
+ public void testMultipleBootLoopMitigationRecoverabilityLowImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_30);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
+ @Test
+ public void testMultipleBootLoopMitigationRecoverabilityHighImpact() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_80);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_THRESHOLD - 1; j++) {
+ watchdog.noteBoot();
+ }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
/**
* Ensure that passing a null list of failed packages does not cause any mitigation logic to
* execute.
@@ -1304,6 +1587,78 @@
}
/**
+ * Ensure that a {@link ObserverInternal} may be correctly written and read in order to persist
+ * across reboots.
+ */
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testWritingAndReadingObserverInternalRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+ MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, mitigationCalls);
+ final int bootMitigationCount = 4;
+ ObserverInternal writeObserver = new ObserverInternal("test", List.of(writePkg),
+ bootMitigationCount);
+
+ // Write the observer
+ File tmpFile = File.createTempFile("observer-watchdog-test", ".xml");
+ AtomicFile testFile = new AtomicFile(tmpFile);
+ FileOutputStream stream = testFile.startWrite();
+ TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+ outputSerializer.startDocument(null, true);
+ writeObserver.writeLocked(outputSerializer);
+ outputSerializer.endDocument();
+ testFile.finishWrite(stream);
+
+ // Read the observer
+ TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+ XmlUtils.beginDocument(parser, "observer");
+ ObserverInternal readObserver = ObserverInternal.read(parser, watchdog);
+
+ assertThat(readObserver.name).isEqualTo(writeObserver.name);
+ assertThat(readObserver.getBootMitigationCount()).isEqualTo(bootMitigationCount);
+ }
+
+ /**
+ * Ensure that boot mitigation counts may be correctly written and read as metadata
+ * in order to persist across reboots.
+ */
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testWritingAndReadingMetadataBootMitigationCountRecoverability() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ String filePath = InstrumentationRegistry.getContext().getFilesDir().toString()
+ + "metadata_file.txt";
+
+ ObserverInternal observer1 = new ObserverInternal("test1", List.of(), 1);
+ ObserverInternal observer2 = new ObserverInternal("test2", List.of(), 2);
+ watchdog.registerObserverInternal(observer1);
+ watchdog.registerObserverInternal(observer2);
+
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+
+ watchdog.saveAllObserversBootMitigationCountToMetadata(filePath);
+
+ observer1.setBootMitigationCount(0);
+ observer2.setBootMitigationCount(0);
+ assertThat(observer1.getBootMitigationCount()).isEqualTo(0);
+ assertThat(observer2.getBootMitigationCount()).isEqualTo(0);
+
+ mSpyBootThreshold.readAllObserversBootMitigationCountIfNecessary(filePath);
+
+ assertThat(observer1.getBootMitigationCount()).isEqualTo(1);
+ assertThat(observer2.getBootMitigationCount()).isEqualTo(2);
+ }
+
+ /**
* Tests device config changes are propagated correctly.
*/
@Test
@@ -1440,11 +1795,19 @@
// Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+ mCrashRecoveryPropertiesMap = new HashMap<>();
+
try {
- mSpyBootThreshold = spy(watchdog.new BootThreshold(
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
- PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
- mCrashRecoveryPropertiesMap = new HashMap<>();
+ if (Flags.recoverabilityDetection()) {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_MITIGATION_INCREMENT));
+ } else {
+ mSpyBootThreshold = spy(watchdog.new BootThreshold(
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+ PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+ }
doAnswer((Answer<Integer>) invocationOnMock -> {
String storedValue = mCrashRecoveryPropertiesMap
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
index 867c0a6..a5ce69d 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
@@ -27,6 +27,7 @@
import com.android.bedstead.harrier.DeviceState;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +35,7 @@
@RunWith(BedsteadJUnit4.class)
public final class ConcurrentMultiUserTest {
+ @ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index 1d7be2f..5107943 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -333,6 +333,7 @@
public void testHandleLossRate_validationFail() throws Exception {
checkHandleLossRate(
22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
+ verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index 381c574..444208e 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.IpSecConfig;
import android.net.IpSecTransform;
import android.net.LinkProperties;
@@ -33,12 +34,14 @@
import android.net.NetworkCapabilities;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.FeatureFlags;
+import android.net.vcn.Flags;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.ParcelUuid;
import android.os.PowerManager;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyManager;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -46,6 +49,7 @@
import com.android.server.vcn.VcnNetworkProvider;
import org.junit.Before;
+import org.junit.Rule;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -53,6 +57,8 @@
import java.util.UUID;
public abstract class NetworkEvaluationTestBase {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
protected static final String SSID = "TestWifi";
protected static final String SSID_OTHER = "TestWifiOther";
protected static final String PLMN_ID = "123456";
@@ -103,6 +109,7 @@
@Mock protected FeatureFlags mFeatureFlags;
@Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
@Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+ @Mock protected ConnectivityManager mConnectivityManager;
@Mock protected TelephonyManager mTelephonyManager;
@Mock protected IPowerManager mPowerManagerService;
@@ -114,6 +121,8 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS);
+
when(mNetwork.getNetId()).thenReturn(-1);
mTestLooper = new TestLooper();
@@ -130,6 +139,12 @@
doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled();
setupSystemService(
+ mContext,
+ mConnectivityManager,
+ Context.CONNECTIVITY_SERVICE,
+ ConnectivityManager.class);
+
+ setupSystemService(
mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
diff --git a/tools/app_metadata_bundles/Android.bp b/tools/app_metadata_bundles/Android.bp
new file mode 100644
index 0000000..be6bea6
--- /dev/null
+++ b/tools/app_metadata_bundles/Android.bp
@@ -0,0 +1,26 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library_host {
+ name: "asllib",
+ srcs: [
+ "src/lib/java/**/*.java",
+ ],
+}
+
+java_binary_host {
+ name: "aslgen",
+ manifest: "src/aslgen/aslgen.mf",
+ srcs: [
+ "src/aslgen/java/**/*.java",
+ ],
+ static_libs: [
+ "asllib",
+ ],
+}
diff --git a/tools/app_metadata_bundles/OWNERS b/tools/app_metadata_bundles/OWNERS
new file mode 100644
index 0000000..a2a250b
--- /dev/null
+++ b/tools/app_metadata_bundles/OWNERS
@@ -0,0 +1,2 @@
+wenhaowang@google.com
+mloh@google.com
diff --git a/tools/app_metadata_bundles/README.md b/tools/app_metadata_bundles/README.md
new file mode 100644
index 0000000..6e8d287
--- /dev/null
+++ b/tools/app_metadata_bundles/README.md
@@ -0,0 +1,9 @@
+# App metadata bundles
+
+This project delivers a comprehensive toolchain solution for developers
+to efficiently manage app metadata bundles.
+
+The project consists of two subprojects:
+
+ * A pure Java library, and
+ * A pure Java command-line tool.
diff --git a/tools/app_metadata_bundles/src/aslgen/aslgen.mf b/tools/app_metadata_bundles/src/aslgen/aslgen.mf
new file mode 100644
index 0000000..fc656e2
--- /dev/null
+++ b/tools/app_metadata_bundles/src/aslgen/aslgen.mf
@@ -0,0 +1 @@
+Main-Class: com.android.aslgen.Main
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java
new file mode 100644
index 0000000..fb7a6ab
--- /dev/null
+++ b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java
@@ -0,0 +1,115 @@
+/*
+ * 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.aslgen;
+
+import com.android.asllib.AndroidSafetyLabel;
+import com.android.asllib.AndroidSafetyLabel.Format;
+import com.android.asllib.util.MalformedXmlException;
+
+import org.xml.sax.SAXException;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+public class Main {
+
+ /** Takes the options to make file conversion. */
+ public static void main(String[] args)
+ throws IOException,
+ ParserConfigurationException,
+ SAXException,
+ TransformerException,
+ MalformedXmlException {
+
+ String inFile = null;
+ String outFile = null;
+ Format inFormat = Format.NULL;
+ Format outFormat = Format.NULL;
+
+
+ // Except for "--help", all arguments require a value currently.
+ // So just make sure we have an even number and
+ // then process them all two at a time.
+ if (args.length == 1 && "--help".equals(args[0])) {
+ showUsage();
+ return;
+ }
+ if (args.length % 2 != 0) {
+ throw new IllegalArgumentException("Argument is missing corresponding value");
+ }
+ for (int i = 0; i < args.length - 1; i += 2) {
+ final String arg = args[i].trim();
+ final String argValue = args[i + 1].trim();
+ if ("--in-path".equals(arg)) {
+ inFile = argValue;
+ } else if ("--out-path".equals(arg)) {
+ outFile = argValue;
+ } else if ("--in-format".equals(arg)) {
+ inFormat = getFormat(argValue);
+ } else if ("--out-format".equals(arg)) {
+ outFormat = getFormat(argValue);
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+
+ if (inFile == null) {
+ throw new IllegalArgumentException("input file is required");
+ }
+
+ if (outFile == null) {
+ throw new IllegalArgumentException("output file is required");
+ }
+
+ if (inFormat == Format.NULL) {
+ throw new IllegalArgumentException("input format is required");
+ }
+
+ if (outFormat == Format.NULL) {
+ throw new IllegalArgumentException("output format is required");
+ }
+
+ System.out.println("in path: " + inFile);
+ System.out.println("out path: " + outFile);
+ System.out.println("in format: " + inFormat);
+ System.out.println("out format: " + outFormat);
+
+ var asl = AndroidSafetyLabel.readFromStream(new FileInputStream(inFile), inFormat);
+ asl.writeToStream(new FileOutputStream(outFile), outFormat);
+ }
+
+ private static Format getFormat(String argValue) {
+ if ("hr".equals(argValue)) {
+ return Format.HUMAN_READABLE;
+ } else if ("od".equals(argValue)) {
+ return Format.ON_DEVICE;
+ } else {
+ return Format.NULL;
+ }
+ }
+
+ private static void showUsage() {
+ AndroidSafetyLabel.test();
+ System.err.println(
+ "Usage:\n"
+ );
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
new file mode 100644
index 0000000..bc8063e
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
@@ -0,0 +1,122 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+public class AndroidSafetyLabel implements AslMarshallable {
+
+ public enum Format {
+ NULL, HUMAN_READABLE, ON_DEVICE;
+ }
+
+ private final SafetyLabels mSafetyLabels;
+
+ public SafetyLabels getSafetyLabels() {
+ return mSafetyLabels;
+ }
+
+ public AndroidSafetyLabel(SafetyLabels safetyLabels) {
+ this.mSafetyLabels = safetyLabels;
+ }
+
+ /** Reads a {@link AndroidSafetyLabel} from an {@link InputStream}. */
+ // TODO(b/329902686): Support parsing from on-device.
+ public static AndroidSafetyLabel readFromStream(InputStream in, Format format)
+ throws IOException, ParserConfigurationException, SAXException, MalformedXmlException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ Document document = factory.newDocumentBuilder().parse(in);
+
+ switch (format) {
+ case HUMAN_READABLE:
+ Element appMetadataBundles =
+ XmlUtils.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES);
+
+ return new AndroidSafetyLabelFactory()
+ .createFromHrElements(
+ List.of(
+ XmlUtils.getSingleElement(
+ document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES)));
+ case ON_DEVICE:
+ throw new IllegalArgumentException(
+ "Parsing from on-device format is not supported at this time.");
+ default:
+ throw new IllegalStateException("Unrecognized input format.");
+ }
+ }
+
+ /** Write the content of the {@link AndroidSafetyLabel} to a {@link OutputStream}. */
+ // TODO(b/329902686): Support outputting human-readable format.
+ public void writeToStream(OutputStream out, Format format)
+ throws IOException, ParserConfigurationException, TransformerException {
+ var docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ var document = docBuilder.newDocument();
+
+ switch (format) {
+ case HUMAN_READABLE:
+ throw new IllegalArgumentException(
+ "Outputting human-readable format is not supported at this time.");
+ case ON_DEVICE:
+ for (var child : this.toOdDomElements(document)) {
+ document.appendChild(child);
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unrecognized input format.");
+ }
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ StreamResult streamResult = new StreamResult(out); // out
+ DOMSource domSource = new DOMSource(document);
+ transformer.transform(domSource, streamResult);
+ }
+
+ /** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */
+ @Override
+ public List<Element> toOdDomElements(Document doc) {
+ Element aslEle = doc.createElement(XmlUtils.OD_TAG_BUNDLE);
+ XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc));
+ return List.of(aslEle);
+ }
+
+ public static void test() {
+ // TODO(b/329902686): Add tests.
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
new file mode 100644
index 0000000..7e7fcf9
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> {
+
+ /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
+ @Override
+ public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles)
+ throws MalformedXmlException {
+ Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles);
+ Element safetyLabelsEle =
+ XmlUtils.getSingleChildElement(
+ appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS);
+ SafetyLabels safetyLabels =
+ new SafetyLabelsFactory().createFromHrElements(List.of(safetyLabelsEle));
+ return new AndroidSafetyLabel(safetyLabels);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallable.java
new file mode 100644
index 0000000..4e64ab0
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallable.java
@@ -0,0 +1,28 @@
+/*
+ * 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.asllib;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public interface AslMarshallable {
+
+ /** Creates the on-device DOM element from the AslMarshallable Java Object. */
+ List<Element> toOdDomElements(Document doc);
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java
new file mode 100644
index 0000000..b8f9f0e
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java
@@ -0,0 +1,29 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public interface AslMarshallableFactory<T extends AslMarshallable> {
+
+ /** Creates an {@link AslMarshallableFactory} from human-readable DOM element */
+ T createFromHrElements(List<Element> elements) throws MalformedXmlException;
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java
new file mode 100644
index 0000000..e5ed63b
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.asllib;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Data usage category representation containing one or more {@link DataType}. Valid category keys
+ * are defined in {@link DataCategoryConstants}, each category has a valid set of types {@link
+ * DataType}, which are mapped in {@link DataTypeConstants}
+ */
+public class DataCategory implements AslMarshallable {
+ private final String mCategoryName;
+ private final Map<String, DataType> mDataTypes;
+
+ public DataCategory(String categoryName, Map<String, DataType> dataTypes) {
+ this.mCategoryName = categoryName;
+ this.mDataTypes = dataTypes;
+ }
+
+ public String getCategoryName() {
+ return mCategoryName;
+ }
+
+ /** Return the type {@link Map} of String type key to {@link DataType} */
+
+ public Map<String, DataType> getDataTypes() {
+ return mDataTypes;
+ }
+
+ /** Creates on-device DOM element(s) from the {@link DataCategory}. */
+ @Override
+ public List<Element> toOdDomElements(Document doc) {
+ Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, this.getCategoryName());
+ for (DataType dataType : mDataTypes.values()) {
+ XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
+ }
+ return List.of(dataCategoryEle);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryConstants.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryConstants.java
new file mode 100644
index 0000000..b364c8b
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryConstants.java
@@ -0,0 +1,74 @@
+/*
+ * 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.asllib;
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Constants for determining valid {@link String} data types for usage within {@link SafetyLabels},
+ * {@link DataCategory}, and {@link DataType}
+ */
+public class DataCategoryConstants {
+
+ public static final String CATEGORY_PERSONAL = "personal";
+ public static final String CATEGORY_FINANCIAL = "financial";
+ public static final String CATEGORY_LOCATION = "location";
+ public static final String CATEGORY_EMAIL_TEXT_MESSAGE = "email_text_message";
+ public static final String CATEGORY_PHOTO_VIDEO = "photo_video";
+ public static final String CATEGORY_AUDIO = "audio";
+ public static final String CATEGORY_STORAGE = "storage";
+ public static final String CATEGORY_HEALTH_FITNESS = "health_fitness";
+ public static final String CATEGORY_CONTACTS = "contacts";
+ public static final String CATEGORY_CALENDAR = "calendar";
+ public static final String CATEGORY_IDENTIFIERS = "identifiers";
+ public static final String CATEGORY_APP_PERFORMANCE = "app_performance";
+ public static final String CATEGORY_ACTIONS_IN_APP = "actions_in_app";
+ public static final String CATEGORY_SEARCH_AND_BROWSING = "search_and_browsing";
+
+ /** Set of valid categories */
+ public static final Set<String> VALID_CATEGORIES =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ CATEGORY_PERSONAL,
+ CATEGORY_FINANCIAL,
+ CATEGORY_LOCATION,
+ CATEGORY_EMAIL_TEXT_MESSAGE,
+ CATEGORY_PHOTO_VIDEO,
+ CATEGORY_AUDIO,
+ CATEGORY_STORAGE,
+ CATEGORY_HEALTH_FITNESS,
+ CATEGORY_CONTACTS,
+ CATEGORY_CALENDAR,
+ CATEGORY_IDENTIFIERS,
+ CATEGORY_APP_PERFORMANCE,
+ CATEGORY_ACTIONS_IN_APP,
+ CATEGORY_SEARCH_AND_BROWSING)));
+
+ /** Returns {@link Set} of valid {@link String} category keys */
+ public static Set<String> getValidDataCategories() {
+ return VALID_CATEGORIES;
+ }
+
+ private DataCategoryConstants() {
+ /* do nothing - hide constructor */
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
new file mode 100644
index 0000000..d946345
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DataCategoryFactory implements AslMarshallableFactory<DataCategory> {
+ @Override
+ public DataCategory createFromHrElements(List<Element> elements) throws MalformedXmlException {
+ String categoryName = null;
+ Map<String, DataType> dataTypeMap = new HashMap<String, DataType>();
+ for (Element ele : elements) {
+ categoryName = ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY);
+ String dataTypeName = ele.getAttribute(XmlUtils.HR_ATTR_DATA_TYPE);
+ if (!DataTypeConstants.getValidDataTypes().contains(dataTypeName)) {
+ throw new MalformedXmlException(
+ String.format("Unrecognized data type name: %s", dataTypeName));
+ }
+ dataTypeMap.put(dataTypeName, new DataTypeFactory().createFromHrElements(List.of(ele)));
+ }
+
+ return new DataCategory(categoryName, dataTypeMap);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java
new file mode 100644
index 0000000..d2fffc0
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java
@@ -0,0 +1,101 @@
+/*
+ * 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.asllib;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Data label representation with data shared and data collected maps containing zero or more {@link
+ * DataCategory}
+ */
+public class DataLabels implements AslMarshallable {
+ private final Map<String, DataCategory> mDataAccessed;
+ private final Map<String, DataCategory> mDataCollected;
+ private final Map<String, DataCategory> mDataShared;
+
+ public DataLabels(
+ Map<String, DataCategory> dataAccessed,
+ Map<String, DataCategory> dataCollected,
+ Map<String, DataCategory> dataShared) {
+ mDataAccessed = dataAccessed;
+ mDataCollected = dataCollected;
+ mDataShared = dataShared;
+ }
+
+ /**
+ * Returns the data accessed {@link Map} of {@link com.android.asllib.DataCategoryConstants} to
+ * {@link DataCategory}
+ */
+ public Map<String, DataCategory> getDataAccessed() {
+ return mDataAccessed;
+ }
+
+ /**
+ * Returns the data collected {@link Map} of {@link com.android.asllib.DataCategoryConstants} to
+ * {@link DataCategory}
+ */
+ public Map<String, DataCategory> getDataCollected() {
+ return mDataCollected;
+ }
+
+ /**
+ * Returns the data shared {@link Map} of {@link com.android.asllib.DataCategoryConstants} to
+ * {@link DataCategory}
+ */
+ public Map<String, DataCategory> getDataShared() {
+ return mDataShared;
+ }
+
+ /** Gets the on-device DOM element for the {@link DataLabels}. */
+ @Override
+ public List<Element> toOdDomElements(Document doc) {
+ Element dataLabelsEle =
+ XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DATA_LABELS);
+
+ maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_ACCESSED);
+ maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_COLLECTED);
+ maybeAppendDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.OD_NAME_DATA_SHARED);
+
+ return List.of(dataLabelsEle);
+ }
+
+ private void maybeAppendDataUsages(
+ Document doc,
+ Element dataLabelsEle,
+ Map<String, DataCategory> dataCategoriesMap,
+ String dataUsageTypeName) {
+ if (dataCategoriesMap.isEmpty()) {
+ return;
+ }
+ Element dataUsageEle = XmlUtils.createPbundleEleWithName(doc, dataUsageTypeName);
+
+ for (String dataCategoryName : dataCategoriesMap.keySet()) {
+ Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, dataCategoryName);
+ DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName);
+ for (String dataTypeName : dataCategory.getDataTypes().keySet()) {
+ DataType dataType = dataCategory.getDataTypes().get(dataTypeName);
+ XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
+ }
+ dataUsageEle.appendChild(dataCategoryEle);
+ }
+ dataLabelsEle.appendChild(dataUsageEle);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
new file mode 100644
index 0000000..1adb140
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
@@ -0,0 +1,117 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {
+
+ /** Creates a {@link DataLabels} from the human-readable DOM element. */
+ @Override
+ public DataLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
+ Element ele = XmlUtils.getSingleElement(elements);
+ Map<String, DataCategory> dataAccessed =
+ getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_ACCESSED);
+ Map<String, DataCategory> dataCollected =
+ getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED);
+ Map<String, DataCategory> dataShared =
+ getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_SHARED);
+
+ // Validate booleans such as isCollectionOptional, isSharingOptional.
+ for (DataCategory dataCategory : dataAccessed.values()) {
+ for (DataType dataType : dataCategory.getDataTypes().values()) {
+ if (dataType.getIsSharingOptional() != null) {
+ throw new MalformedXmlException(
+ String.format(
+ "isSharingOptional was unexpectedly defined on a DataType"
+ + " belonging to data accessed: %s",
+ dataType.getDataTypeName()));
+ }
+ if (dataType.getIsCollectionOptional() != null) {
+ throw new MalformedXmlException(
+ String.format(
+ "isCollectionOptional was unexpectedly defined on a DataType"
+ + " belonging to data accessed: %s",
+ dataType.getDataTypeName()));
+ }
+ }
+ }
+ for (DataCategory dataCategory : dataCollected.values()) {
+ for (DataType dataType : dataCategory.getDataTypes().values()) {
+ if (dataType.getIsSharingOptional() != null) {
+ throw new MalformedXmlException(
+ String.format(
+ "isSharingOptional was unexpectedly defined on a DataType"
+ + " belonging to data collected: %s",
+ dataType.getDataTypeName()));
+ }
+ }
+ }
+ for (DataCategory dataCategory : dataShared.values()) {
+ for (DataType dataType : dataCategory.getDataTypes().values()) {
+ if (dataType.getIsCollectionOptional() != null) {
+ throw new MalformedXmlException(
+ String.format(
+ "isCollectionOptional was unexpectedly defined on a DataType"
+ + " belonging to data shared: %s",
+ dataType.getDataTypeName()));
+ }
+ }
+ }
+
+ return new DataLabels(dataAccessed, dataCollected, dataShared);
+ }
+
+ private static Map<String, DataCategory> getDataCategoriesWithTag(
+ Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException {
+ NodeList dataUsedNodeList = dataLabelsEle.getElementsByTagName(dataCategoryUsageTypeTag);
+ Map<String, DataCategory> dataCategoryMap = new HashMap<String, DataCategory>();
+
+ Set<String> dataCategoryNames = new HashSet<String>();
+ for (int i = 0; i < dataUsedNodeList.getLength(); i++) {
+ Element dataUsedEle = (Element) dataUsedNodeList.item(i);
+ String dataCategoryName = dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY);
+ if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) {
+ throw new MalformedXmlException(
+ String.format("Unrecognized category name: %s", dataCategoryName));
+ }
+ dataCategoryNames.add(dataCategoryName);
+ }
+ for (String dataCategoryName : dataCategoryNames) {
+ var dataCategoryElements =
+ XmlUtils.asElementList(dataUsedNodeList).stream()
+ .filter(
+ ele ->
+ ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY)
+ .equals(dataCategoryName))
+ .toList();
+ DataCategory dataCategory =
+ new DataCategoryFactory().createFromHrElements(dataCategoryElements);
+ dataCategoryMap.put(dataCategoryName, dataCategory);
+ }
+ return dataCategoryMap;
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java
new file mode 100644
index 0000000..5ba2975
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java
@@ -0,0 +1,176 @@
+/*
+ * 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.asllib;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Data usage type representation. Types are specific to a {@link DataCategory} and contains
+ * metadata related to the data usage purpose.
+ */
+public class DataType implements AslMarshallable {
+
+ public enum Purpose {
+ PURPOSE_APP_FUNCTIONALITY(1),
+ PURPOSE_ANALYTICS(2),
+ PURPOSE_DEVELOPER_COMMUNICATIONS(3),
+ PURPOSE_FRAUD_PREVENTION_SECURITY(4),
+ PURPOSE_ADVERTISING(5),
+ PURPOSE_PERSONALIZATION(6),
+ PURPOSE_ACCOUNT_MANAGEMENT(7);
+
+ private static final String PURPOSE_PREFIX = "PURPOSE_";
+
+ private final int mValue;
+
+ Purpose(int value) {
+ this.mValue = value;
+ }
+
+ /** Get the int value associated with the Purpose. */
+ public int getValue() {
+ return mValue;
+ }
+
+ /** Get the Purpose associated with the int value. */
+ public static Purpose forValue(int value) {
+ for (Purpose e : values()) {
+ if (e.getValue() == value) {
+ return e;
+ }
+ }
+ throw new IllegalArgumentException("No enum for value: " + value);
+ }
+
+ /** Get the Purpose associated with the human-readable String. */
+ public static Purpose forString(String s) {
+ for (Purpose e : values()) {
+ if (e.toString().equals(s)) {
+ return e;
+ }
+ }
+ throw new IllegalArgumentException("No enum for str: " + s);
+ }
+
+ /** Human-readable String representation of Purpose. */
+ public String toString() {
+ if (!this.name().startsWith(PURPOSE_PREFIX)) {
+ return this.name();
+ }
+ return this.name().substring(PURPOSE_PREFIX.length()).toLowerCase();
+ }
+ }
+
+ private final String mDataTypeName;
+
+ private final Set<Purpose> mPurposeSet;
+ private final Boolean mIsCollectionOptional;
+ private final Boolean mIsSharingOptional;
+ private final Boolean mEphemeral;
+
+ public DataType(
+ String dataTypeName,
+ Set<Purpose> purposeSet,
+ Boolean isCollectionOptional,
+ Boolean isSharingOptional,
+ Boolean ephemeral) {
+ this.mDataTypeName = dataTypeName;
+ this.mPurposeSet = purposeSet;
+ this.mIsCollectionOptional = isCollectionOptional;
+ this.mIsSharingOptional = isSharingOptional;
+ this.mEphemeral = ephemeral;
+ }
+
+ public String getDataTypeName() {
+ return mDataTypeName;
+ }
+
+ /**
+ * Returns {@link Set} of valid {@link Integer} purposes for using the associated data category
+ * and type
+ */
+ public Set<Purpose> getPurposeSet() {
+ return mPurposeSet;
+ }
+
+ /**
+ * For data-collected, returns {@code true} if data usage is user optional and {@code false} if
+ * data usage is required. Should return {@code null} for data-accessed and data-shared.
+ */
+ public Boolean getIsCollectionOptional() {
+ return mIsCollectionOptional;
+ }
+
+ /**
+ * For data-shared, returns {@code true} if data usage is user optional and {@code false} if
+ * data usage is required. Should return {@code null} for data-accessed and data-collected.
+ */
+ public Boolean getIsSharingOptional() {
+ return mIsSharingOptional;
+ }
+
+ /**
+ * For data-collected, returns {@code true} if data usage is user optional and {@code false} if
+ * data usage is processed ephemerally. Should return {@code null} for data-shared.
+ */
+ public Boolean getEphemeral() {
+ return mEphemeral;
+ }
+
+ @Override
+ public List<Element> toOdDomElements(Document doc) {
+ Element dataTypeEle = XmlUtils.createPbundleEleWithName(doc, this.getDataTypeName());
+ if (!this.getPurposeSet().isEmpty()) {
+ Element purposesEle = doc.createElement(XmlUtils.OD_TAG_INT_ARRAY);
+ purposesEle.setAttribute(XmlUtils.OD_ATTR_NAME, XmlUtils.OD_NAME_PURPOSES);
+ purposesEle.setAttribute(
+ XmlUtils.OD_ATTR_NUM, String.valueOf(this.getPurposeSet().size()));
+ for (DataType.Purpose purpose : this.getPurposeSet()) {
+ Element purposeEle = doc.createElement(XmlUtils.OD_TAG_ITEM);
+ purposeEle.setAttribute(XmlUtils.OD_ATTR_VALUE, String.valueOf(purpose.getValue()));
+ purposesEle.appendChild(purposeEle);
+ }
+ dataTypeEle.appendChild(purposesEle);
+ }
+
+ maybeAddBoolToOdElement(
+ doc,
+ dataTypeEle,
+ this.getIsCollectionOptional(),
+ XmlUtils.OD_NAME_IS_COLLECTION_OPTIONAL);
+ maybeAddBoolToOdElement(
+ doc,
+ dataTypeEle,
+ this.getIsSharingOptional(),
+ XmlUtils.OD_NAME_IS_SHARING_OPTIONAL);
+ maybeAddBoolToOdElement(doc, dataTypeEle, this.getEphemeral(), XmlUtils.OD_NAME_EPHEMERAL);
+ return List.of(dataTypeEle);
+ }
+
+ private static void maybeAddBoolToOdElement(
+ Document doc, Element parentEle, Boolean b, String odName) {
+ if (b == null) {
+ return;
+ }
+ Element ele = XmlUtils.createOdBooleanEle(doc, odName, b);
+ parentEle.appendChild(ele);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeConstants.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeConstants.java
new file mode 100644
index 0000000..a0a7537
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeConstants.java
@@ -0,0 +1,156 @@
+/*
+ * 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.asllib;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Constants for determining valid {@link String} data types for usage within {@link SafetyLabels},
+ * {@link DataCategory}, and {@link DataType}
+ */
+public class DataTypeConstants {
+ /** Data types for {@link DataCategoryConstants.CATEGORY_PERSONAL} */
+ public static final String TYPE_NAME = "name";
+
+ public static final String TYPE_EMAIL_ADDRESS = "email_address";
+ public static final String TYPE_PHONE_NUMBER = "phone_number";
+ public static final String TYPE_RACE_ETHNICITY = "race_ethnicity";
+ public static final String TYPE_POLITICAL_OR_RELIGIOUS_BELIEFS =
+ "political_or_religious_beliefs";
+ public static final String TYPE_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY =
+ "sexual_orientation_or_gender_identity";
+ public static final String TYPE_PERSONAL_IDENTIFIERS = "personal_identifiers";
+ public static final String TYPE_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_FINANCIAL} */
+ public static final String TYPE_CARD_BANK_ACCOUNT = "card_bank_account";
+
+ public static final String TYPE_PURCHASE_HISTORY = "purchase_history";
+ public static final String TYPE_CREDIT_SCORE = "credit_score";
+ public static final String TYPE_FINANCIAL_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_LOCATION} */
+ public static final String TYPE_APPROX_LOCATION = "approx_location";
+
+ public static final String TYPE_PRECISE_LOCATION = "precise_location";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_EMAIL_TEXT_MESSAGE} */
+ public static final String TYPE_EMAILS = "emails";
+
+ public static final String TYPE_TEXT_MESSAGES = "text_messages";
+ public static final String TYPE_EMAIL_TEXT_MESSAGE_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_PHOTO_VIDEO} */
+ public static final String TYPE_PHOTOS = "photos";
+
+ public static final String TYPE_VIDEOS = "videos";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_AUDIO} */
+ public static final String TYPE_SOUND_RECORDINGS = "sound_recordings";
+
+ public static final String TYPE_MUSIC_FILES = "music_files";
+ public static final String TYPE_AUDIO_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_STORAGE} */
+ public static final String TYPE_FILES_DOCS = "files_docs";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_HEALTH_FITNESS} */
+ public static final String TYPE_HEALTH = "health";
+
+ public static final String TYPE_FITNESS = "fitness";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_CONTACTS} */
+ public static final String TYPE_CONTACTS = "contacts";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_CALENDAR} */
+ public static final String TYPE_CALENDAR = "calendar";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_IDENTIFIERS} */
+ public static final String TYPE_IDENTIFIERS_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_APP_PERFORMANCE} */
+ public static final String TYPE_CRASH_LOGS = "crash_logs";
+
+ public static final String TYPE_PERFORMANCE_DIAGNOSTICS = "performance_diagnostics";
+ public static final String TYPE_APP_PERFORMANCE_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_ACTIONS_IN_APP} */
+ public static final String TYPE_USER_INTERACTION = "user_interaction";
+
+ public static final String TYPE_IN_APP_SEARCH_HISTORY = "in_app_search_history";
+ public static final String TYPE_INSTALLED_APPS = "installed_apps";
+ public static final String TYPE_USER_GENERATED_CONTENT = "user_generated_content";
+ public static final String TYPE_ACTIONS_IN_APP_OTHER = "other";
+
+ /** Data types for {@link DataCategoryConstants.CATEGORY_SEARCH_AND_BROWSING} */
+ public static final String TYPE_WEB_BROWSING_HISTORY = "web_browsing_history";
+
+ /** Set of valid categories */
+ public static final Set<String> VALID_TYPES =
+ Collections.unmodifiableSet(
+ new HashSet<>(
+ Arrays.asList(
+ TYPE_NAME,
+ TYPE_EMAIL_ADDRESS,
+ TYPE_PHONE_NUMBER,
+ TYPE_RACE_ETHNICITY,
+ TYPE_POLITICAL_OR_RELIGIOUS_BELIEFS,
+ TYPE_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY,
+ TYPE_PERSONAL_IDENTIFIERS,
+ TYPE_OTHER,
+ TYPE_CARD_BANK_ACCOUNT,
+ TYPE_PURCHASE_HISTORY,
+ TYPE_CREDIT_SCORE,
+ TYPE_FINANCIAL_OTHER,
+ TYPE_APPROX_LOCATION,
+ TYPE_PRECISE_LOCATION,
+ TYPE_EMAILS,
+ TYPE_TEXT_MESSAGES,
+ TYPE_EMAIL_TEXT_MESSAGE_OTHER,
+ TYPE_PHOTOS,
+ TYPE_VIDEOS,
+ TYPE_SOUND_RECORDINGS,
+ TYPE_MUSIC_FILES,
+ TYPE_AUDIO_OTHER,
+ TYPE_FILES_DOCS,
+ TYPE_HEALTH,
+ TYPE_FITNESS,
+ TYPE_CONTACTS,
+ TYPE_CALENDAR,
+ TYPE_IDENTIFIERS_OTHER,
+ TYPE_CRASH_LOGS,
+ TYPE_PERFORMANCE_DIAGNOSTICS,
+ TYPE_APP_PERFORMANCE_OTHER,
+ TYPE_USER_INTERACTION,
+ TYPE_IN_APP_SEARCH_HISTORY,
+ TYPE_INSTALLED_APPS,
+ TYPE_USER_GENERATED_CONTENT,
+ TYPE_ACTIONS_IN_APP_OTHER,
+ TYPE_WEB_BROWSING_HISTORY)));
+
+ /** Returns {@link Set} of valid {@link String} category keys */
+ public static Set<String> getValidDataTypes() {
+ return VALID_TYPES;
+ }
+
+ private DataTypeConstants() {
+ /* do nothing - hide constructor */
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
new file mode 100644
index 0000000..e3d1587
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.asllib;
+
+import org.w3c.dom.Element;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class DataTypeFactory implements AslMarshallableFactory<DataType> {
+ /** Creates a {@link DataType} from the human-readable DOM element. */
+ @Override
+ public DataType createFromHrElements(List<Element> elements) {
+ Element hrDataTypeEle = XmlUtils.getSingleElement(elements);
+ String dataTypeName = hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_DATA_TYPE);
+ Set<DataType.Purpose> purposeSet =
+ Arrays.stream(hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_PURPOSES).split("\\|"))
+ .map(DataType.Purpose::forString)
+ .collect(Collectors.toUnmodifiableSet());
+ Boolean isCollectionOptional =
+ XmlUtils.fromString(
+ hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL));
+ Boolean isSharingOptional =
+ XmlUtils.fromString(
+ hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL));
+ Boolean ephemeral =
+ XmlUtils.fromString(hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_EPHEMERAL));
+ return new DataType(
+ dataTypeName, purposeSet, isCollectionOptional, isSharingOptional, ephemeral);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java
new file mode 100644
index 0000000..f06522f
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java
@@ -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.asllib;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+/** Safety Label representation containing zero or more {@link DataCategory} for data shared */
+public class SafetyLabels implements AslMarshallable {
+
+ private final Long mVersion;
+ private final DataLabels mDataLabels;
+
+ public SafetyLabels(Long version, DataLabels dataLabels) {
+ this.mVersion = version;
+ this.mDataLabels = dataLabels;
+ }
+
+ /** Returns the data label for the safety label */
+ public DataLabels getDataLabel() {
+ return mDataLabels;
+ }
+
+ /** Gets the version of the {@link SafetyLabels}. */
+ public Long getVersion() {
+ return mVersion;
+ }
+
+ /** Creates an on-device DOM element from the {@link SafetyLabels}. */
+ @Override
+ public List<Element> toOdDomElements(Document doc) {
+ Element safetyLabelsEle =
+ XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS);
+ XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
+ return List.of(safetyLabelsEle);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
new file mode 100644
index 0000000..80b9f57
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels> {
+
+ /** Creates a {@link SafetyLabels} from the human-readable DOM element. */
+ @Override
+ public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
+ Element safetyLabelsEle = XmlUtils.getSingleElement(elements);
+ Long version;
+ try {
+ version = Long.parseLong(safetyLabelsEle.getAttribute(XmlUtils.HR_ATTR_VERSION));
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Malformed or missing required version in safety labels.");
+ }
+
+ DataLabels dataLabels =
+ new DataLabelsFactory()
+ .createFromHrElements(
+ List.of(
+ XmlUtils.getSingleChildElement(
+ safetyLabelsEle, XmlUtils.HR_TAG_DATA_LABELS)));
+ return new SafetyLabels(version, dataLabels);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
new file mode 100644
index 0000000..3bc9ccc
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
@@ -0,0 +1,158 @@
+/*
+ * 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.asllib;
+
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlUtils {
+ public static final String HR_TAG_APP_METADATA_BUNDLES = "app-metadata-bundles";
+ public static final String HR_TAG_SAFETY_LABELS = "safety-labels";
+ public static final String HR_TAG_DATA_LABELS = "data-labels";
+ public static final String HR_TAG_DATA_ACCESSED = "data-accessed";
+ public static final String HR_TAG_DATA_COLLECTED = "data-collected";
+ public static final String HR_TAG_DATA_SHARED = "data-shared";
+
+ public static final String HR_ATTR_DATA_CATEGORY = "dataCategory";
+ public static final String HR_ATTR_DATA_TYPE = "dataType";
+ public static final String HR_ATTR_IS_COLLECTION_OPTIONAL = "isCollectionOptional";
+ public static final String HR_ATTR_IS_SHARING_OPTIONAL = "isSharingOptional";
+ public static final String HR_ATTR_EPHEMERAL = "ephemeral";
+ public static final String HR_ATTR_PURPOSES = "purposes";
+ public static final String HR_ATTR_VERSION = "version";
+
+ public static final String OD_TAG_BUNDLE = "bundle";
+ public static final String OD_TAG_PBUNDLE_AS_MAP = "pbundle_as_map";
+ public static final String OD_TAG_BOOLEAN = "boolean";
+ public static final String OD_TAG_INT_ARRAY = "int-array";
+ public static final String OD_TAG_ITEM = "item";
+ public static final String OD_ATTR_NAME = "name";
+ public static final String OD_ATTR_VALUE = "value";
+ public static final String OD_ATTR_NUM = "num";
+ public static final String OD_NAME_SAFETY_LABELS = "safety_labels";
+ public static final String OD_NAME_DATA_LABELS = "data_labels";
+ public static final String OD_NAME_DATA_ACCESSED = "data_accessed";
+ public static final String OD_NAME_DATA_COLLECTED = "data_collected";
+ public static final String OD_NAME_DATA_SHARED = "data_shared";
+ public static final String OD_NAME_PURPOSES = "purposes";
+ public static final String OD_NAME_IS_COLLECTION_OPTIONAL = "is_collection_optional";
+ public static final String OD_NAME_IS_SHARING_OPTIONAL = "is_sharing_optional";
+ public static final String OD_NAME_EPHEMERAL = "ephemeral";
+
+ public static final String TRUE_STR = "true";
+ public static final String FALSE_STR = "false";
+
+ /** Gets the single top-level {@link Element} having the {@param tagName}. */
+ public static Element getSingleElement(Document doc, String tagName)
+ throws MalformedXmlException {
+ var elements = doc.getElementsByTagName(tagName);
+ return getSingleElement(elements, tagName);
+ }
+
+ /**
+ * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
+ */
+ public static Element getSingleChildElement(Element parentEle, String tagName)
+ throws MalformedXmlException {
+ var elements = parentEle.getElementsByTagName(tagName);
+ return getSingleElement(elements, tagName);
+ }
+
+ /** Gets the single {@link Element} from {@param elements} */
+ public static Element getSingleElement(NodeList elements, String tagName)
+ throws MalformedXmlException {
+ if (elements.getLength() != 1) {
+ throw new MalformedXmlException(
+ String.format(
+ "Expected 1 element \"%s\" in NodeList but got %s.",
+ tagName, elements.getLength()));
+ }
+ var elementAsNode = elements.item(0);
+ if (!(elementAsNode instanceof Element)) {
+ throw new MalformedXmlException(
+ String.format("%s was not a valid XML element.", tagName));
+ }
+ return ((Element) elementAsNode);
+ }
+
+ /** Gets the single {@link Element} within {@param elements}. */
+ public static Element getSingleElement(List<Element> elements) {
+ if (elements.size() != 1) {
+ throw new IllegalStateException(
+ String.format("Expected 1 element in list but got %s.", elements.size()));
+ }
+ return elements.get(0);
+ }
+
+ /** Converts {@param nodeList} into List of {@link Element}. */
+ public static List<Element> asElementList(NodeList nodeList) {
+ List<Element> elementList = new ArrayList<Element>();
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ var elementAsNode = nodeList.item(0);
+ if (elementAsNode instanceof Element) {
+ elementList.add(((Element) elementAsNode));
+ }
+ }
+ return elementList;
+ }
+
+ /** Appends {@param children} to the {@param ele}. */
+ public static void appendChildren(Element ele, List<Element> children) {
+ for (Element c : children) {
+ ele.appendChild(c);
+ }
+ }
+
+ /** Gets the Boolean from the String value. */
+ public static Boolean fromString(String s) {
+ if (s == null) {
+ return null;
+ }
+ if (s.equals(TRUE_STR)) {
+ return true;
+ } else if (s.equals(FALSE_STR)) {
+ return false;
+ }
+ return null;
+ }
+
+ /** Creates an on-device PBundle DOM Element with the given attribute name. */
+ public static Element createPbundleEleWithName(Document doc, String name) {
+ var ele = doc.createElement(XmlUtils.OD_TAG_PBUNDLE_AS_MAP);
+ ele.setAttribute(XmlUtils.OD_ATTR_NAME, name);
+ return ele;
+ }
+
+ /** Create an on-device Boolean DOM Element with the given attribute name. */
+ public static Element createOdBooleanEle(Document doc, String name, boolean b) {
+ var ele = doc.createElement(XmlUtils.OD_TAG_BOOLEAN);
+ ele.setAttribute(XmlUtils.OD_ATTR_NAME, name);
+ ele.setAttribute(XmlUtils.OD_ATTR_VALUE, String.valueOf(b));
+ return ele;
+ }
+
+ /** Returns whether the String is null or empty. */
+ public static boolean isNullOrEmpty(String s) {
+ return s == null || s.isEmpty();
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java
new file mode 100644
index 0000000..216df56
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java
@@ -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.asllib.util;
+
+public class MalformedXmlException extends Exception {
+ /** Constructs an {@code MalformedXmlException} with no detail message. */
+ public MalformedXmlException() {
+ super();
+ }
+
+ /**
+ * Constructs an {@code MalformedXmlException} with the specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public MalformedXmlException(String s) {
+ super(s);
+ }
+}
diff --git a/wifi/java/src/android/net/wifi/WifiBlobStore.java b/wifi/java/src/android/net/wifi/WifiBlobStore.java
new file mode 100644
index 0000000..8bfaae7
--- /dev/null
+++ b/wifi/java/src/android/net/wifi/WifiBlobStore.java
@@ -0,0 +1,39 @@
+/*
+ * 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.net.wifi;
+
+import com.android.internal.net.ConnectivityBlobStore;
+
+/**
+ * Database blob store for Wifi.
+ * @hide
+ */
+public class WifiBlobStore extends ConnectivityBlobStore {
+ private static final String DB_NAME = "WifiBlobStore.db";
+ private static WifiBlobStore sInstance;
+ private WifiBlobStore() {
+ super(DB_NAME);
+ }
+
+ /** Returns an instance of WifiBlobStore. */
+ public static WifiBlobStore getInstance() {
+ if (sInstance == null) {
+ sInstance = new WifiBlobStore();
+ }
+ return sInstance;
+ }
+}
diff --git a/wifi/java/src/android/net/wifi/WifiKeystore.java b/wifi/java/src/android/net/wifi/WifiKeystore.java
index 1cda032..a06d0ee 100644
--- a/wifi/java/src/android/net/wifi/WifiKeystore.java
+++ b/wifi/java/src/android/net/wifi/WifiKeystore.java
@@ -18,12 +18,17 @@
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.os.Binder;
import android.os.Process;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.legacykeystore.ILegacyKeystore;
import android.util.Log;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* This class allows the storage and retrieval of non-standard Wifi certificate blobs.
* @hide
@@ -34,7 +39,7 @@
private static final String TAG = "WifiKeystore";
private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore";
- private static ILegacyKeystore getService() {
+ private static ILegacyKeystore getLegacyKeystore() {
return ILegacyKeystore.Stub.asInterface(
ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME));
}
@@ -54,13 +59,18 @@
@SystemApi
@SuppressLint("UnflaggedApi")
public static boolean put(@NonNull String alias, @NonNull byte[] blob) {
+ // ConnectivityBlobStore uses the calling uid as a key into the DB.
+ // Clear identity to ensure that callers from system apps and the Wifi framework
+ // are able to access the same values.
+ final long identity = Binder.clearCallingIdentity();
try {
Log.i(TAG, "put blob. alias " + alias);
- getService().put(alias, Process.WIFI_UID, blob);
- return true;
+ return WifiBlobStore.getInstance().put(alias, blob);
} catch (Exception e) {
Log.e(TAG, "Failed to put blob.", e);
return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -69,23 +79,31 @@
* @param alias Name of the blob to retrieve.
* @return The unstructured blob, that is the blob that was stored using
* {@link android.net.wifi.WifiKeystore#put}.
- * Returns null if no blob was found.
+ * Returns empty byte[] if no blob was found.
* @hide
*/
@SystemApi
@SuppressLint("UnflaggedApi")
public static @NonNull byte[] get(@NonNull String alias) {
+ final long identity = Binder.clearCallingIdentity();
try {
Log.i(TAG, "get blob. alias " + alias);
- return getService().get(alias, Process.WIFI_UID);
+ byte[] blob = WifiBlobStore.getInstance().get(alias);
+ if (blob != null) {
+ return blob;
+ }
+ Log.i(TAG, "Searching for blob in Legacy Keystore");
+ return getLegacyKeystore().get(alias, Process.WIFI_UID);
} catch (ServiceSpecificException e) {
if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) {
Log.e(TAG, "Failed to get blob.", e);
}
} catch (Exception e) {
Log.e(TAG, "Failed to get blob.", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return null;
+ return new byte[0];
}
/**
@@ -97,17 +115,27 @@
@SystemApi
@SuppressLint("UnflaggedApi")
public static boolean remove(@NonNull String alias) {
+ boolean blobStoreSuccess = false;
+ boolean legacyKsSuccess = false;
+ final long identity = Binder.clearCallingIdentity();
try {
- getService().remove(alias, Process.WIFI_UID);
- return true;
+ Log.i(TAG, "remove blob. alias " + alias);
+ blobStoreSuccess = WifiBlobStore.getInstance().remove(alias);
+ // Legacy Keystore will throw an exception if the alias is not found.
+ getLegacyKeystore().remove(alias, Process.WIFI_UID);
+ legacyKsSuccess = true;
} catch (ServiceSpecificException e) {
if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) {
Log.e(TAG, "Failed to remove blob.", e);
}
} catch (Exception e) {
Log.e(TAG, "Failed to remove blob.", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return false;
+ Log.i(TAG, "Removal status: wifiBlobStore=" + blobStoreSuccess
+ + ", legacyKeystore=" + legacyKsSuccess);
+ return blobStoreSuccess || legacyKsSuccess;
}
/**
@@ -119,14 +147,24 @@
@SystemApi
@SuppressLint("UnflaggedApi")
public static @NonNull String[] list(@NonNull String prefix) {
+ final long identity = Binder.clearCallingIdentity();
try {
- final String[] aliases = getService().list(prefix, Process.WIFI_UID);
- for (int i = 0; i < aliases.length; ++i) {
- aliases[i] = aliases[i].substring(prefix.length());
+ // Aliases from WifiBlobStore will be pre-trimmed.
+ final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix);
+ final String[] legacyAliases = getLegacyKeystore().list(prefix, Process.WIFI_UID);
+ for (int i = 0; i < legacyAliases.length; ++i) {
+ legacyAliases[i] = legacyAliases[i].substring(prefix.length());
}
- return aliases;
+ // Deduplicate aliases before returning.
+ Set<String> uniqueAliases = new HashSet<>();
+ uniqueAliases.addAll(Arrays.asList(blobStoreAliases));
+ uniqueAliases.addAll(Arrays.asList(legacyAliases));
+ String[] uniqueAliasArray = new String[uniqueAliases.size()];
+ return uniqueAliases.toArray(uniqueAliasArray);
} catch (Exception e) {
Log.e(TAG, "Failed to list blobs.", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
return new String[0];
}
diff --git a/wifi/wifi.aconfig b/wifi/wifi.aconfig
index 6ac986e..6c4e4c3 100644
--- a/wifi/wifi.aconfig
+++ b/wifi/wifi.aconfig
@@ -2,6 +2,7 @@
flag {
name: "get_device_cross_akm_roaming_support"
+ is_exported: true
namespace: "wifi"
description: "Add new API to get the device support for CROSS-AKM roaming"
bug: "313038031"