Merge "Update comment about immutable overlay idmaps" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index ab5d503..2d05606 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -685,15 +685,17 @@
// Permissions
aconfig_declarations {
name: "android.permission.flags-aconfig",
- package: "android.permission.flags",
container: "system",
+ package: "android.permission.flags",
+ exportable: true,
srcs: ["core/java/android/permission/flags.aconfig"],
}
java_aconfig_library {
- name: "android.permission.flags-aconfig-java",
+ name: "android.permission.flags-aconfig-java-export",
aconfig_declarations: "android.permission.flags-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ mode: "exported",
min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
@@ -708,9 +710,15 @@
host_supported: true,
defaults: ["framework-minus-apex-aconfig-java-defaults"],
min_sdk_version: "30",
+}
+
+java_aconfig_library {
+ name: "android.permission.flags-aconfig-java",
+ aconfig_declarations: "android.permission.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
- "com.android.permission",
"com.android.nfcservices",
],
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index c74c48c..5f57c39 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.app.Notification;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
@@ -1366,6 +1367,7 @@
* @return This object for method chaining
*/
@FlaggedApi(Flags.FLAG_JOB_DEBUG_INFO_APIS)
+ @SuppressLint("BuilderSetStyle")
@NonNull
public Builder removeDebugTag(@NonNull String tag) {
mDebugTags.remove(tag);
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 06c7d64..559490c 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -33,6 +33,7 @@
"modules-utils-fastxmlserializer",
"service-jobscheduler-alarm.flags-aconfig-java",
"service-jobscheduler-job.flags-aconfig-java",
+ "service-jobscheduler-appidle.flags-aconfig-java",
],
// Rename classes shared with the framework
diff --git a/apex/jobscheduler/service/aconfig/Android.bp b/apex/jobscheduler/service/aconfig/Android.bp
index 859c67a..7b2525c 100644
--- a/apex/jobscheduler/service/aconfig/Android.bp
+++ b/apex/jobscheduler/service/aconfig/Android.bp
@@ -42,3 +42,16 @@
name: "service-jobscheduler-alarm.flags-aconfig-java",
aconfig_declarations: "alarm_flags",
}
+
+// App Idle
+aconfig_declarations {
+ name: "app_idle_flags",
+ package: "com.android.server.usage",
+ container: "system",
+ srcs: ["app_idle.aconfig"],
+}
+
+java_aconfig_library {
+ name: "service-jobscheduler-appidle.flags-aconfig-java",
+ aconfig_declarations: "app_idle_flags",
+}
diff --git a/apex/jobscheduler/service/aconfig/app_idle.aconfig b/apex/jobscheduler/service/aconfig/app_idle.aconfig
new file mode 100644
index 0000000..c8976ca
--- /dev/null
+++ b/apex/jobscheduler/service/aconfig/app_idle.aconfig
@@ -0,0 +1,14 @@
+package: "com.android.server.usage"
+container: "system"
+
+flag {
+ name: "avoid_idle_check"
+ namespace: "backstage_power"
+ description: "Postpone app idle check after boot completed"
+ is_fixed_read_only: true
+ bug: "337864590"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 4d4e340..6265d9b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -788,7 +788,13 @@
}
appUsageHistory.nextEstimatedLaunchTime = getLongValue(parser,
ATTR_NEXT_ESTIMATED_APP_LAUNCH_TIME, 0);
- appUsageHistory.lastInformedBucket = -1;
+ if (Flags.avoidIdleCheck()) {
+ // Set lastInformedBucket to the same value with the currentBucket
+ // it should have already been informed.
+ appUsageHistory.lastInformedBucket = appUsageHistory.currentBucket;
+ } else {
+ appUsageHistory.lastInformedBucket = -1;
+ }
userHistory.put(packageName, appUsageHistory);
if (version >= XML_VERSION_ADD_BUCKET_EXPIRY_TIMES) {
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 410074e..c3fe031 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -707,7 +707,7 @@
initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
}
- if (mPendingOneTimeCheckIdleStates) {
+ if (!Flags.avoidIdleCheck() && mPendingOneTimeCheckIdleStates) {
postOneTimeCheckIdleStates();
}
@@ -1021,7 +1021,7 @@
== REASON_SUB_DEFAULT_APP_RESTORED)) {
newBucket = getBucketForLocked(packageName, userId, elapsedRealtime);
if (DEBUG) {
- Slog.d(TAG, "Evaluated AOSP newBucket = "
+ Slog.d(TAG, "Evaluated " + packageName + " newBucket = "
+ standbyBucketToString(newBucket));
}
reason = REASON_MAIN_TIMEOUT;
@@ -1990,7 +1990,9 @@
}
}
if (android.app.admin.flags.Flags.disallowUserControlBgUsageFix()) {
- postCheckIdleStates(userId);
+ if (!Flags.avoidIdleCheck()) {
+ postCheckIdleStates(userId);
+ }
}
}
@@ -2392,9 +2394,14 @@
final boolean isHeadLess = !systemLauncherActivities.contains(pkg);
if (updateHeadlessSystemAppCache(pkg, isHeadLess)) {
- mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
- UserHandle.USER_SYSTEM, -1, pkg)
- .sendToTarget();
+ if (!Flags.avoidIdleCheck()) {
+ // Checking idle state for the each individual headless system app
+ // during the boot up is not necessary, a full idle check for all
+ // usres will be scheduled after boot completed.
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
+ UserHandle.USER_SYSTEM, -1, pkg)
+ .sendToTarget();
+ }
}
}
final long end = SystemClock.uptimeMillis();
@@ -2438,6 +2445,11 @@
@Override
public void dumpState(String[] args, PrintWriter pw) {
+ pw.println("Flags: ");
+ pw.println(" " + Flags.FLAG_AVOID_IDLE_CHECK
+ + ": " + Flags.avoidIdleCheck());
+ pw.println();
+
synchronized (mCarrierPrivilegedLock) {
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ "): " + mCarrierPrivilegedApps);
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 13d6ae5..6cfd2e0 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -44,8 +44,8 @@
removed_api_file: ":non-updatable-removed.txt",
},
last_released: {
- api_file: ":android-non-updatable.api.public.latest",
- removed_api_file: ":android-non-updatable-removed.api.public.latest",
+ api_file: ":android-non-updatable.api.combined.public.latest",
+ removed_api_file: ":android-non-updatable-removed.api.combined.public.latest",
baseline_file: ":android-non-updatable-incompatibilities.api.public.latest",
},
api_lint: {
@@ -124,8 +124,8 @@
removed_api_file: ":non-updatable-system-removed.txt",
},
last_released: {
- api_file: ":android-non-updatable.api.system.latest",
- removed_api_file: ":android-non-updatable-removed.api.system.latest",
+ api_file: ":android-non-updatable.api.combined.system.latest",
+ removed_api_file: ":android-non-updatable-removed.api.combined.system.latest",
baseline_file: ":android-non-updatable-incompatibilities.api.system.latest",
},
api_lint: {
@@ -263,8 +263,8 @@
removed_api_file: ":non-updatable-module-lib-removed.txt",
},
last_released: {
- api_file: ":android-non-updatable.api.module-lib.latest",
- removed_api_file: ":android-non-updatable-removed.api.module-lib.latest",
+ api_file: ":android-non-updatable.api.combined.module-lib.latest",
+ removed_api_file: ":android-non-updatable-removed.api.combined.module-lib.latest",
baseline_file: ":android-non-updatable-incompatibilities.api.module-lib.latest",
},
api_lint: {
diff --git a/core/api/current.txt b/core/api/current.txt
index 13958d2..c0bc6d9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3344,9 +3344,9 @@
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl);
- method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
+ method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public final void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl);
- method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
+ method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public final void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method public boolean clearCache();
method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method public final void disableSelf();
@@ -3354,7 +3354,7 @@
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int);
- method @FlaggedApi("android.view.accessibility.braille_display_hid") @NonNull public android.accessibilityservice.BrailleDisplayController getBrailleDisplayController();
+ method @FlaggedApi("android.view.accessibility.braille_display_hid") @NonNull public final android.accessibilityservice.BrailleDisplayController getBrailleDisplayController();
method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
method @Nullable public final android.accessibilityservice.InputMethod getInputMethod();
method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
@@ -13040,6 +13040,7 @@
method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
method public abstract boolean isSafeMode();
method @FlaggedApi("android.content.pm.get_package_info") @WorkerThread public <T> T parseAndroidManifest(@NonNull java.io.File, @NonNull java.util.function.Function<android.content.res.XmlResourceParser,T>) throws java.io.IOException;
+ method @FlaggedApi("android.content.pm.get_package_info_with_fd") @WorkerThread public <T> T parseAndroidManifest(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Function<android.content.res.XmlResourceParser,T>) throws java.io.IOException;
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryActivityProperty(@NonNull String);
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryApplicationProperty(@NonNull String);
method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
@@ -18087,6 +18088,11 @@
public class LineBreaker {
method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
+ method @FlaggedApi("com.android.text.flags.missing_getter_apis") public int getBreakStrategy();
+ method @FlaggedApi("com.android.text.flags.missing_getter_apis") public int getHyphenationFrequency();
+ method @FlaggedApi("com.android.text.flags.missing_getter_apis") @Nullable public int[] getIndents();
+ method @FlaggedApi("com.android.text.flags.missing_getter_apis") public int getJustificationMode();
+ method @FlaggedApi("com.android.text.flags.missing_getter_apis") public boolean getUseBoundsForWidth();
field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
@@ -26611,7 +26617,7 @@
public abstract static class MediaController.Callback {
ctor public MediaController.Callback();
- method public void onAudioInfoChanged(android.media.session.MediaController.PlaybackInfo);
+ method public void onAudioInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo);
method public void onExtrasChanged(@Nullable android.os.Bundle);
method public void onMetadataChanged(@Nullable android.media.MediaMetadata);
method public void onPlaybackStateChanged(@Nullable android.media.session.PlaybackState);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index d70fa19..fd9600c 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3554,8 +3554,8 @@
* @see #OVERLAY_RESULT_INVALID
* @see #OVERLAY_RESULT_INTERNAL_ERROR
*/
- @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")
- public void attachAccessibilityOverlayToDisplay(
+ @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS)
+ public final void attachAccessibilityOverlayToDisplay(
int displayId,
@NonNull SurfaceControl sc,
@NonNull @CallbackExecutor Executor executor,
@@ -3627,8 +3627,8 @@
* @see #OVERLAY_RESULT_INVALID
* @see #OVERLAY_RESULT_INTERNAL_ERROR
*/
- @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")
- public void attachAccessibilityOverlayToWindow(
+ @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS)
+ public final void attachAccessibilityOverlayToWindow(
int accessibilityWindowId,
@NonNull SurfaceControl sc,
@NonNull @CallbackExecutor Executor executor,
@@ -3645,7 +3645,7 @@
*/
@FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
@NonNull
- public BrailleDisplayController getBrailleDisplayController() {
+ public final BrailleDisplayController getBrailleDisplayController() {
BrailleDisplayController.checkApiFlagIsEnabled();
synchronized (mLock) {
if (mBrailleDisplayController == null) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e1cb630..79e2bd4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1183,6 +1183,7 @@
* @see #setIntent(Intent, ComponentCaller)
*/
@FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+ @SuppressLint("OnNameExpected")
public @Nullable ComponentCaller getCaller() {
return mCaller;
}
@@ -1203,6 +1204,7 @@
* @see #getCaller
*/
@FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+ @SuppressLint("OnNameExpected")
public void setIntent(@Nullable Intent newIntent, @Nullable ComponentCaller newCaller) {
internalSetIntent(newIntent, newCaller);
}
@@ -7161,6 +7163,7 @@
* @see ComponentCaller
*/
@FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+ @SuppressLint("OnNameExpected")
public @NonNull ComponentCaller getInitialCaller() {
return mInitialCaller;
}
@@ -7188,10 +7191,11 @@
* @see #getCaller
*/
@FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+ @SuppressLint("OnNameExpected")
public @NonNull ComponentCaller getCurrentCaller() {
if (mCurrentCaller == null) {
throw new IllegalStateException("The caller is null because #getCurrentCaller should be"
- + " called within #onNewIntent method");
+ + " called within #onNewIntent or #onActivityResult methods");
}
return mCurrentCaller;
}
@@ -9634,6 +9638,7 @@
* the default behaviour
*/
@FlaggedApi(android.security.Flags.FLAG_ASM_RESTRICTIONS_ENABLED)
+ @SuppressLint("OnNameExpected")
public void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) {
ActivityClient.getInstance().setAllowCrossUidActivitySwitchFromBelow(mToken, allowed);
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d8df447..8e99e46b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1282,4 +1282,15 @@
*/
public abstract void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid,
int userId);
+
+ /**
+ * It is similar {@link IActivityManager#killApplication(String, int, int, String, int)} but
+ * it immediately stop the package.
+ *
+ * <p>Note: Do not call this method from inside PMS's lock, otherwise it'll run into
+ * watchdog reset.
+ * @hide
+ */
+ public abstract void killApplicationSync(String pkgName, int appId, int userId,
+ String reason, int exitInfoReason);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d4812dd..76c1ed6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull;
+import static android.app.Flags.skipBgMemTrimOnFgApp;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
@@ -7078,6 +7079,11 @@
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
try {
+ if (skipBgMemTrimOnFgApp()
+ && mLastProcessState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ && level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
+ return;
+ }
if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
PropertyInvalidatedCache.onTrimMemory();
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 54f6909..6865f9c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3583,6 +3583,9 @@
return mAttributionTag;
}
+ /**
+ * Persistent device Id of the proxy that noted the op
+ */
@FlaggedApi(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
public @Nullable String getDeviceId() { return mDeviceId; }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b9906bf..c0f7232 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -4097,6 +4097,38 @@
}
}
+
+ @Override
+ public <T> T parseAndroidManifest(@NonNull ParcelFileDescriptor apkFileDescriptor,
+ @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException {
+ Objects.requireNonNull(apkFileDescriptor, "apkFileDescriptor cannot be null");
+ Objects.requireNonNull(parserFunction, "parserFunction cannot be null");
+ try (XmlResourceParser xmlResourceParser = getAndroidManifestParser(apkFileDescriptor)) {
+ return parserFunction.apply(xmlResourceParser);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get the android manifest parser", e);
+ throw e;
+ }
+ }
+
+ private static XmlResourceParser getAndroidManifestParser(@NonNull ParcelFileDescriptor fd)
+ throws IOException {
+ ApkAssets apkAssets = null;
+ try {
+ apkAssets = ApkAssets.loadFromFd(
+ fd.getFileDescriptor(), fd.toString(), /* flags= */ 0 , /* assets= */null);
+ return apkAssets.openXml(ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME);
+ } finally {
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
+ Log.w(TAG, "Failed to close apkAssets", ignored);
+ }
+ }
+ }
+ }
+
@Override
public TypedArray extractPackageItemInfoAttributes(PackageItemInfo info, String name,
String rootTag, int[] attributes) {
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 76d6547..746ec2e 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -843,6 +843,15 @@
return this;
}
+ /**
+ * Sets the package that owns this rule
+ * @hide
+ */
+ public @NonNull Builder setPackage(@NonNull String pkg) {
+ mPkg = pkg;
+ return this;
+ }
+
public @NonNull AutomaticZenRule build() {
AutomaticZenRule rule = new AutomaticZenRule(mName, mOwner, mConfigurationActivity,
mConditionId, mPolicy, mInterruptionFilter, mEnabled);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e3380e0..3b9a5d3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+import static android.permission.flags.Flags.shouldRegisterAttributionSource;
import static android.view.WindowManager.LayoutParams.WindowType;
import android.Manifest;
@@ -3157,7 +3158,8 @@
int deviceId = vdm.getDeviceIdForDisplayId(displayId);
if (deviceId != mDeviceId) {
mDeviceId = deviceId;
- mAttributionSource = mAttributionSource.withDeviceId(mDeviceId);
+ mAttributionSource =
+ createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId);
notifyOnDeviceChangedListeners(mDeviceId);
}
}
@@ -3180,6 +3182,7 @@
if (mDeviceId != updatedDeviceId) {
mDeviceId = updatedDeviceId;
+ mAttributionSource = createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId);
notifyOnDeviceChangedListeners(updatedDeviceId);
}
}
@@ -3548,8 +3551,22 @@
deviceId, nextAttributionSource);
// If we want to access protected data on behalf of another app we need to
// tell the OS that we opt in to participate in the attribution chain.
- if (nextAttributionSource != null || shouldRegister) {
- attributionSource = getSystemService(PermissionManager.class)
+ return registerAttributionSourceIfNeeded(attributionSource, shouldRegister);
+ }
+
+ private @NonNull AttributionSource createAttributionSourceWithDeviceId(
+ @NonNull AttributionSource oldSource, int deviceId) {
+ boolean shouldRegister = false;
+ if (shouldRegisterAttributionSource()) {
+ shouldRegister = mParams.shouldRegisterAttributionSource();
+ }
+ return registerAttributionSourceIfNeeded(oldSource.withDeviceId(deviceId), shouldRegister);
+ }
+
+ private @NonNull AttributionSource registerAttributionSourceIfNeeded(
+ @NonNull AttributionSource attributionSource, boolean shouldRegister) {
+ if (shouldRegister || attributionSource.getNext() != null) {
+ return getSystemService(PermissionManager.class)
.registerAttributionSource(attributionSource);
}
return attributionSource;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0672064..dfae48b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8725,6 +8725,12 @@
* <p>The messages should be added in chronologic order, i.e. the oldest first,
* the newest last.
*
+ * <p>Multiple Messages in a row with the same timestamp and sender may be grouped as a
+ * single message. This means an app should represent a message that has both an image and
+ * text as two Message objects, one with the image (and fallback text), and the other with
+ * the message text. For consistency, a text message (if any) should be provided after Uri
+ * content.
+ *
* @param message The {@link Message} to be displayed
* @return this object for method chaining
*/
@@ -8892,6 +8898,62 @@
}
}
+ private void fixTitleAndTextForCompactMessaging(StandardTemplateParams p) {
+ Message m = findLatestIncomingMessage();
+ final CharSequence text = (m == null) ? null : m.mText;
+ CharSequence sender = m == null ? null
+ : m.mSender == null || TextUtils.isEmpty(m.mSender.getName())
+ ? mUser.getName() : m.mSender.getName();
+
+ CharSequence conversationTitle = mIsGroupConversation ? mConversationTitle : null;
+
+ // we want to have colon for possible title for conversation.
+ final BidiFormatter bidi = BidiFormatter.getInstance();
+ if (sender != null) {
+ sender = mBuilder.mContext.getString(
+ com.android.internal.R.string.notification_messaging_title_template,
+ bidi.unicodeWrap(sender), "");
+ } else if (conversationTitle != null) {
+ conversationTitle = mBuilder.mContext.getString(
+ com.android.internal.R.string.notification_messaging_title_template,
+ bidi.unicodeWrap(conversationTitle), "");
+ }
+
+ if (Flags.cleanUpSpansAndNewLines()) {
+ conversationTitle = stripStyling(conversationTitle);
+ sender = stripStyling(sender);
+ }
+
+ final boolean showOnlySenderName = showOnlySenderName();
+
+ final CharSequence title;
+ boolean isConversationTitleAvailable = !showOnlySenderName && conversationTitle != null;
+ if (isConversationTitleAvailable) {
+ title = conversationTitle;
+ } else {
+ title = sender;
+ }
+
+ p.title(title);
+ // when the conversation title is available, use headerTextSecondary for sender and
+ // summaryText for text
+ if (isConversationTitleAvailable) {
+ p.headerTextSecondary(sender);
+ p.summaryText(text);
+ } else {
+ // when it is not, use headerTextSecondary for text and don't use summaryText
+ p.headerTextSecondary(text);
+ p.summaryText(null);
+ }
+ }
+
+ /** developer settings to always show sender name */
+ private boolean showOnlySenderName() {
+ return SystemProperties.getBoolean(
+ "persist.compact_heads_up_notification.show_only_sender_name",
+ false);
+ }
+
/**
* @hide
*/
@@ -9211,24 +9273,34 @@
}
}
- // This method fills title and text
- fixTitleAndTextExtras(mBuilder.mN.extras);
final StandardTemplateParams p = mBuilder.mParams.reset()
.viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
.highlightExpander(isConversationLayout)
.fillTextsFrom(mBuilder)
- .hideTime(true)
- .summaryText("");
- p.headerTextSecondary(p.mText);
+ .hideTime(true);
+
+ fixTitleAndTextForCompactMessaging(p);
TemplateBindResult bindResult = new TemplateBindResult();
RemoteViews contentView = mBuilder.applyStandardTemplate(
mBuilder.getMessagingCompactHeadsUpLayoutResource(), p, bindResult);
+ contentView.setViewVisibility(R.id.header_text_secondary_divider, View.GONE);
+ contentView.setViewVisibility(R.id.header_text_divider, View.GONE);
if (conversationIcon != null) {
contentView.setViewVisibility(R.id.icon, View.GONE);
+ contentView.setViewVisibility(R.id.conversation_face_pile, View.GONE);
contentView.setViewVisibility(R.id.conversation_icon, View.VISIBLE);
contentView.setBoolean(R.id.conversation_icon, "setApplyCircularCrop", true);
contentView.setImageViewIcon(R.id.conversation_icon, conversationIcon);
+ } else if (mIsGroupConversation) {
+ contentView.setViewVisibility(R.id.icon, View.GONE);
+ contentView.setViewVisibility(R.id.conversation_icon, View.GONE);
+ contentView.setInt(R.id.status_bar_latest_event_content,
+ "setNotificationBackgroundColor", mBuilder.getBackgroundColor(p));
+ contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
+ mBuilder.getSmallIconColor(p));
+ contentView.setBundle(R.id.status_bar_latest_event_content, "setGroupFacePile",
+ mBuilder.mN.extras);
}
if (remoteInputAction != null) {
@@ -9293,6 +9365,15 @@
}
}
+ /*
+ * An object representing a simple message or piece of media within a mixed-media message.
+ *
+ * This object can only represent text or a single binary piece of media. For apps which
+ * support mixed-media messages (e.g. text + image), multiple Messages should be used, one
+ * to represent each piece of the message, and they should all be given the same timestamp.
+ * For consistency, a text message should be added last of all Messages with the same
+ * timestamp.
+ */
public static final class Message {
/** @hide */
public static final String KEY_TEXT = "text";
@@ -9381,8 +9462,9 @@
/**
* Sets a binary blob of data and an associated MIME type for a message. In the case
- * where the platform doesn't support the MIME type, the original text provided in the
- * constructor will be used.
+ * where the platform or the UI state doesn't support the MIME type, the original text
+ * provided in the constructor will be used. When this data can be presented to the
+ * user, the original text will only be used as accessibility text.
* @param dataMimeType The MIME type of the content. See
* {@link android.graphics.ImageDecoder#isMimeTypeSupported(String)} for a list of
* supported image MIME types.
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index bb24fd1..fa646a7 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -70,3 +70,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "backstage_power"
+ name: "skip_bg_mem_trim_on_fg_app"
+ description: "Skip background memory trim event on foreground processes."
+ is_fixed_read_only: true
+ bug: "308927629"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 4154e66..86b4180 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -115,6 +115,16 @@
}
flag {
+ name: "hsum_unlock_notification_fix"
+ namespace: "enterprise"
+ description: "Using the right userId when starting the work profile unlock flow "
+ bug: "327350831"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "dumpsys_policy_engine_migration_enabled"
namespace: "enterprise"
description: "Update DumpSys to include information about migrated APIs in DPE"
@@ -308,6 +318,16 @@
}
flag {
+ name: "delete_private_space_under_restriction"
+ namespace: "enterprise"
+ description: "Delete private space if user restriction is set"
+ bug: "328758346"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "headless_single_user_fixes"
namespace: "enterprise"
description: "Various fixes for headless single user mode"
@@ -318,6 +338,13 @@
}
flag {
+ name: "backup_connected_apps_settings"
+ namespace: "enterprise"
+ description: "backup and restore connected work and personal apps user settings across devices"
+ bug: "175067666"
+}
+
+flag {
name: "headless_single_user_compatibility_fix"
namespace: "enterprise"
description: "Fix for compatibility issue introduced from using single_user mode on pre-Android V builds"
@@ -336,3 +363,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "onboarding_consentless_bugreports"
+ namespace: "enterprise"
+ description: "Allow subsequent bugreports to skip user consent within a time frame"
+ bug: "340439309"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java b/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java
new file mode 100644
index 0000000..ee04f8c
--- /dev/null
+++ b/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.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 android.app.servertransaction;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ClientTransactionHandler;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+import android.view.IWindow;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+import java.util.Objects;
+
+/**
+ * Message to deliver window insets control change info.
+ * @hide
+ */
+public class WindowStateInsetsControlChangeItem extends ClientTransactionItem {
+
+ private static final String TAG = "WindowStateInsetsControlChangeItem";
+
+ private IWindow mWindow;
+ private InsetsState mInsetsState;
+ private InsetsSourceControl.Array mActiveControls;
+
+ @Override
+ public void execute(@NonNull ClientTransactionHandler client,
+ @NonNull PendingTransactionActions pendingActions) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "windowInsetsControlChanged");
+ if (mWindow instanceof InsetsControlChangeListener listener) {
+ listener.onExecutingWindowStateInsetsControlChangeItem();
+ }
+ try {
+ mWindow.insetsControlChanged(mInsetsState, mActiveControls);
+ } catch (RemoteException e) {
+ // Should be a local call.
+ // An exception could happen if the process is restarted. It is safe to ignore since
+ // the window should no longer exist.
+ Log.w(TAG, "The original window no longer exists in the new process", e);
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+
+ // ObjectPoolItem implementation
+
+ private WindowStateInsetsControlChangeItem() {}
+
+ /** Obtains an instance initialized with provided params. */
+ public static WindowStateInsetsControlChangeItem obtain(@NonNull IWindow window,
+ @NonNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls) {
+ WindowStateInsetsControlChangeItem instance =
+ ObjectPool.obtain(WindowStateInsetsControlChangeItem.class);
+ if (instance == null) {
+ instance = new WindowStateInsetsControlChangeItem();
+ }
+ instance.mWindow = requireNonNull(window);
+ instance.mInsetsState = new InsetsState(insetsState, true /* copySources */);
+ instance.mActiveControls = new InsetsSourceControl.Array(activeControls);
+
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ mWindow = null;
+ mInsetsState = null;
+ mActiveControls = null;
+ ObjectPool.recycle(this);
+ }
+
+ // Parcelable implementation
+
+ /** Writes to Parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mWindow.asBinder());
+ dest.writeTypedObject(mInsetsState, flags);
+ dest.writeTypedObject(mActiveControls, flags);
+ }
+
+ /** Reads from Parcel. */
+ private WindowStateInsetsControlChangeItem(@NonNull Parcel in) {
+ mWindow = IWindow.Stub.asInterface(in.readStrongBinder());
+ mInsetsState = in.readTypedObject(InsetsState.CREATOR);
+ mActiveControls = in.readTypedObject(InsetsSourceControl.Array.CREATOR);
+
+ }
+
+ public static final @NonNull Creator<WindowStateInsetsControlChangeItem> CREATOR =
+ new Creator<>() {
+ public WindowStateInsetsControlChangeItem createFromParcel(@NonNull Parcel in) {
+ return new WindowStateInsetsControlChangeItem(in);
+ }
+
+ public WindowStateInsetsControlChangeItem[] newArray(int size) {
+ return new WindowStateInsetsControlChangeItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final WindowStateInsetsControlChangeItem other = (WindowStateInsetsControlChangeItem) o;
+ return Objects.equals(mWindow, other.mWindow)
+ && Objects.equals(mInsetsState, other.mInsetsState)
+ && Objects.equals(mActiveControls, other.mActiveControls);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + Objects.hashCode(mWindow);
+ result = 31 * result + Objects.hashCode(mInsetsState);
+ result = 31 * result + Objects.hashCode(mActiveControls);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowStateInsetsControlChangeItem{window=" + mWindow + "}";
+ }
+
+ /** The interface for IWindow to perform insets control change directly if possible. */
+ public interface InsetsControlChangeListener {
+ /**
+ * Notifies that IWindow#insetsControlChanged is going to be called from
+ * WindowStateInsetsControlChangeItem.
+ */
+ void onExecutingWindowStateInsetsControlChangeItem();
+ }
+}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 8220313..57ee622 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -326,6 +326,7 @@
* @return whether the specified user is a profile.
*/
@FlaggedApi(FLAG_ALLOW_QUERYING_PROFILE_TYPE)
+ @SuppressWarnings("UserHandleName")
public boolean isProfile(@NonNull UserHandle userHandle) {
// Note that this is not a security check, but rather a check for correct use.
// The actual security check is performed by UserManager.
@@ -343,6 +344,7 @@
* @return whether the specified user is a managed profile.
*/
@FlaggedApi(FLAG_ALLOW_QUERYING_PROFILE_TYPE)
+ @SuppressWarnings("UserHandleName")
public boolean isManagedProfile(@NonNull UserHandle userHandle) {
// Note that this is not a security check, but rather a check for correct use.
// The actual security check is performed by UserManager.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c506c97..2d9881a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -75,6 +75,7 @@
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -11755,6 +11756,27 @@
}
/**
+ * Similar to {@link #parseAndroidManifest(File, Function)}, but accepting a file descriptor
+ * instead of a File object.
+ *
+ * @param apkFileDescriptor The file descriptor of an application apk.
+ * The parserFunction will be invoked with the XmlResourceParser object
+ * after getting the AndroidManifest.xml of an application package.
+ *
+ * @return Returns the result of the {@link Function#apply(Object)}.
+ *
+ * @throws IOException if the AndroidManifest.xml of an application package cannot be
+ * read or accessed.
+ */
+ @FlaggedApi(android.content.pm.Flags.FLAG_GET_PACKAGE_INFO_WITH_FD)
+ @WorkerThread
+ public <T> T parseAndroidManifest(@NonNull ParcelFileDescriptor apkFileDescriptor,
+ @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException {
+ throw new UnsupportedOperationException(
+ "parseAndroidManifest not implemented in subclass");
+ }
+
+ /**
* @param info The {@link ServiceInfo} to pull the attributes from.
* @param name The name of the Xml metadata where the attributes are stored.
* @param rootTag The root tag of the attributes.
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 061e7f7..d9b0e6d 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -276,3 +276,11 @@
bug: "300309050"
is_fixed_read_only: true
}
+
+flag {
+ name: "get_package_info_with_fd"
+ is_exported: true
+ namespace: "package_manager_service"
+ description: "Feature flag to enable the feature to retrieve package info without installation with a file descriptor."
+ bug: "340879905"
+}
\ No newline at end of file
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 885f4c5..982224b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -806,7 +806,7 @@
*
* <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.
+ * 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>
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index e2b409f..7f3c49d 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1571,8 +1571,7 @@
}
// Allow RAW formats, even when not advertised.
- if (inputFormat == ImageFormat.RAW_PRIVATE || inputFormat == ImageFormat.RAW10
- || inputFormat == ImageFormat.RAW12 || inputFormat == ImageFormat.RAW_SENSOR) {
+ if (isRawFormat(inputFormat)) {
return true;
}
@@ -1642,6 +1641,11 @@
}
}
+ // Allow RAW formats, even when not advertised.
+ if (Flags.multiResRawReprocessing() && isRawFormat(inputFormat)) {
+ return;
+ }
+
if (validFormat == false) {
throw new IllegalArgumentException("multi-resolution input format " +
inputFormat + " is not valid");
@@ -2584,6 +2588,11 @@
return mCharacteristics;
}
+ private boolean isRawFormat(int format) {
+ return (format == ImageFormat.RAW_PRIVATE || format == ImageFormat.RAW10
+ || format == ImageFormat.RAW12 || format == ImageFormat.RAW_SENSOR);
+ }
+
/**
* Listener for binder death.
*
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 45b316a..40d4fb6 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -55,7 +55,6 @@
int[] getInputDeviceIds();
// Enable/disable input device.
- boolean isInputDeviceEnabled(int deviceId);
void enableInputDevice(int deviceId);
void disableInputDevice(int deviceId);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 7527aa7..9eabc8d 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -333,19 +333,6 @@
}
/**
- * Returns true if an input device is enabled. Should return true for most
- * situations. Some system apps may disable an input device, for
- * example to prevent unwanted touch events.
- *
- * @param id The input device Id.
- *
- * @hide
- */
- public boolean isInputDeviceEnabled(int id) {
- return mGlobal.isInputDeviceEnabled(id);
- }
-
- /**
* Enables an InputDevice.
* <p>
* Requires {@link android.Manifest.permission#DISABLE_INPUT_DEVICE}.
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index fcd5a3e..7b47180 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -411,18 +411,6 @@
}
/**
- * @see InputManager#isInputDeviceEnabled(int)
- */
- public boolean isInputDeviceEnabled(int id) {
- try {
- return mIm.isInputDeviceEnabled(id);
- } catch (RemoteException ex) {
- Log.w(TAG, "Could not check enabled status of input device with id = " + id);
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
* @see InputManager#enableInputDevice(int)
*/
public void enableInputDevice(int id) {
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index fedc97d..caf963e 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1388,7 +1388,7 @@
*/
public Builder scheme(String scheme) {
if (scheme != null) {
- this.scheme = scheme.replaceAll("://", "");
+ this.scheme = scheme.replace("://", "");
} else {
this.scheme = null;
}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 960e84d..a818df5 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -252,7 +252,8 @@
params.getMode(),
params.getFlags(),
dsListener,
- isScreenshotRequested);
+ isScreenshotRequested,
+ /* skipUserConsent = */ false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (FileNotFoundException e) {
@@ -313,6 +314,7 @@
bugreportFd.getFileDescriptor(),
bugreportFile,
/* keepBugreportOnRetrieval = */ false,
+ /* skipUserConsent = */ false,
dsListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 4512180..8aa2c35 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -36,6 +36,8 @@
import android.util.Slog;
import android.view.View;
+import com.android.internal.ravenwood.RavenwoodEnvironment;
+
import dalvik.system.VMRuntime;
import java.util.ArrayList;
@@ -49,6 +51,10 @@
*/
@RavenwoodKeepWholeClass
public class Build {
+ static {
+ // Set up the default system properties.
+ RavenwoodEnvironment.ensureRavenwoodInitialized();
+ }
private static final String TAG = "Build";
/** Value used for when a build property is unknown. */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2f0d634..80d3566 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -368,17 +368,18 @@
public static final String DISALLOW_WIFI_TETHERING = "no_wifi_tethering";
/**
- * Specifies if a user is disallowed from being granted admin privileges.
+ * Restricts a user's ability to possess or grant admin privileges.
*
- * <p>This restriction limits ability of other admin users to grant admin
- * privileges to selected user.
+ * <p>When set to <code>true</code>, this prevents the user from:
+ * <ul>
+ * <li>Becoming an admin</li>
+ * <li>Giving other users admin privileges</li>
+ * </ul>
*
- * <p>This restriction has no effect in a mode that does not allow multiple admins.
+ * <p>This restriction is only effective in environments where multiple admins are allowed.
*
- * <p>The default value is <code>false</code>.
+ * <p>Key for user restrictions. Type: Boolean. Default: <code>false</code>.
*
- * <p>Key for user restrictions.
- * <p>Type: Boolean
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 5056557..bb89e07 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -17,8 +17,11 @@
package android.os;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.app.ActivityThread;
+import java.io.IOException;
import java.util.Map;
/**
@@ -113,5 +116,20 @@
@TestApi
public static native Long getTargetFrameworkCompatibilityMatrixVersion();
+ /**
+ * Executes a shell command using shell user identity, and return the standard output in string.
+ *
+ * @hide
+ */
+ private static @Nullable String runShellCommand(@NonNull String command) throws IOException {
+ var activityThread = ActivityThread.currentActivityThread();
+ var instrumentation = activityThread.getInstrumentation();
+ var automation = instrumentation.getUiAutomation();
+ var pfd = automation.executeShellCommand(command);
+ try (var is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ return new String(is.readAllBytes());
+ }
+ }
+
private VintfObject() {}
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 2ca58d1..25389e5 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -2,20 +2,20 @@
container: "system"
flag {
- name: "device_aware_permission_apis_enabled"
- is_exported: true
- is_fixed_read_only: true
- namespace: "permissions"
- description: "enable device aware permission APIs"
- bug: "274852670"
+ name: "device_aware_permission_apis_enabled"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "enable device aware permission APIs"
+ bug: "274852670"
}
flag {
- name: "voice_activation_permission_apis"
- is_exported: true
- namespace: "permissions"
- description: "enable voice activation permission APIs"
- bug: "287264308"
+ name: "voice_activation_permission_apis"
+ is_exported: true
+ namespace: "permissions"
+ description: "enable voice activation permission APIs"
+ bug: "287264308"
}
flag {
@@ -28,11 +28,11 @@
}
flag {
- name: "set_next_attribution_source"
- is_exported: true
- namespace: "permissions"
- description: "enable AttributionSource.setNextAttributionSource"
- bug: "304478648"
+ name: "set_next_attribution_source"
+ is_exported: true
+ namespace: "permissions"
+ description: "enable AttributionSource.setNextAttributionSource"
+ bug: "304478648"
}
flag {
@@ -53,19 +53,19 @@
}
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"
+ 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"
}
flag {
- name: "factory_reset_prep_permission_apis"
- is_exported: true
- namespace: "wallet_integration"
- description: "enable Permission PREPARE_FACTORY_RESET."
- bug: "302016478"
+ name: "factory_reset_prep_permission_apis"
+ is_exported: true
+ namespace: "wallet_integration"
+ description: "enable Permission PREPARE_FACTORY_RESET."
+ bug: "302016478"
}
flag {
@@ -92,57 +92,61 @@
}
flag {
- name: "signature_permission_allowlist_enabled"
- is_fixed_read_only: true
- namespace: "permissions"
- description: "Enable signature permission allowlist"
- bug: "308573169"
+ name: "signature_permission_allowlist_enabled"
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enable signature permission allowlist"
+ bug: "308573169"
}
flag {
- name: "sensitive_notification_app_protection"
- namespace: "permissions"
- description: "This flag controls the sensitive notification app protections while screen sharing"
- bug: "312784351"
- # Referenced in WM where WM starts before DeviceConfig
- is_fixed_read_only: true
+ name: "sensitive_notification_app_protection"
+ is_exported: true
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "This flag controls the sensitive notification app protections while screen sharing"
+ bug: "312784351"
}
flag {
- name: "sensitive_content_improvements"
- namespace: "permissions"
- description: "Improvements to sensitive content/notification features, such as the Toast UX."
- bug: "301960090"
- # Referenced in WM where WM starts before DeviceConfig
- is_fixed_read_only: true
+ name: "sensitive_content_improvements"
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Improvements to sensitive content/notification features, such as the Toast UX."
+ bug: "301960090"
+
}
flag {
- name: "sensitive_content_metrics_bugfix"
- namespace: "permissions"
- description: "Enables metrics bugfixes for sensitive content/notification features"
- bug: "312784351"
- # Referenced in WM where WM starts before DeviceConfig
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
+ name: "sensitive_content_metrics_bugfix"
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enables metrics bugfixes for sensitive content/notification features"
+ bug: "312784351"
+
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
- name: "sensitive_content_recents_screenshot_bugfix"
- namespace: "permissions"
- description: "Enables recents screenshot bugfixes for sensitive content/notification features"
- bug: "312784351"
- # Referenced in WM where WM starts before DeviceConfig
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
+ name: "sensitive_content_recents_screenshot_bugfix"
+ # Referenced in WM where WM starts before DeviceConfig
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "Enables recents screenshot bugfixes for sensitive content/notification features"
+ bug: "312784351"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
name: "device_aware_permissions_enabled"
+ is_exported: true
is_fixed_read_only: true
namespace: "permissions"
description: "When the flag is off no permissions can be device aware"
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 120846c..708c196 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -2017,7 +2017,7 @@
return false;
}
final UserInfo userInfo = userManager.getUserInfo(userId);
- return userInfo != null && !userInfo.isManagedProfile();
+ return userInfo != null && !userInfo.isProfile();
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4f5b67c..3738c26 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -17032,6 +17032,28 @@
*/
public static final String ENABLE_BACK_ANIMATION = "enable_back_animation";
+ /**
+ * An allow list of packages for which the user has granted the permission to communicate
+ * across profiles.
+ *
+ * @hide
+ */
+ @Readable
+ @FlaggedApi(android.app.admin.flags.Flags.FLAG_BACKUP_CONNECTED_APPS_SETTINGS)
+ public static final String CONNECTED_APPS_ALLOWED_PACKAGES =
+ "connected_apps_allowed_packages";
+
+ /**
+ * A block list of packages for which the user has denied the permission to communicate
+ * across profiles.
+ *
+ * @hide
+ */
+ @Readable
+ @FlaggedApi(android.app.admin.flags.Flags.FLAG_BACKUP_CONNECTED_APPS_SETTINGS)
+ public static final String CONNECTED_APPS_DISALLOWED_PACKAGES =
+ "connected_apps_disallowed_packages";
+
/** @hide */ public static String zenModeToString(int mode) {
if (mode == ZEN_MODE_IMPORTANT_INTERRUPTIONS) return "ZEN_MODE_IMPORTANT_INTERRUPTIONS";
if (mode == ZEN_MODE_ALARMS) return "ZEN_MODE_ALARMS";
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 77353c2..ff98fc4 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -2,9 +2,9 @@
container: "system"
flag {
- name: "a11y_standalone_fab_enabled"
+ name: "a11y_standalone_gesture_enabled"
namespace: "accessibility"
- description: "Separating a11y software shortcut and floating a11y button"
+ description: "Separating a11y software shortcut and gesture shortcut"
bug: "297544054"
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 38ab590..71066ac 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -433,7 +433,8 @@
mTrackingConfirmKey = event.getKeyCode();
}
case KeyEvent.ACTION_UP -> {
- if (mTrackingConfirmKey != event.getKeyCode()) {
+ if (mTrackingConfirmKey == null
+ || mTrackingConfirmKey != event.getKeyCode()) {
return true;
}
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
index 793e58a..293015f 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
@@ -18,6 +18,9 @@
import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
@@ -40,13 +43,16 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.Handler;
import android.os.IBinder;
import android.os.ICancellationSignal;
+import android.os.Looper;
import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.infra.AndroidFuture;
@@ -88,6 +94,14 @@
private static final String TAG = OnDeviceIntelligenceService.class.getSimpleName();
private volatile IRemoteProcessingService mRemoteProcessingService;
+ private Handler mHandler;
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null /* callback */, true /* async */);
+ }
/**
* The {@link Intent} that must be declared as handled by the service. To be supported, the
@@ -107,38 +121,49 @@
@Override
public final IBinder onBind(@NonNull Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction())) {
- // TODO(326052028) : Move the remote method calls to an app handler from the binder
- // thread.
return new IOnDeviceIntelligenceService.Stub() {
/** {@inheritDoc} */
@Override
public void ready() {
- OnDeviceIntelligenceService.this.onReady();
+ mHandler.executeOrSendMessage(
+ obtainMessage(OnDeviceIntelligenceService::onReady,
+ OnDeviceIntelligenceService.this));
}
@Override
public void getVersion(RemoteCallback remoteCallback) {
Objects.requireNonNull(remoteCallback);
- OnDeviceIntelligenceService.this.onGetVersion(l -> {
- Bundle b = new Bundle();
- b.putLong(OnDeviceIntelligenceManager.API_VERSION_BUNDLE_KEY, l);
- remoteCallback.sendResult(b);
- });
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onGetVersion,
+ OnDeviceIntelligenceService.this, l -> {
+ Bundle b = new Bundle();
+ b.putLong(
+ OnDeviceIntelligenceManager.API_VERSION_BUNDLE_KEY,
+ l);
+ remoteCallback.sendResult(b);
+ }));
}
@Override
public void listFeatures(int callerUid,
IListFeaturesCallback listFeaturesCallback) {
Objects.requireNonNull(listFeaturesCallback);
- OnDeviceIntelligenceService.this.onListFeatures(callerUid,
- wrapListFeaturesCallback(listFeaturesCallback));
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onListFeatures,
+ OnDeviceIntelligenceService.this, callerUid,
+ wrapListFeaturesCallback(listFeaturesCallback)));
}
@Override
public void getFeature(int callerUid, int id, IFeatureCallback featureCallback) {
Objects.requireNonNull(featureCallback);
- OnDeviceIntelligenceService.this.onGetFeature(callerUid,
- id, wrapFeatureCallback(featureCallback));
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onGetFeature,
+ OnDeviceIntelligenceService.this, callerUid,
+ id, wrapFeatureCallback(featureCallback)));
}
@@ -147,9 +172,11 @@
IFeatureDetailsCallback featureDetailsCallback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(featureDetailsCallback);
-
- OnDeviceIntelligenceService.this.onGetFeatureDetails(callerUid,
- feature, wrapFeatureDetailsCallback(featureDetailsCallback));
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onGetFeatureDetails,
+ OnDeviceIntelligenceService.this, callerUid,
+ feature, wrapFeatureDetailsCallback(featureDetailsCallback)));
}
@Override
@@ -163,10 +190,13 @@
transport = CancellationSignal.createTransport();
cancellationSignalFuture.complete(transport);
}
- OnDeviceIntelligenceService.this.onDownloadFeature(callerUid,
- feature,
- CancellationSignal.fromTransport(transport),
- wrapDownloadCallback(downloadCallback));
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onDownloadFeature,
+ OnDeviceIntelligenceService.this, callerUid,
+ feature,
+ CancellationSignal.fromTransport(transport),
+ wrapDownloadCallback(downloadCallback)));
}
@Override
@@ -174,9 +204,11 @@
AndroidFuture<ParcelFileDescriptor> future) {
Objects.requireNonNull(fileName);
Objects.requireNonNull(future);
-
- OnDeviceIntelligenceService.this.onGetReadOnlyFileDescriptor(fileName,
- future);
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onGetReadOnlyFileDescriptor,
+ OnDeviceIntelligenceService.this, fileName,
+ future));
}
@Override
@@ -184,13 +216,15 @@
Feature feature, RemoteCallback remoteCallback) {
Objects.requireNonNull(feature);
Objects.requireNonNull(remoteCallback);
-
- OnDeviceIntelligenceService.this.onGetReadOnlyFeatureFileDescriptorMap(
- feature, parcelFileDescriptorMap -> {
- Bundle bundle = new Bundle();
- parcelFileDescriptorMap.forEach(bundle::putParcelable);
- remoteCallback.sendResult(bundle);
- });
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onGetReadOnlyFeatureFileDescriptorMap,
+ OnDeviceIntelligenceService.this, feature,
+ parcelFileDescriptorMap -> {
+ Bundle bundle = new Bundle();
+ parcelFileDescriptorMap.forEach(bundle::putParcelable);
+ remoteCallback.sendResult(bundle);
+ }));
}
@Override
@@ -201,12 +235,18 @@
@Override
public void notifyInferenceServiceConnected() {
- OnDeviceIntelligenceService.this.onInferenceServiceConnected();
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onInferenceServiceConnected,
+ OnDeviceIntelligenceService.this));
}
@Override
public void notifyInferenceServiceDisconnected() {
- OnDeviceIntelligenceService.this.onInferenceServiceDisconnected();
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceIntelligenceService::onInferenceServiceDisconnected,
+ OnDeviceIntelligenceService.this));
}
};
}
@@ -222,7 +262,8 @@
* @hide
*/
@TestApi
- public void onReady() {}
+ public void onReady() {
+ }
/**
@@ -410,12 +451,16 @@
Slog.v(TAG,
"onGetReadOnlyFileDescriptor: " + fileName + " under internal app storage.");
File f = new File(getBaseContext().getFilesDir(), fileName);
+ if (!f.exists()) {
+ f = new File(fileName);
+ }
ParcelFileDescriptor pfd = null;
try {
pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
Slog.d(TAG, "Successfully opened a file with ParcelFileDescriptor.");
} catch (FileNotFoundException e) {
Slog.e(TAG, "Cannot open file. No ParcelFileDescriptor returned.");
+ future.completeExceptionally(e);
} finally {
future.complete(pfd);
if (pfd != null) {
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
index 8237b20..d00485c 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
@@ -19,7 +19,10 @@
import static android.app.ondeviceintelligence.OnDeviceIntelligenceManager.AUGMENT_REQUEST_CONTENT_BUNDLE_KEY;
import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
import android.annotation.CallbackExecutor;
+import android.annotation.CallSuper;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,6 +51,7 @@
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.ICancellationSignal;
+import android.os.Looper;
import android.os.OutcomeReceiver;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -120,7 +124,20 @@
*/
public static final String MODEL_UNLOADED_BUNDLE_KEY = "model_unloaded";
+ /**
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_UPDATE_BUNDLE_KEY = "device_config_update";
+
private IRemoteStorageService mRemoteStorageService;
+ private Handler mHandler;
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null /* callback */, true /* async */);
+ }
/**
* @hide
@@ -147,11 +164,15 @@
transport = CancellationSignal.createTransport();
cancellationSignalFuture.complete(transport);
}
- OnDeviceSandboxedInferenceService.this.onTokenInfoRequest(callerUid,
- feature,
- request,
- CancellationSignal.fromTransport(transport),
- wrapTokenInfoCallback(tokenInfoCallback));
+
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceSandboxedInferenceService::onTokenInfoRequest,
+ OnDeviceSandboxedInferenceService.this,
+ callerUid, feature,
+ request,
+ CancellationSignal.fromTransport(transport),
+ wrapTokenInfoCallback(tokenInfoCallback)));
}
@Override
@@ -173,13 +194,18 @@
processingSignalTransport = ProcessingSignal.createTransport();
processingSignalFuture.complete(processingSignalTransport);
}
- OnDeviceSandboxedInferenceService.this.onProcessRequestStreaming(callerUid,
- feature,
- request,
- requestType,
- CancellationSignal.fromTransport(transport),
- ProcessingSignal.fromTransport(processingSignalTransport),
- wrapStreamingResponseCallback(callback));
+
+
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceSandboxedInferenceService::onProcessRequestStreaming,
+ OnDeviceSandboxedInferenceService.this, callerUid,
+ feature,
+ request,
+ requestType,
+ CancellationSignal.fromTransport(transport),
+ ProcessingSignal.fromTransport(processingSignalTransport),
+ wrapStreamingResponseCallback(callback)));
}
@Override
@@ -200,11 +226,14 @@
processingSignalTransport = ProcessingSignal.createTransport();
processingSignalFuture.complete(processingSignalTransport);
}
- OnDeviceSandboxedInferenceService.this.onProcessRequest(callerUid, feature,
- request, requestType,
- CancellationSignal.fromTransport(transport),
- ProcessingSignal.fromTransport(processingSignalTransport),
- wrapResponseCallback(callback));
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceSandboxedInferenceService::onProcessRequest,
+ OnDeviceSandboxedInferenceService.this, callerUid, feature,
+ request, requestType,
+ CancellationSignal.fromTransport(transport),
+ ProcessingSignal.fromTransport(processingSignalTransport),
+ wrapResponseCallback(callback)));
}
@Override
@@ -212,10 +241,11 @@
IProcessingUpdateStatusCallback callback) {
Objects.requireNonNull(processingState);
Objects.requireNonNull(callback);
-
- OnDeviceSandboxedInferenceService.this.onUpdateProcessingState(processingState,
- wrapOutcomeReceiver(callback)
- );
+ mHandler.executeOrSendMessage(
+ obtainMessage(
+ OnDeviceSandboxedInferenceService::onUpdateProcessingState,
+ OnDeviceSandboxedInferenceService.this, processingState,
+ wrapOutcomeReceiver(callback)));
}
};
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index cce4f7b..a78a417 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -310,6 +310,7 @@
* @see Layout#getUseBoundsForWidth()
* @see Layout.Builder#setUseBoundsForWidth(boolean)
*/
+ @SuppressLint("MissingGetterMatchingBuilder") // The base class `Layout` has a getter.
@NonNull
@FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
public Builder setUseBoundsForWidth(boolean useBoundsForWidth) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 3dd3a9e..95460a3 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -447,6 +447,7 @@
* @see Layout#getUseBoundsForWidth()
* @see Layout.Builder#setUseBoundsForWidth(boolean)
*/
+ @SuppressLint("MissingGetterMatchingBuilder") // The base class `Layout` has a getter.
@NonNull
@FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
public Builder setUseBoundsForWidth(boolean useBoundsForWidth) {
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index 56df328..70dc300e 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -181,3 +181,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "missing_getter_apis"
+ namespace: "text"
+ description: "Fix the lint warning about missing getters."
+ bug: "340875345"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4475418..ba1915c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -916,6 +916,12 @@
* {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the
* size of the current app window is returned. As a result, in multi-window mode, the
* returned size can be smaller than the size of the device screen.
+ * The returned window size can vary depending on API level:
+ * <ul>
+ * <li>API level 35 and above, the window size will be returned.
+ * <li>API level 34 and below, the window size minus system decoration areas and
+ * display cutout is returned.
+ * </ul>
* <li>If size is requested from a non-activity context (for example, the application
* context, where the WindowManager is accessed by
* {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the
@@ -924,9 +930,10 @@
* <li>API level 29 and below — The size of the entire display (based on
* current rotation) minus system decoration areas is returned.
* <li>API level 30 and above — The size of the top running activity in the
- * current process is returned. If the current process has no running
- * activities, the size of the device default display, including system
- * decoration areas, is returned.
+ * current process is returned, system decoration areas exclusion follows the
+ * behavior defined above, based on the caller's API level. If the current
+ * process has no running activities, the size of the device default display,
+ * including system decoration areas, is returned.
* </ul>
* </ul>
*
@@ -1218,11 +1225,24 @@
}
/**
- * Gets the supported modes of this display.
+ * Gets the supported modes of this display, might include synthetic modes
*/
public Mode[] getSupportedModes() {
synchronized (mLock) {
updateDisplayInfoLocked();
+ final Display.Mode[] modes = mDisplayInfo.appsSupportedModes;
+ return Arrays.copyOf(modes, modes.length);
+ }
+ }
+
+ /**
+ * Gets system supported modes of this display,
+ * @hide
+ */
+ @SuppressLint("ArrayReturn")
+ public @NonNull Mode[] getSystemSupportedModes() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
final Display.Mode[] modes = mDisplayInfo.supportedModes;
return Arrays.copyOf(modes, modes.length);
}
@@ -2206,6 +2226,7 @@
@NonNull
@HdrCapabilities.HdrType
private final int[] mSupportedHdrTypes;
+ private final boolean mIsSynthetic;
/**
* @hide
@@ -2219,13 +2240,6 @@
/**
* @hide
*/
- public Mode(int width, int height, float refreshRate, float vsyncRate) {
- this(INVALID_MODE_ID, width, height, refreshRate, vsyncRate, new float[0], new int[0]);
- }
-
- /**
- * @hide
- */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Mode(int modeId, int width, int height, float refreshRate) {
this(modeId, width, height, refreshRate, refreshRate, new float[0], new int[0]);
@@ -2246,11 +2260,21 @@
*/
public Mode(int modeId, int width, int height, float refreshRate, float vsyncRate,
float[] alternativeRefreshRates, @HdrCapabilities.HdrType int[] supportedHdrTypes) {
+ this(modeId, width, height, refreshRate, vsyncRate, false, alternativeRefreshRates,
+ supportedHdrTypes);
+ }
+ /**
+ * @hide
+ */
+ public Mode(int modeId, int width, int height, float refreshRate, float vsyncRate,
+ boolean isSynthetic, float[] alternativeRefreshRates,
+ @HdrCapabilities.HdrType int[] supportedHdrTypes) {
mModeId = modeId;
mWidth = width;
mHeight = height;
mPeakRefreshRate = refreshRate;
mVsyncRate = vsyncRate;
+ mIsSynthetic = isSynthetic;
mAlternativeRefreshRates =
Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
Arrays.sort(mAlternativeRefreshRates);
@@ -2315,6 +2339,15 @@
}
/**
+ * Returns true if mode is synthetic and does not have corresponding
+ * SurfaceControl.DisplayMode
+ * @hide
+ */
+ public boolean isSynthetic() {
+ return mIsSynthetic;
+ }
+
+ /**
* Returns an array of refresh rates which can be switched to seamlessly.
* <p>
* A seamless switch is one without visual interruptions, such as a black screen for
@@ -2449,6 +2482,7 @@
.append(", height=").append(mHeight)
.append(", fps=").append(mPeakRefreshRate)
.append(", vsync=").append(mVsyncRate)
+ .append(", synthetic=").append(mIsSynthetic)
.append(", alternativeRefreshRates=")
.append(Arrays.toString(mAlternativeRefreshRates))
.append(", supportedHdrTypes=")
@@ -2464,7 +2498,7 @@
private Mode(Parcel in) {
this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.readFloat(),
- in.createFloatArray(), in.createIntArray());
+ in.readBoolean(), in.createFloatArray(), in.createIntArray());
}
@Override
@@ -2474,6 +2508,7 @@
out.writeInt(mHeight);
out.writeFloat(mPeakRefreshRate);
out.writeFloat(mVsyncRate);
+ out.writeBoolean(mIsSynthetic);
out.writeFloatArray(mAlternativeRefreshRates);
out.writeIntArray(mSupportedHdrTypes);
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 5654bc1..da86e2d 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -211,6 +211,12 @@
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
+ /**
+ * The supported modes that will be exposed externally.
+ * Might have different set of modes that supportedModes for VRR displays
+ */
+ public Display.Mode[] appsSupportedModes = Display.Mode.EMPTY_ARRAY;
+
/** The active color mode. */
public int colorMode;
@@ -429,6 +435,7 @@
&& defaultModeId == other.defaultModeId
&& userPreferredModeId == other.userPreferredModeId
&& Arrays.equals(supportedModes, other.supportedModes)
+ && Arrays.equals(appsSupportedModes, other.appsSupportedModes)
&& colorMode == other.colorMode
&& Arrays.equals(supportedColorModes, other.supportedColorModes)
&& Objects.equals(hdrCapabilities, other.hdrCapabilities)
@@ -488,6 +495,8 @@
defaultModeId = other.defaultModeId;
userPreferredModeId = other.userPreferredModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
+ appsSupportedModes = Arrays.copyOf(
+ other.appsSupportedModes, other.appsSupportedModes.length);
colorMode = other.colorMode;
supportedColorModes = Arrays.copyOf(
other.supportedColorModes, other.supportedColorModes.length);
@@ -545,6 +554,11 @@
for (int i = 0; i < nModes; i++) {
supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
}
+ int nAppModes = source.readInt();
+ appsSupportedModes = new Display.Mode[nAppModes];
+ for (int i = 0; i < nAppModes; i++) {
+ appsSupportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
+ }
colorMode = source.readInt();
int nColorModes = source.readInt();
supportedColorModes = new int[nColorModes];
@@ -611,6 +625,10 @@
for (int i = 0; i < supportedModes.length; i++) {
supportedModes[i].writeToParcel(dest, flags);
}
+ dest.writeInt(appsSupportedModes.length);
+ for (int i = 0; i < appsSupportedModes.length; i++) {
+ appsSupportedModes[i].writeToParcel(dest, flags);
+ }
dest.writeInt(colorMode);
dest.writeInt(supportedColorModes.length);
for (int i = 0; i < supportedColorModes.length; i++) {
@@ -849,8 +867,10 @@
sb.append(defaultModeId);
sb.append(", userPreferredModeId ");
sb.append(userPreferredModeId);
- sb.append(", modes ");
+ sb.append(", supportedModes ");
sb.append(Arrays.toString(supportedModes));
+ sb.append(", appsSupportedModes ");
+ sb.append(Arrays.toString(appsSupportedModes));
sb.append(", hdrCapabilities ");
sb.append(hdrCapabilities);
sb.append(", userDisabledHdrTypes ");
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 1898407..b65e3eb 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -156,6 +156,13 @@
private float mOffsetX;
private float mOffsetY;
+ /**
+ * The View#DRAG_FLAG_* flags used to start the current drag, only provided if the target window
+ * has the {@link WindowManager.LayoutParams#PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP} flag
+ * and is only sent with {@link #ACTION_DRAG_STARTED} and {@link #ACTION_DROP}.
+ */
+ private int mFlags;
+
private DragEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
@@ -290,7 +297,7 @@
private DragEvent() {
}
- private void init(int action, float x, float y, float offsetX, float offsetY,
+ private void init(int action, float x, float y, float offsetX, float offsetY, int flags,
ClipDescription description, ClipData data, SurfaceControl dragSurface,
IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result) {
mAction = action;
@@ -298,6 +305,7 @@
mY = y;
mOffsetX = offsetX;
mOffsetY = offsetY;
+ mFlags = flags;
mClipDescription = description;
mClipData = data;
mDragSurface = dragSurface;
@@ -307,19 +315,19 @@
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, 0f, 0f, null, null, null, null, null, false);
+ return DragEvent.obtain(0, 0f, 0f, 0f, 0f, 0, null, null, null, null, null, false);
}
/** @hide */
public static DragEvent obtain(int action, float x, float y, float offsetX, float offsetY,
- Object localState, ClipDescription description, ClipData data,
+ int flags, Object localState, ClipDescription description, ClipData data,
SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions,
boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
ev = new DragEvent();
- ev.init(action, x, y, offsetX, offsetY, description, data, dragSurface,
+ ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
dragAndDropPermissions, localState, result);
return ev;
}
@@ -331,7 +339,7 @@
ev.mRecycled = false;
ev.mNext = null;
- ev.init(action, x, y, offsetX, offsetY, description, data, dragSurface,
+ ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
dragAndDropPermissions, localState, result);
return ev;
@@ -341,8 +349,8 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static DragEvent obtain(DragEvent source) {
return obtain(source.mAction, source.mX, source.mY, source.mOffsetX, source.mOffsetY,
- source.mLocalState, source.mClipDescription, source.mClipData, source.mDragSurface,
- source.mDragAndDropPermissions, source.mDragResult);
+ source.mFlags, source.mLocalState, source.mClipDescription, source.mClipData,
+ source.mDragSurface, source.mDragAndDropPermissions, source.mDragResult);
}
/**
@@ -424,6 +432,11 @@
}
/** @hide */
+ public int getDragFlags() {
+ return mFlags;
+ }
+
+ /** @hide */
public IDragAndDropPermissions getDragAndDropPermissions() {
return mDragAndDropPermissions;
}
@@ -571,6 +584,7 @@
dest.writeFloat(mY);
dest.writeFloat(mOffsetX);
dest.writeFloat(mOffsetY);
+ dest.writeInt(mFlags);
dest.writeInt(mDragResult ? 1 : 0);
if (mClipData == null) {
dest.writeInt(0);
@@ -610,6 +624,7 @@
event.mY = in.readFloat();
event.mOffsetX = in.readFloat();
event.mOffsetY = in.readFloat();
+ event.mFlags = in.readInt();
event.mDragResult = (in.readInt() != 0);
if (in.readInt() != 0) {
event.mClipData = ClipData.CREATOR.createFromParcel(in);
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3743035..f628c21 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -68,7 +68,8 @@
/**
* Called when this window retrieved control over a specified set of insets sources.
*/
- void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+ void insetsControlChanged(in InsetsState insetsState,
+ in InsetsSourceControl.Array activeControls);
/**
* Called when a set of insets source window should be shown by policy.
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index 8c14de6..fc1852d 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -255,10 +255,11 @@
private boolean isBackAnimationAllowed() {
// back animation is allowed in all cases except when softInputMode is adjust_resize AND
- // there is no app-registered WindowInsetsAnimationCallback.
+ // there is no app-registered WindowInsetsAnimationCallback AND edge-to-edge is not enabled.
return (mViewRoot.mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
!= SOFT_INPUT_ADJUST_RESIZE
- || (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback());
+ || (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback())
+ || mViewRoot.mAttachInfo.mContentOnApplyWindowInsetsListener == null;
}
private boolean isAdjustPan() {
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index d22d2a5..609ad5b 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -78,6 +78,7 @@
private final InputDeviceIdentifier mIdentifier;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private final boolean mIsExternal;
+ @Source
private final int mSources;
private final int mKeyboardType;
private final KeyCharacterMap mKeyCharacterMap;
@@ -92,6 +93,7 @@
private final boolean mHasBattery;
private final HostUsiVersion mHostUsiVersion;
private final int mAssociatedDisplayId;
+ private final boolean mEnabled;
private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
private final ViewBehavior mViewBehavior = new ViewBehavior(this);
@@ -359,6 +361,28 @@
*/
public static final int SOURCE_ANY = 0xffffff00;
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SOURCE_" }, value = {
+ SOURCE_UNKNOWN,
+ SOURCE_KEYBOARD,
+ SOURCE_DPAD,
+ SOURCE_GAMEPAD,
+ SOURCE_TOUCHSCREEN,
+ SOURCE_MOUSE,
+ SOURCE_STYLUS,
+ SOURCE_BLUETOOTH_STYLUS,
+ SOURCE_TRACKBALL,
+ SOURCE_MOUSE_RELATIVE,
+ SOURCE_TOUCHPAD,
+ SOURCE_TOUCH_NAVIGATION,
+ SOURCE_ROTARY_ENCODER,
+ SOURCE_JOYSTICK,
+ SOURCE_HDMI,
+ SOURCE_SENSOR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Source {}
+
/**
* Constant for retrieving the range of values for {@link MotionEvent#AXIS_X}.
*
@@ -479,7 +503,7 @@
int keyboardType, KeyCharacterMap keyCharacterMap, @Nullable String keyboardLanguageTag,
@Nullable String keyboardLayoutType, boolean hasVibrator, boolean hasMicrophone,
boolean hasButtonUnderPad, boolean hasSensor, boolean hasBattery, int usiVersionMajor,
- int usiVersionMinor, int associatedDisplayId) {
+ int usiVersionMinor, int associatedDisplayId, boolean enabled) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -510,6 +534,7 @@
mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
mHostUsiVersion = new HostUsiVersion(usiVersionMajor, usiVersionMinor);
mAssociatedDisplayId = associatedDisplayId;
+ mEnabled = enabled;
}
private InputDevice(Parcel in) {
@@ -534,6 +559,7 @@
mHasBattery = in.readInt() != 0;
mHostUsiVersion = HostUsiVersion.CREATOR.createFromParcel(in);
mAssociatedDisplayId = in.readInt();
+ mEnabled = in.readInt() != 0;
mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
int numRanges = in.readInt();
@@ -578,6 +604,8 @@
private int mUsiVersionMajor = -1;
private int mUsiVersionMinor = -1;
private int mAssociatedDisplayId = Display.INVALID_DISPLAY;
+ // The default is true, the same as the native default state.
+ private boolean mEnabled = true;
private List<MotionRange> mMotionRanges = new ArrayList<>();
private boolean mShouldSmoothScroll;
@@ -708,6 +736,12 @@
return this;
}
+ /** @see InputDevice#isEnabled() */
+ public Builder setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ return this;
+ }
+
/** @see InputDevice#getMotionRanges() */
public Builder addMotionRange(int axis, int source,
float min, float max, float flat, float fuzz, float resolution) {
@@ -749,7 +783,8 @@
mHasBattery,
mUsiVersionMajor,
mUsiVersionMinor,
- mAssociatedDisplayId);
+ mAssociatedDisplayId,
+ mEnabled);
final int numRanges = mMotionRanges.size();
for (int i = 0; i < numRanges; i++) {
@@ -1298,7 +1333,7 @@
* @return Whether the input device is enabled.
*/
public boolean isEnabled() {
- return InputManagerGlobal.getInstance().isInputDeviceEnabled(mId);
+ return mEnabled;
}
/**
@@ -1588,6 +1623,7 @@
out.writeInt(mHasBattery ? 1 : 0);
mHostUsiVersion.writeToParcel(out, flags);
out.writeInt(mAssociatedDisplayId);
+ out.writeInt(mEnabled ? 1 : 0);
int numRanges = mMotionRanges.size();
numRanges = numRanges > MAX_RANGES ? MAX_RANGES : numRanges;
@@ -1619,6 +1655,7 @@
description.append(" Generation: ").append(mGeneration).append("\n");
description.append(" Location: ").append(mIsExternal ? "external" : "built-in").append(
"\n");
+ description.append(" Enabled: ").append(isEnabled()).append("\n");
description.append(" Keyboard Type: ");
switch (mKeyboardType) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index d7f2b01..1fc98cf 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -303,7 +303,7 @@
}
/** Not running an animation. */
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
public static final int ANIMATION_TYPE_NONE = -1;
/** Running animation will show insets */
@@ -317,7 +317,7 @@
public static final int ANIMATION_TYPE_USER = 2;
/** Running animation will resize insets */
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
public static final int ANIMATION_TYPE_RESIZE = 3;
@Retention(RetentionPolicy.SOURCE)
@@ -1262,9 +1262,11 @@
mHost.getInputMethodManager(), null /* icProto */);
}
- final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_USER,
- ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION,
- mHost.isHandlingPointerEvent() /* fromUser */);
+ final var statsToken = (types & ime()) == 0 ? null
+ : ImeTracker.forLogging().onStart(ImeTracker.TYPE_USER,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION,
+ mHost.isHandlingPointerEvent() /* fromUser */);
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
interpolator, animationType,
getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack),
@@ -1714,7 +1716,7 @@
mImeSourceConsumer.onWindowFocusLost();
}
- @VisibleForTesting
+ @VisibleForTesting(visibility = PACKAGE)
public @AnimationType int getAnimationType(@InsetsType int type) {
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index fdb2a6e..6c670f5 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
+import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
import static android.view.InsetsSourceConsumerProto.ANIMATION_STATE;
@@ -31,6 +32,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -179,10 +181,11 @@
mController.notifyVisibilityChanged();
}
- // If we have a new leash, make sure visibility is up-to-date, even though we
- // didn't want to run an animation above.
- if (mController.getAnimationType(mType) == ANIMATION_TYPE_NONE) {
- applyRequestedVisibilityToControl();
+ // If there is no animation controlling the leash, make sure the visibility and the
+ // position is up-to-date.
+ final int animType = mController.getAnimationType(mType);
+ if (animType == ANIMATION_TYPE_NONE || animType == ANIMATION_TYPE_RESIZE) {
+ applyRequestedVisibilityAndPositionToControl();
}
// Remove the surface that owned by last control when it lost.
@@ -371,21 +374,27 @@
if (DEBUG) Log.d(TAG, "updateSource: " + newSource);
}
- private void applyRequestedVisibilityToControl() {
- if (mSourceControl == null || mSourceControl.getLeash() == null) {
+ private void applyRequestedVisibilityAndPositionToControl() {
+ if (mSourceControl == null) {
+ return;
+ }
+ final SurfaceControl leash = mSourceControl.getLeash();
+ if (leash == null) {
return;
}
final boolean requestedVisible = (mController.getRequestedVisibleTypes() & mType) != 0;
+ final Point surfacePosition = mSourceControl.getSurfacePosition();
try (Transaction t = mTransactionSupplier.get()) {
if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + requestedVisible);
if (requestedVisible) {
- t.show(mSourceControl.getLeash());
+ t.show(leash);
} else {
- t.hide(mSourceControl.getLeash());
+ t.hide(leash);
}
// Ensure the alpha value is aligned with the actual requested visibility.
- t.setAlpha(mSourceControl.getLeash(), requestedVisible ? 1 : 0);
+ t.setAlpha(leash, requestedVisible ? 1 : 0);
+ t.setPosition(leash, surfacePosition.x, surfacePosition.y);
t.apply();
}
onPerceptible(requestedVisible);
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 527c7ed..4e5cb58 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -32,6 +32,7 @@
import android.view.WindowInsets.Type.InsetsType;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Objects;
import java.util.function.Consumer;
@@ -268,6 +269,10 @@
public Array() {
}
+ public Array(@NonNull Array other) {
+ mControls = other.mControls;
+ }
+
public Array(Parcel in) {
readFromParcel(in);
}
@@ -303,5 +308,22 @@
return new Array[size];
}
};
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final InsetsSourceControl.Array other = (InsetsSourceControl.Array) o;
+ return Arrays.equals(mControls, other.mControls);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mControls);
+ }
}
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 154f1fe..01015ea 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -20,6 +20,7 @@
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -35,6 +36,8 @@
import com.android.hardware.input.Flags;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;
/**
@@ -944,7 +947,7 @@
@FlaggedApi(Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE)
public static final int KEYCODE_SCREENSHOT = 318;
- /**
+ /**
* Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
* @hide
*/
@@ -1034,6 +1037,15 @@
@Deprecated
public static final int ACTION_MULTIPLE = 2;
+ /** @hide */
+ @IntDef(prefix = {"ACTION_"}, value = {
+ ACTION_DOWN,
+ ACTION_UP,
+ ACTION_MULTIPLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Action {}
+
/**
* SHIFT key locked in CAPS mode.
* Reserved for use by {@link MetaKeyKeyListener} for a published constant in its API.
@@ -1222,6 +1234,33 @@
*/
public static final int META_SCROLL_LOCK_ON = 0x400000;
+ /** @hide */
+ @IntDef(flag = true, prefix = {"META_"}, value = {
+ META_CAP_LOCKED,
+ META_ALT_LOCKED,
+ META_SYM_LOCKED,
+ META_SELECTING,
+ META_ALT_ON,
+ META_ALT_LEFT_ON,
+ META_ALT_RIGHT_ON,
+ META_SHIFT_ON,
+ META_SHIFT_LEFT_ON,
+ META_SHIFT_RIGHT_ON,
+ META_SYM_ON,
+ META_FUNCTION_ON,
+ META_CTRL_ON,
+ META_CTRL_LEFT_ON,
+ META_CTRL_RIGHT_ON,
+ META_META_ON,
+ META_META_LEFT_ON,
+ META_META_RIGHT_ON,
+ META_CAPS_LOCK_ON,
+ META_NUM_LOCK_ON,
+ META_SCROLL_LOCK_ON,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MetaState {}
+
/**
* This mask is a combination of {@link #META_SHIFT_ON}, {@link #META_SHIFT_LEFT_ON}
* and {@link #META_SHIFT_RIGHT_ON}.
@@ -1366,6 +1405,27 @@
*/
public static final int FLAG_TAINTED = IInputConstants.INPUT_EVENT_FLAG_TAINTED;
+ /** @hide */
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_WOKE_HERE,
+ FLAG_SOFT_KEYBOARD,
+ FLAG_KEEP_TOUCH_MODE,
+ FLAG_FROM_SYSTEM,
+ FLAG_EDITOR_ACTION,
+ FLAG_CANCELED,
+ FLAG_VIRTUAL_HARD_KEY,
+ FLAG_LONG_PRESS,
+ FLAG_CANCELED_LONG_PRESS,
+ FLAG_TRACKING,
+ FLAG_FALLBACK,
+ FLAG_IS_ACCESSIBILITY_EVENT,
+ FLAG_PREDISPATCH,
+ FLAG_START_TRACKING,
+ FLAG_TAINTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Flag {}
+
/**
* Returns the maximum keycode.
*/
@@ -1401,8 +1461,10 @@
// NOTE: mHmac is private and not used in this class, but it's used on native side / parcel.
private @Nullable byte[] mHmac;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @MetaState
private int mMetaState;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Action
private int mAction;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int mKeyCode;
@@ -1411,6 +1473,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int mRepeatCount;
@UnsupportedAppUsage
+ @Flag
private int mFlags;
/**
* The time when the key initially was pressed, in nanoseconds. Only millisecond precision is
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 38f9a91..6db40bf 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -50,6 +50,7 @@
import dalvik.annotation.optimization.FastNative;
import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -445,6 +446,25 @@
@Deprecated
public static final int ACTION_POINTER_ID_SHIFT = 8;
+ /** @hide */
+ @IntDef(prefix = { "ACTION_" }, value = {
+ ACTION_DOWN,
+ ACTION_UP,
+ ACTION_MOVE,
+ ACTION_CANCEL,
+ ACTION_OUTSIDE,
+ ACTION_POINTER_DOWN,
+ ACTION_POINTER_UP,
+ ACTION_HOVER_MOVE,
+ ACTION_SCROLL,
+ ACTION_HOVER_ENTER,
+ ACTION_HOVER_EXIT,
+ ACTION_BUTTON_PRESS,
+ ACTION_BUTTON_RELEASE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ActionMasked {}
+
/**
* This flag indicates that the window that received this motion event is partly
* or wholly obscured by another visible window above it and the event directly passed through
@@ -548,6 +568,21 @@
public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS =
MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS;
+ /** @hide */
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_WINDOW_IS_OBSCURED,
+ FLAG_WINDOW_IS_PARTIALLY_OBSCURED,
+ FLAG_HOVER_EXIT_PENDING,
+ FLAG_IS_GENERATED_GESTURE,
+ FLAG_CANCELED,
+ FLAG_NO_FOCUS_CHANGE,
+ FLAG_IS_ACCESSIBILITY_EVENT,
+ FLAG_TAINTED,
+ FLAG_TARGET_ACCESSIBILITY_FOCUS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Flag {}
+
/**
* Flag indicating the motion event intersected the top edge of the screen.
*/
@@ -1422,6 +1457,63 @@
names.append(AXIS_GESTURE_SWIPE_FINGER_COUNT, "AXIS_GESTURE_SWIPE_FINGER_COUNT");
}
+ /** @hide */
+ @IntDef(prefix = { "AXIS_" }, value = {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_PRESSURE,
+ AXIS_SIZE,
+ AXIS_TOUCH_MAJOR,
+ AXIS_TOUCH_MINOR,
+ AXIS_TOOL_MAJOR,
+ AXIS_TOOL_MINOR,
+ AXIS_ORIENTATION,
+ AXIS_VSCROLL,
+ AXIS_HSCROLL,
+ AXIS_Z,
+ AXIS_RX,
+ AXIS_RY,
+ AXIS_RZ,
+ AXIS_HAT_X,
+ AXIS_HAT_Y,
+ AXIS_LTRIGGER,
+ AXIS_RTRIGGER,
+ AXIS_THROTTLE,
+ AXIS_RUDDER,
+ AXIS_WHEEL,
+ AXIS_GAS,
+ AXIS_BRAKE,
+ AXIS_DISTANCE,
+ AXIS_TILT,
+ AXIS_SCROLL,
+ AXIS_RELATIVE_X,
+ AXIS_RELATIVE_Y,
+ AXIS_GENERIC_1,
+ AXIS_GENERIC_2,
+ AXIS_GENERIC_3,
+ AXIS_GENERIC_4,
+ AXIS_GENERIC_5,
+ AXIS_GENERIC_6,
+ AXIS_GENERIC_7,
+ AXIS_GENERIC_8,
+ AXIS_GENERIC_9,
+ AXIS_GENERIC_10,
+ AXIS_GENERIC_11,
+ AXIS_GENERIC_12,
+ AXIS_GENERIC_13,
+ AXIS_GENERIC_14,
+ AXIS_GENERIC_15,
+ AXIS_GENERIC_16,
+ AXIS_GESTURE_X_OFFSET,
+ AXIS_GESTURE_Y_OFFSET,
+ AXIS_GESTURE_SCROLL_X_DISTANCE,
+ AXIS_GESTURE_SCROLL_Y_DISTANCE,
+ AXIS_GESTURE_PINCH_SCALE_FACTOR,
+ AXIS_GESTURE_SWIPE_FINGER_COUNT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Axis {}
+
/**
* Button constant: Primary button (left mouse button).
*
@@ -1522,6 +1614,19 @@
"0x80000000",
};
+ /** @hide */
+ @IntDef(flag = true, prefix = { "BUTTON_" }, value = {
+ BUTTON_PRIMARY,
+ BUTTON_SECONDARY,
+ BUTTON_TERTIARY,
+ BUTTON_BACK,
+ BUTTON_FORWARD,
+ BUTTON_STYLUS_PRIMARY,
+ BUTTON_STYLUS_SECONDARY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Button {}
+
/**
* Classification constant: None.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0715474..8e2b7f1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10234,7 +10234,7 @@
// force DRAG_EXITED_EVENT if appropriate
DragEvent event = DragEvent.obtain(
isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
- x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
+ x, y, 0 /* offsetX */, 0 /* offsetY */, 0 /* flags */, null/* localState */,
null/* description */, null /* data */, null /* dragSurface */,
null /* dragAndDropPermissions */, false /* result */);
dispatchDragEvent(event);
@@ -11258,10 +11258,10 @@
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl.Array activeControls) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
- viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
+ viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls.get());
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f22e8f5..0f54940b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -781,7 +781,7 @@
* <p>
* The metrics describe the size of the area the window would occupy with
* {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
- * such a window would have.
+ * such a window would have. The {@link WindowInsets} are not deducted from the bounds.
* <p>
* The value of this is based on the <b>current</b> windowing state of the system.
*
@@ -811,7 +811,7 @@
* <p>
* The metrics describe the size of the largest potential area the window might occupy with
* {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
- * such a window would have.
+ * such a window would have. The {@link WindowInsets} are not deducted from the bounds.
* <p>
* Note that this might still be smaller than the size of the physical display if certain areas
* of the display are not available to windows created in this {@link Context}.
@@ -4264,11 +4264,9 @@
* no letterbox is applied."/>
*
* <p>
- * A cutout in the corner is considered to be on the short edge: <br/>
- * <img src="{@docRoot}reference/android/images/display_cutout/short_edge/fullscreen_corner_no_letterbox.png"
- * height="720"
- * alt="Screenshot of a fullscreen activity on a display with a cutout in the corner in
- * portrait, no letterbox is applied."/>
+ * A cutout in the corner can be considered to be on different edge in different device
+ * rotations. This behavior may vary from device to device. Use this flag is possible to
+ * letterbox your app if the display cutout is at corner.
*
* <p>
* On the other hand, should the cutout be on the long edge of the display, a letterbox will
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index 26298bc..8bcc9de 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -101,9 +101,13 @@
* Returns the bounds of the area associated with this window or {@code UiContext}.
* <p>
* <b>Note that the size of the reported bounds can have different size than
- * {@link Display#getSize(Point)}.</b> This method reports the window size including all system
- * bar areas, while {@link Display#getSize(Point)} reports the area excluding navigation bars
- * and display cutout areas. The value reported by {@link Display#getSize(Point)} can be
+ * {@link Display#getSize(Point)} based on your target API level and calling context.</b>
+ * This method reports the window size including all system
+ * bar areas, while {@link Display#getSize(Point)} can report the area excluding navigation bars
+ * and display cutout areas depending on the calling context and target SDK level. Please refer
+ * to {@link Display#getSize(Point)} for details.
+ * <p>
+ * The value reported by {@link Display#getSize(Point)} excluding system decoration areas can be
* obtained by using:
* <pre class="prettyprint">
* final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
diff --git a/core/java/android/view/accessibility/IMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IMagnificationConnectionCallback.aidl
index 0ba61b1..6ff7f7e 100644
--- a/core/java/android/view/accessibility/IMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IMagnificationConnectionCallback.aidl
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, Veorsion 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
@@ -32,6 +32,7 @@
* @param displayId The logical display id.
* @param bounds The window magnifier bounds in screen coordinates.
*/
+ @RequiresNoPermission
void onWindowMagnifierBoundsChanged(int displayId, in Rect bounds);
/**
@@ -41,6 +42,7 @@
* @param displayId The logical display id.
* @param magnificationMode new magnification mode.
*/
+ @RequiresNoPermission
void onChangeMagnificationMode(int displayId, int magnificationMode);
/**
@@ -49,6 +51,7 @@
* @param displayId The logical display id.
* @param sourceBounds The magnified bounds in screen coordinates.
*/
+ @RequiresNoPermission
void onSourceBoundsChanged(int displayId, in Rect sourceBounds);
/**
@@ -59,6 +62,7 @@
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
* @param updatePersistence whether the new scale should be persisted in Settings
*/
+ @RequiresNoPermission
void onPerformScaleAction(int displayId, float scale, boolean updatePersistence);
/**
@@ -66,6 +70,7 @@
*
* @param displayId The logical display id.
*/
+ @RequiresNoPermission
void onAccessibilityActionPerformed(int displayId);
/**
@@ -73,6 +78,7 @@
*
* @param displayId The logical display id.
*/
+ @RequiresNoPermission
void onMove(int displayId);
}
diff --git a/core/java/android/view/accessibility/IRemoteMagnificationAnimationCallback.aidl b/core/java/android/view/accessibility/IRemoteMagnificationAnimationCallback.aidl
index 946ea16..421dfd0 100644
--- a/core/java/android/view/accessibility/IRemoteMagnificationAnimationCallback.aidl
+++ b/core/java/android/view/accessibility/IRemoteMagnificationAnimationCallback.aidl
@@ -29,5 +29,6 @@
* @param success {@code true} if animating successfully with given spec or the spec did not
* change. Otherwise {@code false}
*/
+ @RequiresNoPermission
void onResult(boolean success);
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index da2bf9d..ab7b226 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -124,6 +124,7 @@
namespace: "accessibility"
name: "add_type_window_control"
is_exported: true
+ is_fixed_read_only: true
description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
bug: "320445550"
}
@@ -153,6 +154,16 @@
}
flag {
+ name: "restore_a11y_shortcut_target_service"
+ namespace: "accessibility"
+ description: "Perform merging and other bug fixes for SettingsProvider restore of ACCESSIBILITY_SHORTCUT_TARGET_SERVICES secure setting"
+ bug: "341374402"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "support_system_pinch_zoom_opt_out_apis"
namespace: "accessibility"
description: "Feature flag for declaring system pinch zoom opt-out apis"
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 5cdcf0a..46b41ae 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -532,7 +532,7 @@
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_IGNORE_VIEW_STATE_RESET_TO_EMPTY,
- false);
+ true);
}
/** @hide */
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index 3091bf4..acc74b2 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -40,6 +40,7 @@
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.InputMethodInfoSafeList;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -242,7 +243,12 @@
return new ArrayList<>();
}
try {
- return service.getInputMethodList(userId, directBootAwareness);
+ if (Flags.useInputMethodInfoSafeList()) {
+ return InputMethodInfoSafeList.extractFrom(
+ service.getInputMethodList(userId, directBootAwareness));
+ } else {
+ return service.getInputMethodListLegacy(userId, directBootAwareness);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -257,7 +263,12 @@
return new ArrayList<>();
}
try {
- return service.getEnabledInputMethodList(userId);
+ if (Flags.useInputMethodInfoSafeList()) {
+ return InputMethodInfoSafeList.extractFrom(
+ service.getEnabledInputMethodList(userId));
+ } else {
+ return service.getEnabledInputMethodListLegacy(userId);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 163e43a..94d7811 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -33,7 +33,7 @@
*
* @hide
*/
-public class BackProgressAnimator {
+public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateListener {
/**
* A factor to scale the input progress by, so that it works better with the spring.
* We divide the output progress by this value before sending it to apps, so that apps
@@ -43,6 +43,7 @@
private final SpringAnimation mSpring;
private ProgressCallback mCallback;
private float mProgress = 0;
+ private float mVelocity = 0;
private BackMotionEvent mLastBackEvent;
private boolean mBackAnimationInProgress = false;
@Nullable
@@ -67,7 +68,6 @@
@Override
public void setValue(BackProgressAnimator animator, float value) {
animator.setProgress(value);
- animator.updateProgressValue(value);
}
@Override
@@ -76,6 +76,11 @@
}
};
+ @Override
+ public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
+ updateProgressValue(value, velocity);
+ }
+
/** A callback to be invoked when there's a progress value update from the animator. */
public interface ProgressCallback {
@@ -85,6 +90,7 @@
public BackProgressAnimator() {
mSpring = new SpringAnimation(this, PROGRESS_PROP);
+ mSpring.addUpdateListener(this);
mSpring.setSpring(new SpringForce()
.setStiffness(SpringForce.STIFFNESS_MEDIUM)
.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY));
@@ -114,11 +120,10 @@
* dispatches as the progress animation updates.
*/
public void onBackStarted(BackMotionEvent event, ProgressCallback callback) {
- reset();
mLastBackEvent = event;
mCallback = callback;
mBackAnimationInProgress = true;
- updateProgressValue(0);
+ updateProgressValue(0, 0);
}
/**
@@ -127,7 +132,7 @@
public void reset() {
if (mBackCancelledFinishRunnable != null) {
// Ensure that last progress value that apps see is 0
- updateProgressValue(0);
+ updateProgressValue(0, 0);
invokeBackCancelledRunnable();
}
mSpring.animateToFinalPosition(0);
@@ -168,7 +173,15 @@
return mBackAnimationInProgress;
}
- private void updateProgressValue(float progress) {
+ /**
+ * @return The last recorded velocity. Unit: change in progress per second
+ */
+ public float getVelocity() {
+ return mVelocity / SCALE_FACTOR;
+ }
+
+ private void updateProgressValue(float progress, float velocity) {
+ mVelocity = velocity;
if (mLastBackEvent == null || mCallback == null || !mBackAnimationInProgress) {
return;
}
diff --git a/core/java/android/window/RemoteTransition.java b/core/java/android/window/RemoteTransition.java
index 4cc7ec5..15b3c44 100644
--- a/core/java/android/window/RemoteTransition.java
+++ b/core/java/android/window/RemoteTransition.java
@@ -22,15 +22,12 @@
import android.os.IBinder;
import android.os.Parcelable;
-import com.android.internal.util.DataClass;
-
/**
* Represents a remote transition animation and information required to run it (eg. the app thread
* that needs to be boosted).
* @hide
*/
-@DataClass(genToString = true, genSetters = true, genAidl = true)
-public class RemoteTransition implements Parcelable {
+public final class RemoteTransition implements Parcelable {
/** The actual remote-transition interface used to run the transition animation. */
private @NonNull IRemoteTransition mRemoteTransition;
@@ -41,12 +38,18 @@
/** A name for this that can be used for debugging. */
private @Nullable String mDebugName;
- /** Constructs with no app thread (animation runs in shell). */
+ /**
+ * Constructs with no app thread (animation runs in shell).
+ * @hide
+ */
public RemoteTransition(@NonNull IRemoteTransition remoteTransition) {
this(remoteTransition, null /* appThread */, null /* debugName */);
}
- /** Constructs with no app thread (animation runs in shell). */
+ /**
+ * Constructs with no app thread (animation runs in shell).
+ * @hide
+ */
public RemoteTransition(@NonNull IRemoteTransition remoteTransition,
@Nullable String debugName) {
this(remoteTransition, null /* appThread */, debugName);
@@ -57,21 +60,6 @@
return mRemoteTransition.asBinder();
}
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/RemoteTransition.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
/**
* Creates a new RemoteTransition.
*
@@ -81,8 +69,8 @@
* The application thread that will be running the remote transition.
* @param debugName
* A name for this that can be used for debugging.
+ * @hide
*/
- @DataClass.Generated.Member
public RemoteTransition(
@NonNull IRemoteTransition remoteTransition,
@Nullable IApplicationThread appThread,
@@ -98,16 +86,16 @@
/**
* The actual remote-transition interface used to run the transition animation.
+ * @hide
*/
- @DataClass.Generated.Member
public @NonNull IRemoteTransition getRemoteTransition() {
return mRemoteTransition;
}
/**
* The application thread that will be running the remote transition.
+ * @hide
*/
- @DataClass.Generated.Member
public @Nullable IApplicationThread getAppThread() {
return mAppThread;
}
@@ -115,15 +103,14 @@
/**
* A name for this that can be used for debugging.
*/
- @DataClass.Generated.Member
public @Nullable String getDebugName() {
return mDebugName;
}
/**
* The actual remote-transition interface used to run the transition animation.
+ * @hide
*/
- @DataClass.Generated.Member
public @NonNull RemoteTransition setRemoteTransition(@NonNull IRemoteTransition value) {
mRemoteTransition = value;
com.android.internal.util.AnnotationValidations.validate(
@@ -133,8 +120,8 @@
/**
* The application thread that will be running the remote transition.
+ * @hide
*/
- @DataClass.Generated.Member
public @NonNull RemoteTransition setAppThread(@NonNull IApplicationThread value) {
mAppThread = value;
return this;
@@ -143,14 +130,12 @@
/**
* A name for this that can be used for debugging.
*/
- @DataClass.Generated.Member
public @NonNull RemoteTransition setDebugName(@NonNull String value) {
mDebugName = value;
return this;
}
@Override
- @DataClass.Generated.Member
public String toString() {
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
@@ -163,7 +148,6 @@
}
@Override
- @DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -178,12 +162,10 @@
}
@Override
- @DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
protected RemoteTransition(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -198,11 +180,8 @@
NonNull.class, null, mRemoteTransition);
this.mAppThread = appThread;
this.mDebugName = debugName;
-
- // onConstructed(); // You can define this method to get a callback
}
- @DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<RemoteTransition> CREATOR
= new Parcelable.Creator<RemoteTransition>() {
@Override
@@ -215,17 +194,4 @@
return new RemoteTransition(in);
}
};
-
- @DataClass.Generated(
- time = 1678926409863L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java",
- inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.app.IApplicationThread mAppThread\nprivate @android.annotation.Nullable java.lang.String mDebugName\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
}
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 32e3f5a..1e5b097 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -189,6 +189,10 @@
@Nullable
private IBinder mActivityToken;
+ /** @see #setOtherActivityToken(IBinder) */
+ @Nullable
+ private IBinder mOtherActivityToken;
+
@Nullable
private TaskFragmentParentInfo mTaskFragmentParentInfo;
@@ -210,6 +214,7 @@
mActivityToken = in.readStrongBinder();
mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
mSurfaceControl = in.readTypedObject(SurfaceControl.CREATOR);
+ mOtherActivityToken = in.readStrongBinder();
}
@Override
@@ -224,6 +229,7 @@
dest.writeStrongBinder(mActivityToken);
dest.writeTypedObject(mTaskFragmentParentInfo, flags);
dest.writeTypedObject(mSurfaceControl, flags);
+ dest.writeStrongBinder(mOtherActivityToken);
}
/** The change is related to the TaskFragment created with this unique token. */
@@ -292,6 +298,21 @@
}
/**
+ * Token of another activity.
+ * <p>For {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}, it is the next activity (behind the
+ * reparented one) that fills the Task and occludes other activities. It will be the
+ * actual activity token if the activity belongs to the same process as the organizer.
+ * Otherwise, it is {@code null}.
+ *
+ * @hide
+ */
+ @NonNull
+ public Change setOtherActivityToken(@NonNull IBinder activityToken) {
+ mOtherActivityToken = requireNonNull(activityToken);
+ return this;
+ }
+
+ /**
* Sets info of the parent Task of the embedded TaskFragment.
* @see TaskFragmentParentInfo
*
@@ -350,6 +371,12 @@
return mActivityToken;
}
+ /** @hide */
+ @Nullable
+ public IBinder getOtherActivityToken() {
+ return mOtherActivityToken;
+ }
+
/**
* Obtains the {@link TaskFragmentParentInfo} for this transaction.
*/
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index a2e3d40..f0144cb 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -33,6 +33,8 @@
import android.view.Surface;
import android.view.WindowInsetsController;
+import com.android.window.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -334,7 +336,8 @@
*/
public synchronized void removeReference(@ReferenceFlags int usage) {
mInternalReferences &= ~usage;
- if (mInternalReferences == 0 && mSnapshot != null && !mSnapshot.isClosed()) {
+ if (Flags.releaseSnapshotAggressively() && mInternalReferences == 0 && mSnapshot != null
+ && !mSnapshot.isClosed()) {
mSnapshot.close();
}
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index bcae571..4ffd880 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -54,6 +54,8 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -69,6 +71,7 @@
* Modes are only a sub-set of all the transit-types since they are per-container
* @hide
*/
+ @Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "TRANSIT_" }, value = {
TRANSIT_NONE,
TRANSIT_OPEN,
@@ -102,11 +105,11 @@
/** The container is the display. */
public static final int FLAG_IS_DISPLAY = 1 << 5;
+ // TODO(b/194540864): Once we can include all windows in transition, then replace this with
+ // something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
/**
* Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
* used to prevent seamless rotation.
- * TODO(b/194540864): Once we can include all windows in transition, then replace this with
- * something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
*/
public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
@@ -173,6 +176,7 @@
public static final int FLAGS_IS_OCCLUDED_NO_ANIMATION = FLAG_IS_OCCLUDED | FLAG_NO_ANIMATION;
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "FLAG_" }, value = {
FLAG_NONE,
FLAG_SHOW_WALLPAPER,
@@ -267,11 +271,11 @@
}
/** @see #getRoot */
- public void addRoot(Root other) {
+ public void addRoot(@NonNull Root other) {
mRoots.add(other);
}
- public void setAnimationOptions(AnimationOptions options) {
+ public void setAnimationOptions(@Nullable AnimationOptions options) {
mOptions = options;
}
@@ -336,6 +340,7 @@
return mRoots.get(0).mLeash;
}
+ @Nullable
public AnimationOptions getAnimationOptions() {
return mOptions;
}
@@ -601,7 +606,7 @@
* Updates the callsites of all the surfaces in this transition, which aids in the debugging of
* lingering surfaces.
*/
- public void setUnreleasedWarningCallSiteForAllSurfaces(String callsite) {
+ public void setUnreleasedWarningCallSiteForAllSurfaces(@Nullable String callsite) {
for (int i = mChanges.size() - 1; i >= 0; --i) {
mChanges.get(i).getLeash().setUnreleasedWarningCallSite(callsite);
}
@@ -613,6 +618,7 @@
* the caller's references. Use this only if you need to "send" this to a local function which
* assumes it is being called from a remote caller.
*/
+ @NonNull
public TransitionInfo localRemoteCopy() {
final TransitionInfo out = new TransitionInfo(mType, mFlags);
out.mTrack = mTrack;
@@ -891,7 +897,7 @@
return mTaskInfo;
}
- public boolean getAllowEnterPip() {
+ public boolean isAllowEnterPip() {
return mAllowEnterPip;
}
@@ -1042,6 +1048,7 @@
}
/** Represents animation options during a transition */
+ @SuppressWarnings("UserHandleName")
public static final class AnimationOptions implements Parcelable {
private int mType;
@@ -1061,7 +1068,7 @@
mType = type;
}
- public AnimationOptions(Parcel in) {
+ private AnimationOptions(Parcel in) {
mType = in.readInt();
mEnterResId = in.readInt();
mExitResId = in.readInt();
@@ -1076,14 +1083,17 @@
}
/** Make basic customized animation for a package */
- public static AnimationOptions makeCommonAnimOptions(String packageName) {
+ @NonNull
+ public static AnimationOptions makeCommonAnimOptions(@NonNull String packageName) {
AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
options.mPackageName = packageName;
return options;
}
+ /** Make custom animation from the content of LayoutParams */
+ @NonNull
public static AnimationOptions makeAnimOptionsFromLayoutParameters(
- WindowManager.LayoutParams lp) {
+ @NonNull WindowManager.LayoutParams lp) {
AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
options.mPackageName = lp.packageName;
options.mAnimations = lp.windowAnimations;
@@ -1091,7 +1101,7 @@
}
/** Add customized window animations */
- public void addOptionsFromLayoutParameters(WindowManager.LayoutParams lp) {
+ public void addOptionsFromLayoutParameters(@NonNull WindowManager.LayoutParams lp) {
mAnimations = lp.windowAnimations;
}
@@ -1111,8 +1121,11 @@
customTransition.addCustomActivityTransition(enterResId, exitResId, backgroundColor);
}
- public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
- int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition) {
+ /** Make options for a custom animation based on anim resources */
+ @NonNull
+ public static AnimationOptions makeCustomAnimOptions(@NonNull String packageName,
+ int enterResId, int exitResId, @ColorInt int backgroundColor,
+ boolean overrideTaskTransition) {
AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
options.mPackageName = packageName;
options.mEnterResId = enterResId;
@@ -1122,6 +1135,8 @@
return options;
}
+ /** Make options for a clip-reveal animation. */
+ @NonNull
public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width,
int height) {
AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL);
@@ -1129,6 +1144,8 @@
return options;
}
+ /** Make options for a scale-up animation. */
+ @NonNull
public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width,
int height) {
AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP);
@@ -1136,7 +1153,9 @@
return options;
}
- public static AnimationOptions makeThumbnailAnimOptions(HardwareBuffer srcThumb,
+ /** Make options for a thumbnail-scaling animation. */
+ @NonNull
+ public static AnimationOptions makeThumbnailAnimOptions(@NonNull HardwareBuffer srcThumb,
int startX, int startY, boolean scaleUp) {
AnimationOptions options = new AnimationOptions(
scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
@@ -1145,11 +1164,15 @@
return options;
}
+ /** Make options for an animation that spans activities of different profiles. */
+ @NonNull
public static AnimationOptions makeCrossProfileAnimOptions() {
AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS);
return options;
}
+ /** Make options designating this as a scene-transition animation. */
+ @NonNull
public static AnimationOptions makeSceneTransitionAnimOptions() {
AnimationOptions options = new AnimationOptions(ANIM_SCENE_TRANSITION);
return options;
@@ -1175,14 +1198,17 @@
return mOverrideTaskTransition;
}
+ @Nullable
public String getPackageName() {
return mPackageName;
}
+ @NonNull
public Rect getTransitionBounds() {
return mTransitionBounds;
}
+ @Nullable
public HardwareBuffer getThumbnail() {
return mThumbnail;
}
@@ -1192,12 +1218,13 @@
}
/** Return customized activity transition if existed. */
+ @Nullable
public CustomActivityTransition getCustomActivityTransition(boolean open) {
return open ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeInt(mEnterResId);
dest.writeInt(mExitResId);
@@ -1247,6 +1274,7 @@
}
@Override
+ @NonNull
public String toString() {
final StringBuilder sb = new StringBuilder(32);
sb.append("{t=").append(typeToString(mType));
@@ -1261,7 +1289,7 @@
}
/** Customized activity transition. */
- public static class CustomActivityTransition implements Parcelable {
+ public static final class CustomActivityTransition implements Parcelable {
private int mCustomEnterResId;
private int mCustomExitResId;
private int mCustomBackgroundColor;
@@ -1302,7 +1330,7 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mCustomEnterResId);
dest.writeInt(mCustomExitResId);
dest.writeInt(mCustomBackgroundColor);
diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
index bd54e14..cc22576 100644
--- a/core/java/android/window/TransitionRequestInfo.java
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -113,7 +113,7 @@
/** Requested change to a display. */
@DataClass(genToString = true, genSetters = true, genBuilder = false, genConstructor = false)
- public static class DisplayChange implements Parcelable {
+ public static final class DisplayChange implements Parcelable {
private final int mDisplayId;
@Nullable private Rect mStartAbsBounds = null;
@Nullable private Rect mEndAbsBounds = null;
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index e351d6b..b9c8839 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -480,7 +480,9 @@
// reset progress animator before dispatching onBackStarted to callback. This
// ensures that onBackCancelled (of a previous gesture) is always dispatched
// before onBackStarted
- if (callback != null) mProgressAnimator.reset();
+ if (callback != null && mProgressAnimator.isBackAnimationInProgress()) {
+ mProgressAnimator.reset();
+ }
mTouchTracker.setState(BackTouchTracker.TouchTrackerState.ACTIVE);
mTouchTracker.setShouldUpdateStartLocation(true);
mTouchTracker.setGestureStartLocation(
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 760c916..0590c40 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -78,3 +78,17 @@
description: "Allows for additional windows tied to WindowDecoration to be layered between status bar and notification shade."
bug: "316186265"
}
+
+flag {
+ name: "enable_app_header_with_task_density"
+ namespace: "lse_desktop_experience"
+ description: "Matches the App Header density to that of the app window, instead of SysUI's"
+ bug: "332414819"
+}
+
+flag {
+ name: "enable_themed_app_headers"
+ namespace: "lse_desktop_experience"
+ description: "Makes the App Header style adapt to the system's and app's light/dark theme"
+ bug: "328668781"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index ee3e34f..f08f5b8 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -163,4 +163,12 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "release_snapshot_aggressively"
+ namespace: "windowing_frontend"
+ description: "Actively release task snapshot memory"
+ bug: "238206323"
+ is_fixed_read_only: true
}
\ No newline at end of file
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 4d1b87a..5e0107e 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -124,7 +124,30 @@
flag {
namespace: "windowing_sdk"
- name: "pip_restore_to_overlay"
+ name: "fix_pip_restore_to_overlay"
description: "Restore exit-pip activity back to ActivityEmbedding overlay"
bug: "297887697"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "activity_embedding_animation_customization_flag"
+ description: "Whether the animation customization feature for AE is enabled"
+ bug: "293658614"
+ metadata {
+ purpose: PURPOSE_FEATURE
+ }
+}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "insets_control_changed_item"
+ description: "Pass insetsControlChanged through ClientTransaction to fix the racing"
+ bug: "339380439"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 06ae11fee..33b4e4a 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -28,6 +28,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AlertDialog;
@@ -240,6 +241,7 @@
/**
* Called when the accessibility shortcut is activated
*/
+ @SuppressLint("MissingPermission")
public void performAccessibilityShortcut() {
Slog.d(TAG, "Accessibility shortcut activated");
final ContentResolver cr = mContext.getContentResolver();
@@ -274,6 +276,9 @@
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStatus.SHOWN,
userId);
} else {
+ if (Flags.restoreA11yShortcutTargetService()) {
+ enableDefaultHardwareShortcut(userId);
+ }
playNotificationTone();
if (mAlertDialog != null) {
mAlertDialog.dismiss();
@@ -349,34 +354,7 @@
.setMessage(getShortcutWarningMessage(targets))
.setCancelable(false)
.setNegativeButton(R.string.accessibility_shortcut_on,
- (DialogInterface d, int which) -> {
- String targetServices = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
- String defaultService = mContext.getString(
- R.string.config_defaultAccessibilityService);
- // If the targetServices is null, means the user enables a
- // shortcut for the default service by triggering the volume keys
- // shortcut in the SUW instead of intentionally configuring the
- // shortcut on UI.
- if (targetServices == null && !TextUtils.isEmpty(defaultService)) {
- // The defaultService in the string resource could be a shorten
- // form like com.google.android.marvin.talkback/.TalkBackService.
- // Converts it to the componentName for consistency before saving
- // to the Settings.
- final ComponentName configDefaultService =
- ComponentName.unflattenFromString(defaultService);
- if (Flags.migrateEnableShortcuts()) {
- am.enableShortcutsForTargets(true, HARDWARE,
- Set.of(configDefaultService.flattenToString()), userId);
- } else {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
- configDefaultService.flattenToString(),
- userId);
- }
- }
- })
+ (DialogInterface d, int which) -> enableDefaultHardwareShortcut(userId))
.setPositiveButton(R.string.accessibility_shortcut_off,
(DialogInterface d, int which) -> {
Set<String> targetServices =
@@ -509,6 +487,47 @@
}
}
+ /**
+ * Writes {@link R.string#config_defaultAccessibilityService} to the
+ * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE} Setting if
+ * that Setting is currently {@code null}.
+ *
+ * <p>If {@code ACCESSIBILITY_SHORTCUT_TARGET_SERVICE} is {@code null} then the
+ * user triggered the shortcut during Setup Wizard <i>before</i> directly
+ * enabling the shortcut in the Settings UI of Setup Wizard.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ private void enableDefaultHardwareShortcut(int userId) {
+ final AccessibilityManager accessibilityManager = mFrameworkObjectProvider
+ .getAccessibilityManagerInstance(mContext);
+ final String targetServices = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
+ if (targetServices != null) {
+ // Do not write if the Setting was already configured.
+ return;
+ }
+ final String defaultService = mContext.getString(
+ R.string.config_defaultAccessibilityService);
+ // The defaultService in the string resource could be a shortened
+ // form: "com.android.accessibility.package/.MyService". Convert it to
+ // the component name form for consistency before writing to the Setting.
+ final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
+ ? null : ComponentName.unflattenFromString(defaultService);
+ if (defaultServiceComponent == null) {
+ // Default service is invalid, so nothing we can do here.
+ return;
+ }
+ if (Flags.migrateEnableShortcuts()) {
+ accessibilityManager.enableShortcutsForTargets(true, HARDWARE,
+ Set.of(defaultServiceComponent.flattenToString()), userId);
+ } else {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ defaultServiceComponent.flattenToString(), userId);
+ }
+ }
+
private boolean performTtsPrompt(AlertDialog alertDialog) {
final String serviceName = getShortcutFeatureDescription(false /* no summary */);
final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 84715aa..17adee4 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -917,7 +917,7 @@
mSystemWindowInsets = insets.getSystemWindowInsets();
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
- mSystemWindowInsets.right, 0);
+ mSystemWindowInsets.right, mSystemWindowInsets.bottom);
resetButtonBar();
@@ -946,7 +946,7 @@
if (mSystemWindowInsets != null) {
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
- mSystemWindowInsets.right, 0);
+ mSystemWindowInsets.right, mSystemWindowInsets.bottom);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.aidl
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.aidl
index 26b0b01..1e64ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.aidl
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.internal.inputmethod;
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+parcelable InputMethodInfoSafeList;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.java b/core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.java
new file mode 100644
index 0000000..9e720fb
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputMethodInfoSafeList.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.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.inputmethod.InputMethodInfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A {@link Parcelable} container that can holds an arbitrary number of {@link InputMethodInfo}
+ * without worrying about {@link android.os.TransactionTooLargeException} when passing across
+ * process boundary.
+ *
+ * @see Parcel#readBlob()
+ * @see Parcel#writeBlob(byte[])
+ */
+public final class InputMethodInfoSafeList implements Parcelable {
+ @Nullable
+ private byte[] mBuffer;
+
+ /**
+ * Instantiates a list of {@link InputMethodInfo} from the given {@link InputMethodInfoSafeList}
+ * then clears the internal buffer of {@link InputMethodInfoSafeList}.
+ *
+ * <p>Note that each {@link InputMethodInfo} item is guaranteed to be a copy of the original
+ * {@link InputMethodInfo} object.</p>
+ *
+ * <p>Any subsequent call will return an empty list.</p>
+ *
+ * @param from {@link InputMethodInfoSafeList} from which the list of {@link InputMethodInfo}
+ * will be extracted
+ * @return list of {@link InputMethodInfo} stored in the given {@link InputMethodInfoSafeList}
+ */
+ @NonNull
+ public static List<InputMethodInfo> extractFrom(@Nullable InputMethodInfoSafeList from) {
+ final byte[] buf = from.mBuffer;
+ from.mBuffer = null;
+ if (buf != null) {
+ final InputMethodInfo[] array = unmarshall(buf);
+ if (array != null) {
+ return new ArrayList<>(Arrays.asList(array));
+ }
+ }
+ return new ArrayList<>();
+ }
+
+ @NonNull
+ private static InputMethodInfo[] toArray(@Nullable List<InputMethodInfo> original) {
+ if (original == null) {
+ return new InputMethodInfo[0];
+ }
+ return original.toArray(new InputMethodInfo[0]);
+ }
+
+ @Nullable
+ private static byte[] marshall(@NonNull InputMethodInfo[] array) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ parcel.writeTypedArray(array, 0);
+ return parcel.marshall();
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+
+ @Nullable
+ private static InputMethodInfo[] unmarshall(byte[] data) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ return parcel.createTypedArray(InputMethodInfo.CREATOR);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+
+ private InputMethodInfoSafeList(@Nullable byte[] blob) {
+ mBuffer = blob;
+ }
+
+ /**
+ * Instantiates {@link InputMethodInfoSafeList} from the given list of {@link InputMethodInfo}.
+ *
+ * @param list list of {@link InputMethodInfo} from which {@link InputMethodInfoSafeList} will
+ * be created
+ * @return {@link InputMethodInfoSafeList} that stores the given list of {@link InputMethodInfo}
+ */
+ @NonNull
+ public static InputMethodInfoSafeList create(@Nullable List<InputMethodInfo> list) {
+ if (list == null || list.isEmpty()) {
+ return empty();
+ }
+ return new InputMethodInfoSafeList(marshall(toArray(list)));
+ }
+
+ /**
+ * Creates an empty {@link InputMethodInfoSafeList}.
+ *
+ * @return {@link InputMethodInfoSafeList} that is empty
+ */
+ @NonNull
+ public static InputMethodInfoSafeList empty() {
+ return new InputMethodInfoSafeList(null);
+ }
+
+ public static final Creator<InputMethodInfoSafeList> CREATOR = new Creator<>() {
+ @Override
+ public InputMethodInfoSafeList createFromParcel(Parcel in) {
+ return new InputMethodInfoSafeList(in.readBlob());
+ }
+
+ @Override
+ public InputMethodInfoSafeList[] newArray(int size) {
+ return new InputMethodInfoSafeList[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ // As long as InputMethodInfo#describeContents() is guaranteed to return 0, we can always
+ // return 0 here.
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBlob(mBuffer);
+ }
+}
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 1340156..1494425 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -15,14 +15,23 @@
*/
package com.android.internal.ravenwood;
+import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+
/**
* Class to interact with the Ravenwood environment.
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
-public class RavenwoodEnvironment {
+@RavenwoodNativeSubstitutionClass(
+ "com.android.platform.test.ravenwood.nativesubstitution.RavenwoodEnvironment_host")
+public final class RavenwoodEnvironment {
+ public static final String TAG = "RavenwoodEnvironment";
+
private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment();
private RavenwoodEnvironment() {
+ if (isRunningOnRavenwood()) {
+ ensureRavenwoodInitializedInternal();
+ }
}
/**
@@ -33,6 +42,21 @@
}
/**
+ * Initialize the ravenwood environment if it hasn't happened already, if running on Ravenwood.
+ *
+ * No-op if called on the device side.
+ */
+ public static void ensureRavenwoodInitialized() {
+ }
+
+ private static void ensureRavenwoodInitialized$ravenwood() {
+ getInstance(); // This is enough to initialize the environment.
+ }
+
+ /** Initialize the ravenwood environment */
+ private static native void ensureRavenwoodInitializedInternal();
+
+ /**
* USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment.
*
* <p>Using this allows code to behave differently on a real device and on Ravenwood, but
@@ -49,7 +73,7 @@
return false;
}
- public boolean isRunningOnRavenwood$ravenwood() {
+ private boolean isRunningOnRavenwood$ravenwood() {
return true;
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 3fc4fff..7f896ff 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -64,7 +64,7 @@
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl.Array activeControls) {
}
@Override
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 0257033..2b3ffeb2 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -31,6 +31,7 @@
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.InputMethodInfoSafeList;
/**
* Public interface to the global input method manager, used by all client applications.
@@ -42,20 +43,27 @@
void addClient(in IInputMethodClient client, in IRemoteInputConnection inputmethod,
int untrustedDisplayId);
- // TODO: Use ParceledListSlice instead
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
InputMethodInfo getCurrentInputMethodInfoAsUser(int userId);
- // TODO: Use ParceledListSlice instead
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
- List<InputMethodInfo> getInputMethodList(int userId, int directBootAwareness);
+ InputMethodInfoSafeList getInputMethodList(int userId, int directBootAwareness);
- // TODO: Use ParceledListSlice instead
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
- List<InputMethodInfo> getEnabledInputMethodList(int userId);
+ InputMethodInfoSafeList getEnabledInputMethodList(int userId);
+
+ // TODO(b/339761278): Remove after getInputMethodList() is fully deployed.
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
+ List<InputMethodInfo> getInputMethodListLegacy(int userId, int directBootAwareness);
+
+ // TODO(b/339761278): Remove after getEnabledInputMethodList() is fully deployed.
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
+ List<InputMethodInfo> getEnabledInputMethodListLegacy(int userId);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
diff --git a/core/java/com/android/internal/widget/CompactMessagingLayout.java b/core/java/com/android/internal/widget/CompactMessagingLayout.java
new file mode 100644
index 0000000..1e2c01a
--- /dev/null
+++ b/core/java/com/android/internal/widget/CompactMessagingLayout.java
@@ -0,0 +1,263 @@
+/*
+ * 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.widget;
+
+import android.app.Notification;
+import android.app.Notification.MessagingStyle;
+import android.app.Person;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A custom-built layout for the compact Heads Up of Notification.MessagingStyle .
+ */
+@RemoteViews.RemoteView
+public class CompactMessagingLayout extends FrameLayout {
+
+ private final PeopleHelper mPeopleHelper = new PeopleHelper();
+
+ private ViewStub mConversationFacePileViewStub;
+
+ private int mNotificationBackgroundColor;
+ private int mFacePileSize;
+ private int mFacePileAvatarSize;
+ private int mFacePileProtectionWidth;
+ private int mLayoutColor;
+
+ public CompactMessagingLayout(@NonNull Context context) {
+ super(context);
+ }
+
+ public CompactMessagingLayout(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CompactMessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public CompactMessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mPeopleHelper.init(getContext());
+ mConversationFacePileViewStub = requireViewById(R.id.conversation_face_pile);
+ mFacePileSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_compact_face_pile_size);
+ mFacePileAvatarSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_compact_face_pile_avatar_size);
+ mFacePileProtectionWidth = getResources().getDimensionPixelSize(
+ R.dimen.conversation_compact_face_pile_protection_width);
+ }
+
+ /**
+ * Set conversation data
+ *
+ * @param extras Bundle contains conversation data
+ */
+ @RemotableViewMethod(asyncImpl = "setGroupFacePileAsync")
+ public void setGroupFacePile(Bundle extras) {
+ // NO-OP
+ }
+
+ /**
+ * async version of {@link ConversationLayout#setLayoutColor}
+ */
+ @RemotableViewMethod
+ public Runnable setLayoutColorAsync(int color) {
+ mLayoutColor = color;
+ return NotificationRunnables.NOOP;
+ }
+
+ @RemotableViewMethod(asyncImpl = "setLayoutColorAsync")
+ public void setLayoutColor(int color) {
+ mLayoutColor = color;
+ }
+
+ /**
+ * @param color the color of the notification background
+ */
+ @RemotableViewMethod
+ public void setNotificationBackgroundColor(int color) {
+ mNotificationBackgroundColor = color;
+ }
+
+ /**
+ * async version of {@link CompactMessagingLayout#setGroupFacePile}
+ * setGroupFacePile!
+ */
+ public Runnable setGroupFacePileAsync(Bundle extras) {
+ final Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ final List<Notification.MessagingStyle.Message> newMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ final Parcelable[] histMessages =
+ extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+ final List<Notification.MessagingStyle.Message> newHistoricMessages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+ final Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, Person.class);
+
+ final List<List<MessagingStyle.Message>> groups = groupMessages(newMessages,
+ newHistoricMessages);
+ final PeopleHelper.NameToPrefixMap nameToPrefixMap =
+ mPeopleHelper.mapUniqueNamesToPrefixWithGroupList(groups);
+ final int layoutColor = mLayoutColor;
+ // Find last two person's icon to show them in the face pile.
+ Icon secondLastIcon = null;
+ Icon lastIcon = null;
+ CharSequence lastKey = null;
+ final CharSequence userKey = getPersonKey(user);
+ for (int i = groups.size() - 1; i >= 0; i--) {
+ final MessagingStyle.Message message = groups.get(i).get(0);
+ final Person sender =
+ message.getSenderPerson() != null ? message.getSenderPerson() : user;
+ final CharSequence senderKey = getPersonKey(sender);
+ final boolean notUser = senderKey != userKey;
+ final boolean notIncluded = senderKey != lastKey;
+
+ if ((notUser && notIncluded) || (i == 0 && lastKey == null)) {
+ final Icon icon = getSenderIcon(sender, nameToPrefixMap, layoutColor);
+ if (lastIcon == null) {
+ lastIcon = icon;
+ lastKey = senderKey;
+ } else {
+ secondLastIcon = icon;
+ break;
+ }
+ }
+ }
+
+ if (lastIcon == null) {
+ lastIcon = getSenderIcon(null, null, layoutColor);
+ }
+
+ if (secondLastIcon == null) {
+ secondLastIcon = getSenderIcon(null, null, layoutColor);
+ }
+ final Drawable secondLastIconDrawable = secondLastIcon.loadDrawable(getContext());
+ final Drawable lastIconDrawable = lastIcon.loadDrawable(getContext());
+ return () -> {
+ final View conversationFacePile = mConversationFacePileViewStub.inflate();
+ conversationFacePile.setVisibility(VISIBLE);
+
+ final ImageView facePileBottomBg = conversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom_background);
+ final ImageView facePileTop = conversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_top);
+ final ImageView facePileBottom = conversationFacePile.requireViewById(
+ com.android.internal.R.id.conversation_face_pile_bottom);
+
+ facePileTop.setImageDrawable(secondLastIconDrawable);
+ facePileBottom.setImageDrawable(lastIconDrawable);
+ facePileBottomBg.setImageTintList(ColorStateList.valueOf(mNotificationBackgroundColor));
+ setSize(conversationFacePile, mFacePileSize);
+ setSize(facePileBottom, mFacePileAvatarSize);
+ setSize(facePileTop, mFacePileAvatarSize);
+ setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
+ };
+ }
+
+ @NonNull
+ private Icon getSenderIcon(@Nullable Person sender,
+ @Nullable PeopleHelper.NameToPrefixMap uniqueNames,
+ int layoutColor) {
+ if (sender == null) {
+ return mPeopleHelper.createAvatarSymbol(/* name = */ "", /* symbol = */ "",
+ layoutColor);
+ }
+
+ if (sender.getIcon() != null) {
+ return sender.getIcon();
+ }
+
+ final CharSequence senderName = sender.getName();
+ if (!TextUtils.isEmpty(senderName)) {
+ final String symbol = uniqueNames != null ? uniqueNames.getPrefix(senderName) : "";
+ return mPeopleHelper.createAvatarSymbol(senderName, symbol, layoutColor);
+ }
+
+ return mPeopleHelper.createAvatarSymbol(/* name = */ "", /* symbol = */ "", layoutColor);
+ }
+
+
+ /**
+ * Groups the given messages by their sender.
+ */
+ private static List<List<MessagingStyle.Message>> groupMessages(
+ List<MessagingStyle.Message> messages,
+ List<MessagingStyle.Message> historicMessages
+ ) {
+ if (messages.isEmpty() && historicMessages.isEmpty()) return List.of();
+
+ ArrayList<MessagingStyle.Message> currentGroup = null;
+ CharSequence currentSenderKey = null;
+ final ArrayList<List<MessagingStyle.Message>> groups = new ArrayList<>();
+ final int histSize = historicMessages.size();
+
+ for (int i = 0; i < histSize + messages.size(); i++) {
+ final MessagingStyle.Message message = i < histSize ? historicMessages.get(i)
+ : messages.get(i - histSize);
+ if (message == null) continue;
+
+ final CharSequence senderKey = getPersonKey(message.getSenderPerson());
+ final boolean isNewGroup = currentGroup == null || senderKey != currentSenderKey;
+ if (isNewGroup) {
+ currentGroup = new ArrayList<>();
+ groups.add(currentGroup);
+ currentSenderKey = senderKey;
+ }
+ currentGroup.add(message);
+ }
+ return groups;
+ }
+
+ private static CharSequence getPersonKey(@Nullable Person person) {
+ return person == null ? null : person.getKey() == null ? person.getName() : person.getKey();
+ }
+
+ private static void setSize(View view, int size) {
+ final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) view.getLayoutParams();
+ lp.width = size;
+ lp.height = size;
+ view.setLayoutParams(lp);
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 80a7599..61eaa52 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -439,6 +439,7 @@
"android_database_SQLiteConnection.cpp",
"android_database_SQLiteGlobal.cpp",
"android_database_SQLiteDebug.cpp",
+ "android_database_SQLiteRawStatement.cpp",
"android_hardware_input_InputApplicationHandle.cpp",
"android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",
@@ -483,4 +484,8 @@
"libnativehelper",
"libvintf",
],
+
+ required: [
+ "vintf",
+ ],
}
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 7267eb8..a022842 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -190,21 +190,17 @@
return -1;
}
- bool is_dir_in = (endpoint & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
- jbyte *bufferBytes = (jbyte *)malloc(length);
-
- if (!is_dir_in && buffer) {
- env->GetByteArrayRegion(buffer, start, length, bufferBytes);
+ jbyte* bufferBytes = NULL;
+ if (buffer) {
+ bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
}
- jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
+ jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
- if (is_dir_in && buffer) {
- env->SetByteArrayRegion(buffer, start, length, bufferBytes);
+ if (bufferBytes) {
+ env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
}
- free(bufferBytes);
-
return result;
}
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 8dc9d0a..7a4854b 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -32,6 +32,8 @@
static jmethodID gHashMapPut;
static jclass gLongClazz;
static jmethodID gLongValueOf;
+static jclass gVintfObjectClazz;
+static jmethodID gRunCommand;
namespace android {
@@ -47,6 +49,56 @@
using vintf::Vndk;
using vintf::CheckFlags::ENABLE_ALL_CHECKS;
+// Instead of VintfObject::GetXxx(), we construct
+// HalManifest/CompatibilityMatrix objects by calling `vintf` through
+// UiAutomation.executeShellCommand() so that the commands are executed
+// using shell identity. Otherwise, we would need to allow "apps" to access
+// files like apex-info-list.xml which we don't want to open to apps.
+// This is okay because VintfObject is @TestApi and only used in CTS tests.
+
+static std::string runCmd(JNIEnv* env, const char* cmd) {
+ jstring jstr = (jstring)env->CallStaticObjectMethod(gVintfObjectClazz, gRunCommand,
+ env->NewStringUTF(cmd));
+ std::string output;
+ if (jstr) {
+ auto cstr = env->GetStringUTFChars(jstr, nullptr);
+ output = std::string(cstr);
+ env->ReleaseStringUTFChars(jstr, cstr);
+ } else {
+ LOG(WARNING) << "Failed to run " << cmd;
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ return output;
+}
+
+template <typename T>
+static std::shared_ptr<const T> fromXml(const std::string& content) {
+ std::shared_ptr<T> object = std::make_unique<T>();
+ std::string error;
+ if (fromXml(object.get(), content, &error)) {
+ return object;
+ }
+ LOG(WARNING) << "Unabled to parse: " << error;
+ return nullptr;
+}
+
+static std::shared_ptr<const HalManifest> getDeviceHalManifest(JNIEnv* env) {
+ return fromXml<HalManifest>(runCmd(env, "vintf dm"));
+}
+
+static std::shared_ptr<const HalManifest> getFrameworkHalManifest(JNIEnv* env) {
+ return fromXml<HalManifest>(runCmd(env, "vintf fm"));
+}
+
+static std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(JNIEnv* env) {
+ return fromXml<CompatibilityMatrix>(runCmd(env, "vintf dcm"));
+}
+
+static std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(JNIEnv* env) {
+ return fromXml<CompatibilityMatrix>(runCmd(env, "vintf fcm"));
+}
+
template<typename V>
static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
size_t i;
@@ -83,12 +135,10 @@
{
std::vector<std::string> cStrings;
- tryAddSchema(VintfObject::GetDeviceHalManifest(), "device manifest", &cStrings);
- tryAddSchema(VintfObject::GetFrameworkHalManifest(), "framework manifest", &cStrings);
- tryAddSchema(VintfObject::GetDeviceCompatibilityMatrix(), "device compatibility matrix",
- &cStrings);
- tryAddSchema(VintfObject::GetFrameworkCompatibilityMatrix(), "framework compatibility matrix",
- &cStrings);
+ tryAddSchema(getDeviceHalManifest(env), "device manifest", &cStrings);
+ tryAddSchema(getFrameworkHalManifest(env), "framework manifest", &cStrings);
+ tryAddSchema(getDeviceCompatibilityMatrix(env), "device compatibility matrix", &cStrings);
+ tryAddSchema(getFrameworkCompatibilityMatrix(env), "framework compatibility matrix", &cStrings);
return toJavaStringArray(env, cStrings);
}
@@ -108,15 +158,13 @@
static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
std::set<std::string> halNames;
- tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
- "device manifest", &halNames);
- tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(),
- "framework manifest", &halNames);
+ tryAddHalNamesAndVersions(getDeviceHalManifest(env), "device manifest", &halNames);
+ tryAddHalNamesAndVersions(getFrameworkHalManifest(env), "framework manifest", &halNames);
return toJavaStringArray(env, halNames);
}
static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
- std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+ std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
return nullptr;
@@ -126,8 +174,7 @@
}
static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) {
- std::shared_ptr<const CompatibilityMatrix> matrix =
- VintfObject::GetFrameworkCompatibilityMatrix();
+ std::shared_ptr<const CompatibilityMatrix> matrix = getFrameworkCompatibilityMatrix(env);
if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) {
jniThrowRuntimeException(env, "Cannot get framework compatibility matrix");
return nullptr;
@@ -148,7 +195,7 @@
}
static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
- std::shared_ptr<const HalManifest> manifest = VintfObject::GetFrameworkHalManifest();
+ std::shared_ptr<const HalManifest> manifest = getFrameworkHalManifest(env);
if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
return nullptr;
@@ -163,7 +210,7 @@
}
static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) {
- std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+ std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) {
return nullptr;
}
@@ -188,19 +235,20 @@
const char* const kVintfObjectPathName = "android/os/VintfObject";
-int register_android_os_VintfObject(JNIEnv* env)
-{
-
+int register_android_os_VintfObject(JNIEnv* env) {
gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
- gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
- "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long"));
gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;");
+ gVintfObjectClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kVintfObjectPathName));
+ gRunCommand = GetStaticMethodIDOrDie(env, gVintfObjectClazz, "runShellCommand",
+ "(Ljava/lang/String;)Ljava/lang/String;");
return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
- NELEM(gVintfObjectMethods));
+ NELEM(gVintfObjectMethods));
}
extern int register_android_os_VintfRuntimeInfo(JNIEnv* env);
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index aae0da9..f5992d9 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -90,7 +90,8 @@
deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor(),
deviceInfo.hasBattery(), usiVersion.majorVersion,
usiVersion.minorVersion,
- deviceInfo.getAssociatedDisplayId()));
+ deviceInfo.getAssociatedDisplayId(),
+ deviceInfo.isEnabled()));
// Note: We do not populate the Bluetooth address into the InputDevice object to avoid leaking
// it to apps that do not have the Bluetooth permission.
@@ -126,7 +127,7 @@
gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
"(IIILjava/lang/String;IIILjava/lang/"
"String;ZIILandroid/view/KeyCharacterMap;Ljava/"
- "lang/String;Ljava/lang/String;ZZZZZIII)V");
+ "lang/String;Ljava/lang/String;ZZZZZIIIZ)V");
gInputDeviceClassInfo.addMotionRange =
GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V");
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index acef609..59d18b8 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -89,6 +89,7 @@
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
extern int register_android_database_SQLiteDebug(JNIEnv* env);
+extern int register_android_database_SQLiteRawStatement(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
@@ -128,6 +129,8 @@
REG_JNI(register_android_database_SQLiteConnection)},
{"android.database.sqlite.SQLiteGlobal", REG_JNI(register_android_database_SQLiteGlobal)},
{"android.database.sqlite.SQLiteDebug", REG_JNI(register_android_database_SQLiteDebug)},
+ {"android.database.sqlite.SQLiteRawStatement",
+ REG_JNI(register_android_database_SQLiteRawStatement)},
#endif
{"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)},
{"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
diff --git a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
index 3b288d7..82920ba 100644
--- a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
+++ b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
@@ -13,7 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<FrameLayout
+<com.android.internal.widget.CompactMessagingLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
@@ -45,6 +45,14 @@
android:scaleType="centerCrop"
android:importantForAccessibility="no"
/>
+ <ViewStub
+ android:layout="@layout/conversation_face_pile_layout"
+ android:layout_gravity="center_vertical|start"
+ android:layout_width="@dimen/conversation_compact_face_pile_size"
+ android:layout_height="@dimen/conversation_compact_face_pile_size"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:id="@+id/conversation_face_pile"
+ />
<FrameLayout
android:id="@+id/alternate_expand_target"
android:layout_width="@dimen/notification_content_margin_start"
@@ -101,4 +109,4 @@
/>
</FrameLayout>
</LinearLayout>
-</FrameLayout>
+</com.android.internal.widget.CompactMessagingLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2a3c691d..7fe8641 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Stembystand"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Snelsluit"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nuwe kennisgewing"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fisieke sleutelbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sekuriteit"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Maak Boodskappe oop"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe dit werk"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Hangend …"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Stel Vingerafdrukslot weer op"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> het nie goed gewerk nie en is uitgevee. Stel dit weer op om jou foon met vingerafdruk te ontsluit."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> het nie goed gewerk nie en is uitgevee. Stel dit weer op om jou foon met jou vingerafdruk te ontsluit."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Stel Gesigslot weer op"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Jou gesigmodel het nie goed gewerk nie en is uitgevee. Stel dit weer op om jou foon met gesig te ontsluit."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Stel op"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nie nou nie"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 08a290c..1d1ded6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"የድምጽ እርዳታ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"መቆለፊያ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"አዲስ ማሳወቂያ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"አካላዊ ቁልፍ ሰሌዳ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ደህንነት"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"መልዕክቶች ይክፈቱ"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"እንዴት እንደሚሠራ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"በመጠባበቅ ላይ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> በደንብ እየሠራ አልነበረም እና ተሰርዟል። ስልክዎን በጣት አሻራ ለመክፈት እንደገና ያዋቅሩት።"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> እና <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> በደንብ እየሠሩ አልነበረም እና ተሰርዘዋል። ስልክዎን በጣት አሻራ ለመክፈት እንደገና ያዋቅሯቸው።"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"በመልክ መክፈትን እንደገና ያዋቅሩ"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"የእርስዎ የመልክ ሞዴል በደንብ እየሠራ አልነበረም እና ተሰርዟል። ስልክዎን በመልክ ለመክፈት እንደገና ያዋቅሩት።"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ያዋቅሩ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"አሁን አይደለም"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 20d491f..3a4a79a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -287,6 +287,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"المساعد الصوتي"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"إلغاء التأمين"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ردّ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"إشعار جديد"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الخارجية"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"الأمان"</string>
@@ -2398,9 +2399,9 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"تم ضبط تنسيق لوحة المفاتيح على <xliff:g id="LAYOUT_1">%1$s</xliff:g> و<xliff:g id="LAYOUT_2">%2$s</xliff:g> و<xliff:g id="LAYOUT_3">%3$s</xliff:g>… انقر لتغييره."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"تم إعداد لوحات المفاتيح الخارجية"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"انقر لعرض لوحات المفاتيح."</string>
- <string name="profile_label_private" msgid="6463418670715290696">"ملف شخصي خاص"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"المساحة الخاصة"</string>
<string name="profile_label_clone" msgid="769106052210954285">"نسخة طبق الأصل"</string>
- <string name="profile_label_work" msgid="3495359133038584618">"ملف العمل"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"مساحة العمل"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"ملف العمل 2"</string>
<string name="profile_label_work_3" msgid="4834572253956798917">"ملف العمل 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"ملف شخصي تجريبي"</string>
@@ -2417,22 +2418,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"فتح تطبيق \"الرسائل\""</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"طريقة العمل"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"بانتظار الإزالة من الأرشيف…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"إعادة إعداد ميزة \"فتح الجهاز ببصمة الإصبع\""</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"هناك مشكلة في <xliff:g id="FINGERPRINT">%s</xliff:g> وتم حذفها. يُرجى إعدادها مرة أخرى لفتح قفل هاتفك باستخدام بصمة الإصبع."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"هناك مشكلة في <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> و<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> وتم حذفهما. يُرجى إعادة إعدادهما لفتح قفل هاتفك باستخدام بصمة الإصبع."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"إعادة إعداد ميزة \"فتح الجهاز بالتعرّف على الوجه\""</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"هناك مشكلة في نموذج الوجه الخاص بك وتم حذفه. يُرجى إعداده مرة أخرى لفتح قفل هاتفك باستخدام وجهك."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"إعداد"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"لاحقًا"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 30ced90..e8346b7 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"কণ্ঠধ্বনিৰে সহায়"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"লকডাউন"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"৯৯৯+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"প্ৰত্যুত্তৰ দিয়ক"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"নতুন জাননী"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"কায়িক কীব’ৰ্ড"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"সুৰক্ষা"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খোলক"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ই কেনেকৈ কাম কৰে"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"বিবেচনাধীন হৈ আছে..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g>এ ভালদৰে কাম কৰা নাছিল আৰু সেইটো মচি পেলোৱা হৈছে। ফিংগাৰপ্ৰিণ্টৰ জৰিয়তে আপোনাৰ ফ’নটো আনলক কৰিবলৈ এইটো পুনৰ ছেট আপ কৰক।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> আৰু <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>এ ভালদৰে কাম কৰা নাছিল আৰু সেয়া মচি পেলোৱা হৈছে। ফিংগাৰপ্ৰিণ্টৰ জৰিয়তে আপোনাৰ ফ’নটো আনলক কৰিবলৈ সেয়া পুনৰ ছেট আপ কৰক।"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ফে’চ আনলক পুনৰ ছেট আপ কৰক"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"আপোনাৰ মুখাৱয়বৰ মডেলটোৱে ভালদৰে কাম কৰা নাছিল আৰু সেইটো মচি পেলোৱা হৈছে। মুখাৱয়বৰ জৰিয়তে আপোনাৰ ফ’নটো আনলক কৰিবলৈ এইটো পুনৰ ছেট আপ কৰক।"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ছেট আপ কৰক"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"এতিয়া নহয়"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 49073f1..5f9e9fa 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Səs Yardımçısı"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Kilidləyin"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Cavablayın"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Yeni bildiriş"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziki klaviatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Güvənlik"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajı açın"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Haqqında"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gözləmədə..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Barmaqla Kilidaçmanı yenidən ayarlayın"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> yaxşı işləmirdi və silindi. Telefonu barmaq izi ilə kiliddən çıxarmaq üçün onu yenidən ayarlayın."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> və <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> yaxşı işləmirdi və silindi. Telefonu barmaq izi ilə kiliddən çıxarmaq üçün onları yenidən ayarlayın."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Üzlə Kilidaçmanı yenidən ayarlayın"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Üz modeliniz yaxşı işləmirdi və silindi. Telefonu üzlə kiliddən çıxarmaq üçün onu yenidən ayarlayın."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ayarlayın"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"İndi yox"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ca66ef4..db9a93f 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključavanje"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obaveštenje"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tastatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bezbednost"</string>
@@ -835,11 +837,11 @@
<string name="policylab_watchLogin" msgid="7599669460083719504">"Nadzor pokušaja otključavanja ekrana"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Prati broj netačno unetih lozinki prilikom otključavanja ekrana i zaključava tablet ili briše podatke sa tableta ako je netačna lozinka uneta previše puta."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava Android TV uređaj ili briše sve podatke sa Android TV uređaja ako se unese previše netačnih lozinki."</string>
- <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Prati broj netačno unetih lozinki pri otključavanju ekrana i zaključava sistem za info-zabavu ili briše sve podatke sa sistema za info-zabavu ako je netačna lozinka uneta previše puta."</string>
+ <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Prati broj netačno unetih lozinki pri otključavanju ekrana i zaključava sistem za informacije i zabavu ili briše sve podatke sa sistema za informacije i zabavu ako je netačna lozinka uneta previše puta."</string>
<string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Prati broj netačno unetih lozinki pri otključavanju ekrana i zaključava telefon ili briše sve podatke sa telefona ako je netačna lozinka uneta previše puta."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava tablet ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava Android TV uređaj ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava sistem za info-zabavu ili briše sve podatke ovog profila ako se unese previše netačnih lozinki."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava sistem za informacije i zabavu ili briše sve podatke ovog profila ako se unese previše netačnih lozinki."</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava telefon ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"Promena zaključavanja ekrana"</string>
<string name="policydesc_resetPassword" msgid="4626419138439341851">"Menja otključavanje ekrana."</string>
@@ -848,13 +850,13 @@
<string name="policylab_wipeData" msgid="1359485247727537311">"Brisanje svih podataka"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Brisanje podataka na tabletu bez upozorenja resetovanjem na fabrička podešavanja."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Briše podatke Android TV uređaja bez upozorenja pomoću resetovanja na fabrička podešavanja."</string>
- <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Briše podatke na sistemu za info-zabavu bez upozorenja resetovanjem na fabrička podešavanja."</string>
+ <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Briše podatke na sistemu za informacije i zabavu bez upozorenja resetovanjem na fabrička podešavanja."</string>
<string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Brisanje podataka na telefonu bez upozorenja resetovanjem na fabrička podešavanja."</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Brisanje podataka profila"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Obriši podatke korisnika"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Briše podatke ovog korisnika na ovom tabletu bez upozorenja."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Briše podatke ovog korisnika na ovom Android TV uređaju bez upozorenja."</string>
- <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"Briše podatke ovog profila na ovom sistemu za info-zabavu bez upozorenja."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"Briše podatke ovog profila na ovom sistemu za informacije i zabavu bez upozorenja."</string>
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"Briše podatke ovog korisnika na ovom telefonu bez upozorenja."</string>
<string name="policylab_setGlobalProxy" msgid="215332221188670221">"Podesite globalni proksi server uređaja"</string>
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"Podešava globalni proksi uređaja koji će se koristiti dok su smernice omogućene. Samo vlasnik uređaja može da podesi globalni proksi."</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Princip rada"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovo podesite otključavanje otiskom prsta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> nije funkcionisao i izbrisali smo ga. Ponovo ga podesite da biste telefon otključavali otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nisu funkcionisali i izbrisali smo ih. Ponovo ih podesite da biste telefon otključavali otiskom prsta."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovo podesite otključavanje licem"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Vaš model lica nije funkcionisao i izbrisali smo ga. Ponovo ga podesite da biste telefon otključavali licem."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Podesi"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sada"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 4cd150a..ec19c2d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -285,6 +285,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Галас. дапамога"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Блакіроўка"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Новае апавяшчэнне"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Фізічная клавіятура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Бяспека"</string>
@@ -2415,22 +2417,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Адкрыць Паведамленні"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як гэта працуе"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"У чаканні..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Наладзіць разблакіроўку адбіткам пальца паўторна"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Адбітак пальца \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" не працаваў належным чынам і быў выдалены. Каб мець магчымасць разблакіраваць тэлефон з дапамогай адбітка пальца, наладзьце яго яшчэ раз."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Адбіткі пальцаў \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" і \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" не працавалі належным чынам і былі выдалены. Каб мець магчымасць разблакіраваць тэлефон з дапамогай адбітка пальца, наладзьце іх яшчэ раз."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Паўторна наладзьце распазнаванне твару"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Мадэль твару не працавала належным чынам і была выдалена. Каб мець магчымасць разблакіраваць тэлефон з дапамогай распазнавання твару, наладзьце яго яшчэ раз."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Наладзіць"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не зараз"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index eb2e920..1b73710 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Гласова помощ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Заключване"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново известие"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физическа клавиатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Сигурност"</string>
@@ -1726,7 +1728,7 @@
<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_off" msgid="5531598275559472393">"ИЗКЛ."</string>
- <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Искате ли да разрешите на <xliff:g id="SERVICE">%1$s</xliff:g> да има пълен контрол над устройството ви?"</string>
+ <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Искате ли да разрешите на „<xliff:g id="SERVICE">%1$s</xliff:g>“ да има пълен контрол над устройството ви?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Пълният контрол е подходящ за приложенията, които помагат на потребителите със специални нужди, но не и за повечето приложения."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Преглед и управление на екрана"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Услугата може да чете цялото съдържание на екрана и да показва такова върху други приложения."</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отваряне на Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Начин на работа"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Изчаква..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Повторно настройване на „Отключване с отпечатък“"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Отпечатъкът „<xliff:g id="FINGERPRINT">%s</xliff:g>“ бе изтрит, защото не работеше добре. Настройте го отново, за да отключвате телефона си с отпечатък."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Отпечатъците „<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>“ и „<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>“ бяха изтрити, защото не работеха добре. Настройте ги отново, за да отключвате телефона си с отпечатък."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Повторно настройване на „Отключване с лице“"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Моделът на лицето ви бе изтрит, защото не работеше добре. Настройте го отново, за да отключвате телефона си с лице."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Настройване"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сега"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 6618127..0e32bbe6 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ভয়েস সহায়তা"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"লকডাউন"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"৯৯৯+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"নতুন বিজ্ঞপ্তি"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ফিজিক্যাল কীবোর্ড"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"নিরাপত্তা"</string>
@@ -644,7 +646,7 @@
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"চালিয়ে যেতে আপনার বায়োমেট্রিক্স বা স্ক্রিন লক ব্যবহার করুন"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"যাচাইকরণ বাতিল হয়েছে"</string>
- <string name="biometric_not_recognized" msgid="5106687642694635888">"স্বীকৃত নয়"</string>
+ <string name="biometric_not_recognized" msgid="5106687642694635888">"শনাক্ত করা যায়নি"</string>
<string name="biometric_face_not_recognized" msgid="5535599455744525200">"ফেস চেনা যায়নি"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"যাচাইকরণ বাতিল হয়েছে"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"পিন, প্যাটার্ন অথবা পাসওয়ার্ড সেট করা নেই"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খুলুন"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"এটি কীভাবে কাজ করে"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"বাকি আছে…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"\'ফিঙ্গারপ্রিন্ট আনলক\' আবার সেট-আপ করুন"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ভালোভাবে কাজ করছিল না বলে সেটি মুছে ফেলা হয়েছে। ফিঙ্গারপ্রিন্ট ব্যবহার করে আপনার ফোন আনলক করতে হলে এটি আবার সেট-আপ করুন।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ও <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ভালোভাবে কাজ করছিল না বলে মুছে ফেলা হয়েছে। ফিঙ্গারপ্রিন্ট ব্যবহার করে আপনার ফোন আনলক করতে হলে সেগুলি আবার সেট-আপ করুন।"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"\'ফেস আনলক\' আবার সেট-আপ করুন"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"আপনার ফেস মডেল ভালোভাবে কাজ করছিল না বলে সেটি মুছে ফেলা হয়েছে। ফেস ব্যবহার করে আপনার ফোন আনলক করতে হলে এটি আবার সেট-আপ করুন।"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"সেট-আপ করুন"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"এখন নয়"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 4f058bf..63a83f0 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -284,6 +284,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključaj"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Odgovorite"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obavještenje"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tastatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sigurnost"</string>
@@ -2414,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvorite Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako ovo funkcionira"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovo postavite otključavanje otiskom prsta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Otisak prsta <xliff:g id="FINGERPRINT">%s</xliff:g> nije dobro funkcionirao, pa je izbrisan. Postavite ga ponovo da otključavate telefon otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Otisci prstiju <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nisu dobro funkcionirali, pa su izbrisani. Postavite ih ponovo da otključavate telefon otiskom prsta."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovo postavite otključavanje licem"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Model lica nije dobro funkcionirao, pa je izbrisan. Postavite ga ponovo da otključavate telefon licem."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Postavite"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sada"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 77fd6b8..1fd814d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -85,7 +85,7 @@
<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="9102799172089265268">"Per poder fer trucades d\'emergència, cal tenir connexió a una xarxa mòbil"</string>
+ <string name="EmergencyCallWarningSummary" msgid="9102799172089265268">"Per poder fer trucades d\'emergència, cal tenir connexió de xarxa mòbil"</string>
<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>
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Assist. per veu"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueig de seguretat"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"+999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificació nova"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclat físic"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguretat"</string>
@@ -1905,8 +1907,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions a la xarxa."</string>
- <string name="battery_saver_description" msgid="8518809702138617167">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions a la xarxa."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions de xarxa."</string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions de xarxa."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Estalvi de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vols activar l\'Estalvi de dades?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Obre Missatges"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Com funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendent..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Torna a configurar Desbloqueig amb empremta digital"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> no funcionava correctament i s\'ha suprimit. Torna a configurar-la per desbloquejar el telèfon amb l\'empremta digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> no funcionaven correctament i s\'han suprimit. Torna a configurar-les per desbloquejar el telèfon amb l\'empremta digital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Torna a configurar Desbloqueig facial"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"El teu model facial no funcionava correctament i s\'ha suprimit. Torna a configurar-lo per desbloquejar el telèfon amb la cara."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configura"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ara no"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5615f79..be4128f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -285,6 +285,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Hlas. asistence"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Odpovědět"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nové oznámení"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyzická klávesnice"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Zabezpečení"</string>
@@ -2415,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otevřít Zprávy"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to funguje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Čeká na vyřízení…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Opětovné nastavení odemknutí otiskem prstu"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> nefungoval správně a byl vymazán. Pokud chcete telefon odemykat otiskem prstu, nastavte jej znovu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nefungovaly správně a byly vymazány. Pokud chcete telefon odemykat otiskem prstu, nastavte je znovu."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Nastavte odemknutí obličejem znovu"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Váš model obličeje nefungoval správně a byl vymazán. Pokud chcete telefon odemykat obličejem, nastavte jej znovu."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastavit"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Teď ne"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index fd04e42..9b2844b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Taleassistent"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Låsning"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Svar"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ny notifikation"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysisk tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sikkerhed"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Åbn Beskeder"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Sådan fungerer det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Afventer…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer fingeroplåsning igen"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> virkede ikke optimalt og er derfor slettet. Konfigurer den igen for at bruge fingeroplåsning på din telefon."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> virkede ikke optimalt og er derfor slettet. Konfigurer dem igen for at bruge dit fingeraftryk til at låse din telefon op."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurer ansigtsoplåsning igen"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Din ansigtsmodel virkede ikke optimalt og er derfor slettet. Konfigurer den igen for at bruge ansigtsoplåsning på din telefon."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfigurer"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ikke nu"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 630ec75..1df8954 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Sprachassistent"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Neue Benachrichtigung"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physische Tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sicherheit"</string>
@@ -1997,7 +1999,7 @@
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Notruf"</string>
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Displaysperre einrichten"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Displaysperre einrichten"</string>
- <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Richte zur Nutzung des privaten Bereichs auf dem Gerät die Displaysperre ein"</string>
+ <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Richte zur Nutzung des vertraulichen Profils auf dem Gerät die Displaysperre ein"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages öffnen"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"So funktionierts"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ausstehend…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Entsperrung per Fingerabdruck neu einrichten"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> hat nicht einwandfrei funktioniert und wurde gelöscht. Richte ihn noch einmal ein, um dein Smartphone per Fingerabdruck zu entsperren."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> und <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> haben nicht einwandfrei funktioniert und wurden gelöscht. Richte sie noch einmal ein, um dein Smartphone per Fingerabdruck zu entsperren."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Entsperrung per Gesichtserkennung neu einrichten"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Dein Gesichtsmodell hat nicht einwandfrei funktioniert und wurde gelöscht. Richte es noch einmal ein, um dein Smartphone per Gesichtserkennung zu entsperren."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Einrichten"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nicht jetzt"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 5490131..3c7d167 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Φων.υποβοηθ."</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Κλείδωμα"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Νέα ειδοποίηση"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Κανονικό πληκτρολόγιο"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Ασφάλεια"</string>
@@ -2402,7 +2404,7 @@
<string name="profile_label_test" msgid="9168641926186071947">"Δοκιμή"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"Κοινόχρηστο"</string>
<string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Προφίλ εργασίας"</string>
- <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Απόρρητος χώρος"</string>
+ <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ιδιωτικός χώρος"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Κοινόχρηστο"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Έγινε απόκρυψη της ειδοποίησης ευαίσθητου περιεχομένου"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Άνοιγμα Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Πώς λειτουργεί"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Σε εκκρεμότητα…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με δακτυλικό αποτύπωμα"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Το δακτυλικό αποτύπωμα <xliff:g id="FINGERPRINT">%s</xliff:g> δεν λειτουργούσε καλά και διαγράφηκε. Ρυθμίστε το ξανά για να ξεκλειδώνετε το τηλέφωνο με το δακτυλικό αποτύπωμά σας."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Τα δακτυλικά αποτυπώματα <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> και <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> δεν λειτουργούσαν καλά και διαγράφηκαν. Ρυθμίστε τα ξανά για να ξεκλειδώνετε το τηλέφωνο με το δακτυλικό αποτύπωμά σας."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Επαναρρύθμιση λειτουργίας Ξεκλείδωμα με το πρόσωπο"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Το μοντέλο προσώπου δεν λειτουργούσε καλά και διαγράφηκε. Ρυθμίστε το ξανά για να ξεκλειδώνετε το τηλέφωνο με το πρόσωπό σας."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ρύθμιση"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Όχι τώρα"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a32fcca..0c782a7 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Reply"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with your fingerprint."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with your face."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9f06f71..d1894b5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Reply"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
@@ -2414,8 +2415,10 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <string name="fingerprint_dangling_notification_msg_1" msgid="6261149111900787302">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted to improve performance"</string>
- <string name="fingerprint_dangling_notification_msg_2" msgid="7688302770424064884">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted to improve performance"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
+ <skip />
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
+ <skip />
<string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint."</string>
<string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index bfcc4be..632585f 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Reply"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with your fingerprint."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with your face."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 8000732..1c55884 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Reply"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with your fingerprint."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with your face."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0fe2ccc..e08f934 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Reply"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"New notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Physical keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Security"</string>
@@ -2414,8 +2415,10 @@
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string>
<string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string>
- <string name="fingerprint_dangling_notification_msg_1" msgid="6261149111900787302">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted to improve performance"</string>
- <string name="fingerprint_dangling_notification_msg_2" msgid="7688302770424064884">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted to improve performance"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
+ <skip />
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
+ <skip />
<string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint."</string>
<string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string>
<string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8717640..30a0457 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensajes"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vuelve a configurar el Desbloqueo con huellas dactilares"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Se borró <xliff:g id="FINGERPRINT">%s</xliff:g> porque no funcionaba correctamente. Vuelve a configurarla para desbloquear el teléfono con la huella dactilar."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Se borraron <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> porque no funcionaban correctamente. Vuelve a configurarlas para desbloquear el teléfono con la huella dactilar."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Vuelve a configurar el Desbloqueo facial"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Se borró tu modelo de rostro porque no funcionaba correctamente. Vuelve a configurarlo para desbloquear el teléfono con el rostro."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ahora no"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6549da2..5079fdf 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo de seguridad"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"> 999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
@@ -1402,7 +1404,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración por USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre Mensajes"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura Desbloqueo con huella digital de nuevo"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> no funcionaba correctamente y se ha eliminado. Configúrala de nuevo para desbloquear el teléfono con la huella digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> y <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> no funcionaban correctamente y se han eliminado. Configúralas de nuevo para desbloquear el teléfono con la huella digital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configura Desbloqueo facial de nuevo"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Tu modelo facial no funcionaba correctamente y se ha eliminado. Configúralo de nuevo para desbloquear el teléfono con la cara."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ahora no"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 92f89e3..63e1756 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Häälabi"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lukusta"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Vasta"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Uus märguanne"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Füüsiline klaviatuur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Turvalisus"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ava rakendus Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Tööpõhimõtted"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ootel …"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Seadistage sõrmejäljega avamine uuesti"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ei töötanud hästi ja kustutati. Telefoni sõrmejäljega avamiseks seadistage see uuesti."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ei töötanud hästi ning kustutati. Telefoni sõrmejäljega avamiseks seadistage need uuesti."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Seadistage näoga avamine uuesti"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Teie näomudel ei töötanud hästi ja kustutati. Telefoni näoga avamiseks seadistage see uuesti."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Seadista"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Mitte praegu"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2d4130e..4fb4726 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ahots-laguntza"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Blokeatu"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Jakinarazpen berria"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teklatu fisikoa"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurtasuna"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ireki Mezuak"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Nola funtzionatzen du?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Zain…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ezabatu egin da, ez zuelako ondo funtzionatzen. Telefonoa hatz-markarekin desblokeatzeko, konfigura ezazu berriro."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> eta <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ezabatu egin dira, ez zutelako ondo funtzionatzen. Telefonoa hatz-markarekin desblokeatzeko, konfigura itzazu berriro."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Konfiguratu berriro aurpegi bidez desblokeatzeko eginbidea"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Aurpegi-eredua ezabatu egin da, ez zuelako ondo funtzionatzen. Telefonoa aurpegiarekin desblokeatzeko, konfigura ezazu berriro."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfiguratu"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Orain ez"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 07b2674..9a57d80 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"دستیار صوتی"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"قفل همه"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"۹۹۹+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"اعلان جدید"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"صفحهکلید فیزیکی"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"امنیت"</string>
@@ -481,7 +483,7 @@
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"به برنامه اجازه میدهد گزارشهای تماس در دستگاه Android TV را تغییر دهد، ازجمله دادههای مربوط به تماسهای ورودی و خروجی. برنامههای مخرب میتوانند از این مجوز برای پاک کردن یا تغییر دادن گزارش تماس شما استفاده کنند."</string>
<string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"به برنامه اجازه میدهد گزارشات تماس تلفنی شما، از جمله دادههایی درمورد تماسهای ورودی و خروجی را تغییر دهد. برنامههای مخرب ممکن است از این ویژگی برای پاک کردن یا تغییر گزارش تماس شما استفاده کنند."</string>
<string name="permlab_bodySensors" msgid="662918578601619569">"دسترسی به دادههای حسگر بدن، مثل ضربان قلب، درحین استفاده"</string>
- <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"به برنامه اجازه میدهد تا زمانی که درحال استفاده است، به دادههای حسگر بدن، مثل ضربان قلب، دما، و درصد اکسیژن خون دسترسی داشته باشد."</string>
+ <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"هنگامی که از برنامه استفاده میشود به برنامه اجازه میدهد به دادههای حسگر بدن مانند ضربان قلب، دما، و درصد اکسیژن خون دسترسی داشته باشد."</string>
<string name="permlab_bodySensors_background" msgid="4912560779957760446">"دسترسی به دادههای حسگر بدن، مثل ضربان قلب، درحین اجرا در پسزمینه"</string>
<string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"به برنامه اجازه میدهد تا زمانی که در پسزمینه درحال اجرا است، به دادههای حسگر بدن، مثل ضربان قلب، دما، و درصد اکسیژن خون دسترسی داشته باشد."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"خواندن رویدادها و جزئیات تقویم"</string>
@@ -503,17 +505,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"تغییر تنظیمات صوتی"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"به برنامه امکان میدهد تنظیمات صوتی کلی مانند میزان صدا و بلندگوی مورد استفاده برای پخش صدا را تغییر دهد."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ضبط صدا"</string>
- <string name="permdesc_recordAudio" msgid="5857246765327514062">"این برنامه وقتی درحال استفاده است، میتواند بااستفاده از میکروفون صدا ضبط کند."</string>
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"هنگامی که از برنامه استفاده میشود، این برنامه میتواند بااستفاده از میکروفون صدا ضبط کند."</string>
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ضبط صدا در پسزمینه"</string>
<string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"این برنامه میتواند در هرزمانی با استفاده از میکروفون صدا ضبط کند."</string>
<string name="permlab_detectScreenCapture" msgid="4447042362828799433">"تشخیص ضبط صفحهنمایش از پنجره برنامهها"</string>
- <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"وقتی نماگرفتی درحین استفاده از برنامه گرفته میشود، به این برنامه اطلاع داده میشود."</string>
+ <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"درحین گرفتن نماگرفت، هنگامی که از برنامه استفاده میشود، به این برنامه اطلاع داده میشود."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ارسال فرمان به سیم کارت"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"به برنامه اجازه ارسال دستورات به سیم کارت را میدهد. این بسیار خطرناک است."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"تشخیص فعالیت فیزیکی"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"این برنامه نمیتواند فعالیت فیزیکیتان را تشخیص دهد."</string>
<string name="permlab_camera" msgid="6320282492904119413">"عکسبرداری و فیلمبرداری"</string>
- <string name="permdesc_camera" msgid="5240801376168647151">"این برنامه وقتی درحال استفاده است، میتواند بااستفاده از دوربین عکس و فیلم بگیرد."</string>
+ <string name="permdesc_camera" msgid="5240801376168647151">"هنگامی که از برنامه استفاده میشود، این برنامه میتواند بااستفاده از دوربین عکس و فیلم بگیرد."</string>
<string name="permlab_backgroundCamera" msgid="7549917926079731681">"گرفتن عکس و فیلم در پسزمینه"</string>
<string name="permdesc_backgroundCamera" msgid="1615291686191138250">"این برنامه میتواند در هرزمانی با استفاده از دوربین عکس و فیلم بگیرد."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"به برنامه یا سرویسی اجازه دهید برای عکسبرداری و فیلمبرداری به دوربینهای سیستم دسترسی داشته باشد"</string>
@@ -666,7 +668,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"اثر انگشت تشخیص داده نشد"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"اثر انگشت تشخیص داده نشد"</string>
- <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"چهره شناسایی نشد، از اثر انگشت استفاده کنید."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"اثر انگشت اصالتسنجی شد"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"چهره اصالتسنجی شد"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چهره اصالتسنجی شد، لطفاً تأیید را فشار دهید"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیامها»"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"روش کار"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"درحال تعلیق…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"راهاندازی مجدد «قفلگشایی با اثر انگشت»"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> خوب کار نمیکرد و حذف شد. برای باز کردن قفل تلفن با اثر انگشت، آن را دوباره راهاندازی کنید."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> و <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> خوب کار نمیکرد و حذف شد. برای باز کردن قفل تلفن با اثر انگشت، آنها را دوباره راهاندازی کنید."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"راهاندازی مجدد «قفلگشایی با چهره»"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"مدل چهره شما خوب کار نمیکرد و حذف شد. برای باز کردن قفل تلفن با چهره، دوباره آن را راهاندازی کنید."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"راهاندازی"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"حالا نه"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e802443..7062a89 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ääniapuri"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lukitse"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Uusi ilmoitus"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyysinen näppäimistö"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Turvallisuus"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Avaa Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Näin se toimii"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Odottaa…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ota sormenjälkiavaus uudelleen käyttöön"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ei toiminut kunnolla, ja se poistettiin. Ota se uudelleen käyttöön, jotta voit avata puhelimen lukituksen sormenjäljellä."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ja <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> eivät toimineet kunnolla, ja ne poistettiin. Ota ne uudelleen käyttöön, jotta voit avata puhelimen lukituksen sormenjäljellä."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Ota kasvojentunnistusavaus uudelleen käyttöön"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Kasvomallisi ei toiminut kunnolla, ja se poistettiin. Ota se uudelleen käyttöön, jotta voit avata puhelimen lukituksen kasvoilla."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ota käyttöön"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ei nyt"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index bf70c3c..9aa982f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -284,6 +284,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Assist. vocale"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Verrouillage"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Répondre"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nouvelle notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Clavier physique"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sécurité"</string>
@@ -2414,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurer le Déverrouillage par empreinte digitale à nouveau"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ne fonctionnait pas bien et a été supprimée. Configurez-le à nouveau pour déverrouiller votre téléphone avec l\'empreinte digitale."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne fonctionnaient pas bien et ont été supprimées. Configurez-les à nouveau pour déverrouiller votre téléphone avec votre empreinte digitale."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configurer le Déverrouillage par reconnaissance faciale à nouveau"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Votre modèle facial ne fonctionnait pas bien et a été supprimé. Configurez-le à nouveau pour déverrouiller votre téléphone avec votre visage."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurer"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Plus tard"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5727224..bb1b30d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -284,6 +284,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Assistance vocale"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Répondre"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nouvelle notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Clavier physique"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sécurité"</string>
@@ -2414,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Reconfigurer le déverrouillage par empreinte digitale"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ne fonctionnait pas correctement et a été supprimée. Configurez-la à nouveau pour déverrouiller votre téléphone à l\'aide votre empreinte digitale."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> et <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ne fonctionnaient pas correctement et ont été supprimées. Configurez-les à nouveau pour déverrouiller votre téléphone à l\'aide de votre empreinte digitale."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Reconfigurer le déverrouillage par reconnaissance faciale"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Votre empreinte faciale ne fonctionnait pas correctement et a été supprimée. Configurez-la à nouveau pour déverrouiller votre téléphone à l\'aide votre visage."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuration"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Pas maintenant"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 663ef9a..1808743 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloquear"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Responder"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nova"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguranza"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensaxes"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configura de novo o desbloqueo dactilar"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"A <xliff:g id="FINGERPRINT">%s</xliff:g> non funcionaba correctamente, polo que se eliminou. Configúraa de novo para desbloquear o teléfono usando a impresión dixital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"As impresións dixitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> non funcionaban correctamente, polo que se eliminaron. Configúraas de novo para desbloquear o teléfono usando a impresión dixital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configura de novo o desbloqueo facial"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"O teu modelo facial non funcionaba correctamente, polo que se eliminou. Configúrao de novo para desbloquear o teléfono usando a cara."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora non"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index dc42537..f9b6ae3 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"વૉઇસ સહાય"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"લૉકડાઉન"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"જવાબ આપો"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"નવું નોટિફિકેશન"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ભૌતિક કીબોર્ડ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"સુરક્ષા"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ખોલો"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"તેની કામ કરવાની રીત"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"બાકી..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> બરાબર કામ કરતી ન હતી અને તેને ડિલીટ કરવામાં આવી હતી. તમારા ફોનને ફિંગરપ્રિન્ટ વડે અનલૉક કરવા માટે, તેનું ફરીથી સેટઅપ કરો."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> અને <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> બરાબર કામ કરતી ન હતી અને તેને ડિલીટ કરવામાં આવી હતી. તમારા ફોનને તમારી ફિંગરપ્રિન્ટ વડે અનલૉક કરવા માટે, તેનું ફરીથી સેટઅપ કરો."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ફેસ અનલૉક સુવિધાનું ફરી સેટઅપ કરો"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"તમારા ચહેરાનું મૉડલ બરાબર કામ કરતું ન હતું અને તેને ડિલીટ કરવામાં આવ્યું હતું. તમારા ફોનને ચહેરા વડે અનલૉક કરવા માટે, તેનું ફરીથી સેટઅપ કરો."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"સેટઅપ કરો"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"હમણાં નહીં"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 25f6ca1..ae9b17c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"आवाज़ से डिवाइस का इस्तेमाल"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"लॉकडाउन"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"जवाब दें"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नई सूचना"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"सामान्य कीबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
@@ -666,7 +667,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"फ़िंगरप्रिंट की पहचान नहीं हो पाई"</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फ़िंगरप्रिंट की पहचान नहीं हो पाई"</string>
- <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"चेहरा नहीं पहचाना गया. फ़िंगरप्रिंट इस्तेमाल करें."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"चेहरा की पहचान नहीं हो पाई. फ़िंगरप्रिंट का इस्तेमाल करें."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"चेहरे की पहचान की गई"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
@@ -2394,7 +2395,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"कीबोर्ड का लेआउट <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… पर सेट कर दिया गया है. इसे बदलने के लिए टैप करें."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"फ़िज़िकल कीबोर्ड कॉन्फ़िगर किए गए"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"कीबोर्ड देखने के लिए टैप करें"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"निजी"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"प्राइवेट"</string>
<string name="profile_label_clone" msgid="769106052210954285">"क्लोन"</string>
<string name="profile_label_work" msgid="3495359133038584618">"ऑफ़िस"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"ऑफ़िस 2"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ऐप्लिकेशन खोलें"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यह सेटिंग कैसे काम करती है"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रोसेस जारी है..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"अच्छे से काम न करने की वजह से <xliff:g id="FINGERPRINT">%s</xliff:g> को मिटा दिया गया. फ़िंगरप्रिंट की मदद से फ़ोन अनलॉक करने के लिए, फ़िंगरप्रिंट अनलॉक की सुविधा को दोबारा सेट अप करें."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"अच्छे से काम न करने की वजह से, <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> और <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> को मिटा दिया गया. फ़िंगरप्रिंट की मदद से फ़ोन अनलॉक करने के लिए, फ़िंगरप्रिंट अनलॉक की सुविधा दोबारा सेट अप करें."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"फ़ेस अनलॉक की सुविधा को दोबारा सेट अप करें"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"अच्छे से काम न करने की वजह से, चेहरे का मॉडल मिटा दिया गया. फ़ेस अनलॉक की सुविधा की मदद से फ़ोन अनलॉक करने के लिए, इस सुविधा को दोबारा सेट अप करें."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेट अप करें"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"अभी नहीं"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 117d4e5..0bd8be3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zaključaj"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova obavijest"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizička tipkovnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sigurnost"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Poruke"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako to funkcionira"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ponovno postavite otključavanje otiskom prsta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Otisak prsta <xliff:g id="FINGERPRINT">%s</xliff:g> nije dobro funkcionirao i izbrisan je. Ponovno ga postavite da biste otključali telefon otiskom prsta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Otisci prstiju <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nisu dobro funkcionirali i izbrisani su. Ponovno ih postavite da biste otključali telefon otiskom prsta."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Ponovno postavite otključavanje licem"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Model vašeg lica nije dobro funkcionirao i izbrisan je. Ponovno ga postavite da biste otključali telefon licem."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Postavi"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne sad"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index de8fa84..aeebbdc 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Hangsegéd"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zárolás"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Új értesítés"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizikai billentyűzet"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Biztonság"</string>
@@ -1997,7 +1999,7 @@
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Vészhelyzet"</string>
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Állítson be képernyőzárat"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Képernyőzár beállítása"</string>
- <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"A magánterület használatához állítson be képernyőzárat"</string>
+ <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"A privát terület használatához állítson be képernyőzárat"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"A Messages megnyitása"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hogyan működik?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Függőben…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"A Feloldás ujjlenyomattal funkció újbóli beállítása"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"A(z) <xliff:g id="FINGERPRINT">%s</xliff:g> nem működött megfelelően, ezért törölve lett. Állítsa be újra, hogy feloldhassa a telefonját az ujjlenyomata segítségével."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"A(z) <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> és a(z) <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nem működtek megfelelően, ezért törölve lettek. Állítsa be őket újra, hogy feloldhassa a telefonját az ujjlenyomata segítségével."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Állítsa be újra az Arcalapú feloldást"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Az arcmodellje nem működött megfelelően, ezért törölve lett. Állítsa be újra, hogy feloldhassa a telefonját az arca segítségével."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Beállítás"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Most nem"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index d379934..a0e0bd2 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ձայնային օգնութ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Արգելափակում"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Նոր ծանուցում"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Ֆիզիկական ստեղնաշար"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Անվտանգություն"</string>
@@ -2394,7 +2396,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Ստեղնաշարի համար կարգավորված են <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> դասավորությունները։ Հպեք փոխելու համար։"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Ֆիզիկական ստեղնաշարերը կարգավորված են"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Հպեք՝ ստեղնաշարերը դիտելու համար"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Անձնական"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Մասնավոր"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Կլոն"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Աշխատանքային"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Աշխատանքային 2"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Բացել Messages-ը"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ինչպես է դա աշխատում"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Առկախ է…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Նորից կարգավորեք մատնահետքով ապակողպումը"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"«<xliff:g id="FINGERPRINT">%s</xliff:g>» մատնահետքը հեռացվել է, քանի որ լավ չէր աշխատում։ Նորից կարգավորեք այն՝ ձեր հեռախոսը մատնահետքով ապակողպելու համար։"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"«<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>» և «<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>» մատնահետքերը հեռացվել են, քանի որ լավ չէին աշխատում։ Նորից կարգավորեք դրանք՝ ձեր հեռախոսը մատնահետքով ապակողպելու համար։"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Նորից կարգավորեք դեմքով ապակողպումը"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Ձեր դեմքի նմուշը հեռացվել է, քանի որ լավ չէր աշխատում։ Նորից կարգավորեք այն՝ ձեր հեռախոսը դեմքով ապակողպելու համար։"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Կարգավորել"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ոչ հիմա"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e6634d2..fb6180b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Kunci total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Notifikasi baru"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Keyboard fisik"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Keamanan"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Message"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara kerjanya"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Tertunda..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Siapkan Buka dengan Sidik Jari lagi"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak berfungsi dengan baik dan telah dihapus. Siapkan lagi untuk membuka kunci ponsel Anda dengan sidik jari."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak berfungsi dengan baik dan telah dihapus. Siapkan lagi untuk membuka kunci ponsel Anda dengan sidik jari."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Siapkan Buka dengan Wajah lagi"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Model wajah Anda tidak berfungsi dengan baik dan telah dihapus. Siapkan lagi untuk membuka kunci ponsel Anda dengan wajah."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Penyiapan"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Lain kali"</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index f77a18a..5b38461 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Raddaðstoð"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Læsing"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Svara"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ný tilkynning"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Vélbúnaðarlyklaborð"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Öryggi"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Opna Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Svona virkar þetta"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Í bið…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Setja upp fingrafarskenni aftur"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> virkaði illa og var eytt. Settu það upp aftur til að taka símann úr lás með fingrafari."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> virkuðu illa og var eytt. Settu þau upp aftur til að taka símann úr lás með fingrafarinu þínu."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Setja upp andlitskenni aftur"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Andlitslíkanið þitt virkaði illa og var eytt. Settu það upp aftur til að taka símann úr lás með andlitinu."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Setja upp"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ekki núna"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 95ccad5..f22b6531 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Blocco"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nuova notifica"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastiera fisica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sicurezza"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Apri Messaggi"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Come funziona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In attesa…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Riconfigura lo Sblocco con l\'Impronta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> non funzionava bene ed è stata eliminata. Riconfigurala per sbloccare lo smartphone con l\'impronta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> non funzionavano bene e sono state eliminate. Riconfigurale per sbloccare lo smartphone con l\'impronta."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Riconfigura lo Sblocco con il Volto"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Il tuo modello del volto non funzionava bene ed è stato eliminato. Riconfiguralo per sbloccare lo smartphone con il volto."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configura"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Non ora"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fee437a..3a924e1 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"האסיסטנט"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"נעילה"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"התראה חדשה"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"מקלדת פיזית"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"אבטחה"</string>
@@ -2395,7 +2397,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"הוגדרו מקלדות פיזיות"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"יש להקיש כדי להציג את המקלדות"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"פרטי"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"פרופיל פרטי"</string>
<string name="profile_label_clone" msgid="769106052210954285">"שכפול"</string>
<string name="profile_label_work" msgid="3495359133038584618">"פרופיל עבודה"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"פרופיל עבודה 2"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"לפתיחת Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"איך זה עובד"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"בהמתנה..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"הגדרה חוזרת של \'ביטול הנעילה בטביעת אצבע\'"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> לא פעלה היטב ולכן היא נמחקה. עליך להגדיר אותה שוב כדי שתהיה לך אפשרות לבטל את הנעילה של הטלפון באמצעות טביעת אצבע."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ו<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> לא פעלו היטב ולכן הן נמחקו. עליך להגדיר אותן שוב כדי שתהיה לך אפשרות לבטל את הנעילה של הטלפון באמצעות טביעת אצבע."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"הגדרה חוזרת של \'פתיחה ע\"י זיהוי הפנים\'"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"התבנית לזיהוי הפנים לא פעלה היטב ולכן היא נמחקה. עליך להגדיר אותה שוב כדי שתהיה לך אפשרות לבטל את הנעילה של הטלפון באמצעות זיהוי הפנים."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"הגדרה"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"לא עכשיו"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 726db1c..a802d90 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"音声アシスト"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ロックダウン"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"返信"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新しい通知"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"物理キーボード"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"セキュリティ"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"メッセージ アプリを開く"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"仕組み"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"保留中..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"指紋認証をもう一度設定してください"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> が正常に機能せず、削除されました。指紋認証でスマートフォンのロックを解除するには、設定し直してください。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> と <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> が正常に機能せず、削除されました。指紋認証でスマートフォンのロックを解除するには、設定し直してください。"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"顔認証をもう一度設定してください"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"顔モデルが正常に機能せず、削除されました。顔認証でスマートフォンのロックを解除するには、設定し直してください。"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"後で"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index bdf6c48..338ec1c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ხმოვანი ასისტ."</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"დაბლოკვა"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"პასუხი"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ახალი შეტყობინება"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ფიზიკური კლავიატურა"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"უსაფრთხოება"</string>
@@ -2394,7 +2395,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"დაყენდა კლავიატურის განლაგება: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… შეეხეთ შესაცვლელად."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ფიზიკური კლავიატურები კონფიგურირებულია"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"შეეხეთ კლავიატურების სანახავად"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"პირადი"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"კერძო"</string>
<string name="profile_label_clone" msgid="769106052210954285">"კლონი"</string>
<string name="profile_label_work" msgid="3495359133038584618">"სამსახური"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"სამსახური 2"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages-ის გახსნა"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"მუშაობის პრინციპი"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"მომლოდინე..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ანაბეჭდით განბლოკვის ხელახლა დაყენება"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> კარგად არ მუშაობდა და წაიშალა. თავიდან დააყენეთ, რათა თქვენი ტელეფონი თითის ანაბეჭდის საშუალებით განბლოკოთ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> და <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> კარგად არ მუშაობდნენ და წაიშალა. თავიდან დააყენეთ, რათა თქვენი ტელეფონი თითის ანაბეჭდის საშუალებით განბლოკოთ."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"დააყენეთ სახით განბლოკვა ხელახლა"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"თქვენი სახის მოდელი კარგად არ მუშაობდა და წაიშალა. თავიდან დააყენეთ, რათა თქვენი ტელეფონი სახის საშუალებით განბლოკოთ."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"დაყენება"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ახლა არა"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 55cf92b..e407c09 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Дауыс көмекшісі"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Құлыптау"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Жаңа хабарландыру"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физикалық пернетақта"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Қауіпсіздік"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages қолданбасын ашу"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Бұл қалай орындалады?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Дайын емес…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Саусақ ізімен ашу функциясын қайта реттеу"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> саусақ ізі дұрыс істемегендіктен жойылды. Телефонды саусақ ізімен ашу үшін оны қайта реттеңіз."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Саусақ іздері (<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> және <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>) дұрыс істемегендіктен жойылды. Телефонды саусақ ізімен ашу үшін оларды қайта реттеңіз."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Бет тану функциясын қайта реттеу"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Бет үлгісі дұрыс істемегендіктен жойылды. Телефонды бетпен ашу үшін оны қайта реттеңіз."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Реттеу"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Қазір емес"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 6a826db4..b021038 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ជំនួយសម្លេង"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ការចាក់សោ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ឆ្លើយតប"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ការជូនដំណឹងថ្មី"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ក្ដារចុចរូបវន្ត"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"សុវត្ថិភាព"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"បើកកម្មវិធី Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"របៀបដែលវាដំណើរការ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"កំពុងរង់ចាំ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"រៀបចំការដោះសោដោយស្កេនស្នាមម្រាមដៃម្ដងទៀត"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> មិនដំណើរការល្អទេ ហើយត្រូវបានលុបចេញហើយ។ រៀបចំវាម្ដងទៀត ដើម្បីដោះសោទូរសព្ទរបស់អ្នកដោយប្រើស្នាមម្រាមដៃ។"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> និង <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> មិនដំណើរការល្អទេ ហើយត្រូវបានលុបចេញហើយ។ រៀបចំវាម្ដងទៀត ដើម្បីដោះសោទូរសព្ទរបស់អ្នកដោយប្រើស្នាមម្រាមដៃ។"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"រៀបចំការដោះសោដោយស្កេនមុខម្ដងទៀត"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"គំរូមុខរបស់អ្នកមិនដំណើរការល្អទេ ហើយត្រូវបានលុបចេញហើយ។ រៀបចំវាម្ដងទៀត ដើម្បីដោះសោទូរសព្ទរបស់អ្នកដោយប្រើមុខ។"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"រៀបចំ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"កុំទាន់"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 40d5138..535c125 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ಲಾಕ್ಡೌನ್"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ಪ್ರತ್ಯುತ್ತರಿಸಿ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ಹೊಸ ನೋಟಿಫಿಕೇಶನ್"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ಭದ್ರತೆ"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ಅನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ಬಾಕಿ ಉಳಿದಿದೆ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲ ಹಾಗೂ ಅದನ್ನು ಅಳಿಸಲಾಗಿದೆ. ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಮೂಲಕ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ಅದನ್ನು ಪುನಃ ಸೆಟಪ್ ಮಾಡಿ."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ಮತ್ತು <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲ ಹಾಗೂ ಅವುಗಳನ್ನು ಅಳಿಸಲಾಗಿದೆ. ನಿಮ್ಮ ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಮೂಲಕ ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ಅವುಗಳನ್ನು ಪುನಃ ಸೆಟಪ್ ಮಾಡಿ."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"ನಿಮ್ಮ ಫೇಸ್ ಮಾಡೆಲ್ ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲ ಹಾಗೂ ಅದನ್ನು ಅಳಿಸಲಾಗಿದೆ. ಫೇಸ್ ಮೂಲಕ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ಅದನ್ನು ಪುನಃ ಸೆಟಪ್ ಮಾಡಿ."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ಸೆಟಪ್ ಮಾಡಿ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ಈಗ ಬೇಡ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index dd47628..7a8d324 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"음성 지원"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"잠금"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"새 알림"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"물리적 키보드"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"보안"</string>
@@ -1388,7 +1390,7 @@
<string name="no_permissions" msgid="5729199278862516390">"권한 필요 없음"</string>
<string name="perm_costs_money" msgid="749054595022779685">"비용이 부과될 수 있습니다."</string>
<string name="dlg_ok" msgid="5103447663504839312">"확인"</string>
- <string name="usb_charging_notification_title" msgid="1674124518282666955">"이 기기를 USB로 충전 중."</string>
+ <string name="usb_charging_notification_title" msgid="1674124518282666955">"이 기기를 USB로 충전 중"</string>
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"USB를 통해 연결된 기기 충전"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB 파일 전송 사용 설정됨"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB를 통해 PTP 사용 설정됨"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"메시지 열기"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"작동 방식"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"대기 중…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"지문 잠금 해제 다시 설정"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g>이(가) 제대로 작동하지 않아 삭제되었습니다. 지문으로 휴대전화를 잠금 해제하려면 다시 설정하세요."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> 및 <xliff:g id="FINGERPRINT_1">%2$s</xliff:g>이(가) 제대로 작동하지 않아 삭제되었습니다. 지문으로 휴대전화를 잠금 해제하려면 다시 설정하세요."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"얼굴 인식 잠금 해제 다시 설정"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"얼굴 모델이 제대로 작동하지 않아 삭제되었습니다. 얼굴로 휴대전화를 잠금 해제하려면 다시 설정하세요."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"설정"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"나중에"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index bb29c36..8a233a3 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Үн жардамчысы"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Бекем кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Жаңы эскертме"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Аппараттык баскычтоп"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Коопсуздук"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Жазышуулар колдонмосун ачуу"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ал кантип иштейт"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Кезекте турат..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Манжа изи менен ачуу функциясын кайра тууралаңыз"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ойдогудай иштебегендиктен, жок кылынды. Телефондо Манжа изи менен ачуу функциясын колдонуу үчүн аны кайра тууралаңыз."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> жана <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ойдогудай иштебегендиктен, жок кылынды. Телефонду манжа изи менен ачуу үчүн аларды кайра тууралаңыз."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Жүзүнөн таанып ачуу функциясын кайрадан тууралаңыз"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Жүзүңүздүн үлгүсү ойдогудай иштебегендиктен, жок кылынды. Телефондо Жүзүнөн таанып ачуу функциясын колдонуу үчүн аны кайра тууралаңыз."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Тууралоо"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Азыр эмес"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 5fa0fc1..ec583038 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ຊ່ວຍເຫຼືອທາງສຽງ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ລັອກໄວ້"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ຕອບກັບ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ການແຈ້ງເຕືອນໃໝ່"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ແປ້ນພິມພາຍນອກ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ຄວາມປອດໄພ"</string>
@@ -2394,7 +2395,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ຕັ້ງໂຄງຮ່າງແປ້ນພິມເປັນ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… ແຕະເພື່ອປ່ຽນແປງ."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ຕັ້ງຄ່າແປ້ນພິມແທ້ແລ້ວ"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ແຕະເພື່ອເບິ່ງແປ້ນພິມ"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"ສ່ວນຕົວ"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"ສ່ວນບຸກຄົນ"</string>
<string name="profile_label_clone" msgid="769106052210954285">"ໂຄລນ"</string>
<string name="profile_label_work" msgid="3495359133038584618">"ວຽກ"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"ວຽກ 2"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"ເປີດ Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ມັນເຮັດວຽກແນວໃດ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ລໍຖ້າດຳເນີນການ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືຄືນໃໝ່"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ເຮັດວຽກໄດ້ບໍ່ດີ ແລະ ຖືກລຶບອອກແລ້ວ. ໃຫ້ຕັ້ງຄ່າມັນຄືນໃໝ່ເພື່ອປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍລາຍນິ້ວມື."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ແລະ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ເຮັດວຽກໄດ້ບໍ່ດີ ແລະ ຖືກລຶບອອກແລ້ວ. ໃຫ້ຕັ້ງຄ່າພວກມັນຄືນໃໝ່ເພື່ອປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍລາຍນິ້ວມື."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ຕັ້ງຄ່າການປົດລັອກດ້ວຍໜ້າຄືນໃໝ່"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"ຮູບແບບໃບໜ້າຂອງທ່ານເຮັດວຽກໄດ້ບໍ່ດີ ແລະ ຖືກລຶບອອກແລ້ວ. ໃຫ້ຕັ້ງຄ່າມັນຄືນໃໝ່ເພື່ອປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍໃບໜ້າ."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ຕັ້ງຄ່າ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ບໍ່ຟ້າວເທື່ອ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e06c2ef..d3bf781 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -285,6 +285,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Užrakinimas"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Atsakyti"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Naujas pranešimas"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizinė klaviatūra"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sauga"</string>
@@ -2415,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Atidaryti programą „Messages“"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kaip tai veikia"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Laukiama..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Atrakinimo piršto atspaudu nustatymas dar kartą"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> neveikė tinkamai ir buvo ištrintas. Nustatykite jį dar kartą, kad atrakintumėte telefoną piršto atspaudu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ir <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> neveikė tinkamai ir buvo ištrinti. Nustatykite juos dar kartą, kad atrakintumėte telefoną piršto atspaudu."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Atrakinimo pagal veidą nustatymas iš naujo"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Jūsų veido modelis neveikė tinkamai ir buvo ištrintas. Nustatykite jį dar kartą, kad atrakintumėte telefoną pagal veidą."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nustatyti"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne dabar"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d2a6cd9..8be327d 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Balss palīgs"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloķēšana"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"Pārsniedz"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Jauns paziņojums"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziskā tastatūra"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Drošība"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Atvērt lietotni Ziņojumi"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Darbības principi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Gaida…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> nedarbojās pareizi un tika izdzēsts. Iestatiet to atkal, lai varētu atbloķēt tālruni ar pirksta nospiedumu."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> un <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nedarbojās pareizi un tika izdzēsti. Iestatiet tos atkal, lai varētu atbloķētu tālruni ar pirksta nospiedumu."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Vēlreiz iestatiet autorizāciju pēc sejas"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Jūsu sejas modelis nedarbojās pareizi un tika izdzēsts. Iestatiet to atkal, lai varētu atbloķēt tālruni ar seju."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Iestatīt"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne tagad"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 796f9efe..d8acc30 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -153,7 +153,7 @@
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> по <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string>
<string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е препратено"</string>
<string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е проследен"</string>
- <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Безбедност на мобилна мрежа"</string>
+ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Безбедност на мобилната мрежа"</string>
<string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Шифрирање, известувања за нешифрирани мрежи"</string>
<string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Пристапено е до ID на уредот"</string>
<string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Во <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, мрежа во близина го сними уникатниот ID (IMSI или IMEI) на вашиот телефон со користење на вашата SIM-картичка на <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string>
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Гласовна помош"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Заклучување"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Одговори"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново известување"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физичка тастатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безбедност"</string>
@@ -341,7 +342,7 @@
<string name="permgrouplab_phone" msgid="570318944091926620">"Телефон"</string>
<string name="permgroupdesc_phone" msgid="270048070781478204">"упатува и управува со телефонски повици"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"Телесни сензори"</string>
- <string name="permgroupdesc_sensors" msgid="2610631290633747752">"пристапува до податоците од сензорите за виталните знаци"</string>
+ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"пристапува до податоците од сензорите за виталните функции"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Известувања"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"да прикажува известувања"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"да ги вчитува содржините од прозорците"</string>
@@ -2394,9 +2395,9 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Распоредот на тастатурата е поставен на <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Допрете за да промените."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физичките тастатури се конфигурирани"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Допрете за да ги видите тастатурите"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Приватен профил"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Приватно"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Клониран профил"</string>
- <string name="profile_label_work" msgid="3495359133038584618">"Работен профил"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Работно"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Работен профил 2"</string>
<string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отворете ја Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Дознајте како функционира"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Во фаза на чекање…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Поставете „Отклучување со отпечаток“ повторно"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> не функционираше добро, па се избриша. Поставете го повторно за да го отклучувате телефонот со отпечаток."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> не функционираа добро, па се избришаа. Поставете ги повторно за да го отклучувате телефонот со отпечаток."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Поставете „Отклучување со лик“ повторно"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Вашиот модел на лик не функционираше добро, па се избриша. Поставете го повторно за да го отклучите телефонот со лик."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Поставете"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сега"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index a0b4c8d..747631a 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"വോയ്സ് സഹായം"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ലോക്ക്ഡൗൺ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"മറുപടി"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"പുതിയ അറിയിപ്പ്"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ഫിസിക്കൽ കീബോഡ്"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"സുരക്ഷ"</string>
@@ -1904,8 +1905,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി ലാഭിക്കൽ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
- <string name="battery_saver_description" msgid="8518809702138617167">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, പശ്ചാത്തല ആക്റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്വർക്ക് കണക്ഷനുകളും അത് പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി സേവർ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"ബാറ്ററി സേവർ ഡാർക്ക് തീം ഓണാക്കുന്നു, പശ്ചാത്തല ആക്റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്വർക്ക് കണക്ഷനുകളും അത് പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റാ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ഓണാക്കുക"</string>
@@ -2147,7 +2148,7 @@
<string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ബാറ്ററി സേവർ ഓണാണ്"</string>
<string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ബാറ്ററി ലൈഫ് വർദ്ധിപ്പിക്കാൻ ബാറ്ററി സേവർ ഓണാക്കിയിരിക്കുന്നു"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ബാറ്ററി ലാഭിക്കൽ"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കിയിരിക്കുന്നു"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ബാറ്ററി സേവർ ഓഫാക്കിയിരിക്കുന്നു"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ഫോണിൽ വേണ്ടത്ര ചാർജ് ഉണ്ട്. ഫീച്ചറുകൾക്ക് ഇനി നിയന്ത്രണമില്ല."</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"ടാബ്ലെറ്റിൽ വേണ്ടത്ര ചാർജ് ഉണ്ട്. ഫീച്ചറുകൾക്ക് ഇനി നിയന്ത്രണമില്ല."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ഉപകരണത്തിൽ വേണ്ടത്ര ചാർജ് ഉണ്ട്. ഫീച്ചറുകൾക്ക് ഇനി നിയന്ത്രണമില്ല."</string>
@@ -2384,7 +2385,7 @@
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ഉപകരണത്തിന് ചൂട് കൂടുതലാണ്"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"നിങ്ങളുടെ ഫോൺ വളരെയധികം ചൂടാകുന്നതിനാൽ ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല"</string>
- <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ബാറ്ററി ലാഭിക്കൽ ഓണായതിനാൽ ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല. നിങ്ങൾക്ക് ഇത് ക്രമീകരണത്തിൽ ഓഫാക്കാം."</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ബാറ്ററി സേവർ ഓണായതിനാൽ ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല. നിങ്ങൾക്ക് ഇത് ക്രമീകരണത്തിൽ ഓഫാക്കാം."</string>
<string name="device_state_notification_settings_button" msgid="691937505741872749">"ക്രമീകരണത്തിലേക്ക് പോകുക"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ഓഫാക്കുക"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> കോൺഫിഗർ ചെയ്തു"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages തുറക്കുക"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ഇത് പ്രവർത്തിക്കുന്നത് എങ്ങനെയാണ്"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"തീർപ്പാക്കിയിട്ടില്ല..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ശരിയായി പ്രവർത്തിക്കാത്തതിനാൽ അത് ഇല്ലാതാക്കി. നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യുന്നതിനായി വീണ്ടും സജ്ജീകരിക്കുക."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> എന്നിവ ശരിയായി പ്രവർത്തിക്കാത്തതിനാൽ അവ ഇല്ലാതാക്കി. നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യുന്നതിനായി അവ വീണ്ടും സജ്ജീകരിക്കുക."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ഫെയ്സ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"നിങ്ങളുടെ മുഖ മോഡൽ ശരിയായി പ്രവർത്തിക്കാത്തതിനാൽ അത് ഇല്ലാതാക്കി. നിങ്ങളുടെ മുഖം ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യുന്നതിനായി വീണ്ടും സജ്ജീകരിക്കുക."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"സജ്ജീകരിക്കുക"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ഇപ്പോൾ വേണ്ട"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 5ba16fe..8d430ee 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Дуут туслах"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Түгжих"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Шинэ мэдэгдэл"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Биет гар"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Аюулгүй байдал"</string>
@@ -2394,7 +2396,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Гарын бүдүүвчийг <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> болгож тохируулсан… Өөрчлөхийн тулд товшино уу."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Биет гарыг тохируулсан"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Гарыг харахын тулд товшино уу"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Хувийн"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Хаалттай"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Ажил"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Ажил 2"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Мессежийг нээх"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Энэ хэрхэн ажилладаг вэ?"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Хүлээгдэж буй..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> сайн ажиллахгүй байсан тул үүнийг устгасан. Утасныхаа түгжээг хурууны хээгээр тайлахын тулд хурууны хээг дахин тохируулна уу."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> сайн ажиллахгүй байсан тул эдгээрийг устгасан. Утасныхаа түгжээг хурууныхаа хээгээр тайлахын тулд хоёр хурууны хээг дахин тохируулна уу."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Царайгаар түгжээ тайлахыг дахин тохируулна уу"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Таны нүүрний загвар сайн ажиллахгүй байсан бөгөөд үүнийг устгасан. Утасныхаа түгжээг царайгаар тайлахын тулд нүүрний загварыг дахин тохируулна уу."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Тохируулах"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Одоо биш"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 6c19cc5..022f5c3f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"व्हॉइस सहाय्य"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"लॉकडाउन"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"उत्तर द्या"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नवीन सूचना"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"वास्तविक कीबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages उघडा"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ते कसे काम करते"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रलंबित आहे..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फिंगरप्रिंट अनलॉक पुन्हा सेट करा"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"योग्यरीत्या काम करत नसल्यामुळे <xliff:g id="FINGERPRINT">%s</xliff:g> हटवले गेले आहे. तुमचे फिंगरप्रिंट वापरून फोन अनलॉक करण्यासाठी ते पुन्हा सेट करा."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"परफॉर्मन्समध्ये सुधारणा करण्यासाठी आणि योग्यरीत्या काम करत नसल्यामुळे <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> व <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> हटवली गेली आहेत. तुमचे फिंगरप्रिंट वापरून फोन अनलॉक करण्यासाठी ते पुन्हा सेट करा."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"फेस अनलॉक पुन्हा सेट करा"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"तुमचे फेस मॉडेल योग्यरीत्या काम करत नसल्यामुळे ते हटवले गेले आहे. तुमचा चेहरा वापरून फोन अनलॉक करण्यासाठी ते पुन्हा सेट करा."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेट करा"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"आताच नको"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 82c1a59..908f5a8 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Kunci semua"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Balas"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Pemberitahuan baharu"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Papan kekunci fizikal"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Keselamatan"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara ciri ini berfungsi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Belum selesai..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Sediakan Buka Kunci Cap Jari sekali lagi"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> tidak berfungsi dengan baik dan telah dipadamkan. Sediakan cap jari sekali lagi untuk membuka kunci telefon anda menggunakan cap jari."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dan <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> tidak berfungsi dengan baik dan telah dipadamkan. Sediakan kedua-dua cap jari tersebut sekali lagi untuk membuka kunci telefon anda menggunakan cap jari anda."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Sediakan semula Buka Kunci Wajah"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Model wajah anda tidak berfungsi dengan baik dan telah dipadamkan. Sediakan model wajah sekali lagi untuk membuka kunci telefon anda menggunakan wajah."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Sediakan"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Bukan sekarang"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 43b7ffa..22fe7f2 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"အသံ အကူအညီ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"လော့ခ်ဒေါင်း"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"၉၉၉+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"စာပြန်ရန်"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"အကြောင်းကြားချက်အသစ်"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"စက်၏ ကီးဘုတ်"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"လုံခြုံရေး"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ဖွင့်ရန်"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"အလုပ်လုပ်ပုံ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ဆိုင်းငံ့ထားသည်…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ကို စနစ်ထပ်မံထည့်သွင်းပါ"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> သိပ်အဆင်မပြေသဖြင့် ဖျက်ထားသည်။ သင့်ဖုန်းကို လက်ဗွေဖြင့်လော့ခ်ဖွင့်ရန် ၎င်းကို စနစ်ထပ်မံထည့်သွင်းပါ။"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> နှင့် <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> တို့ သိပ်အဆင်မပြေသဖြင့် ဖျက်ထားသည်။ သင့်ဖုန်းကို လက်ဗွေဖြင့်လော့ခ်ဖွင့်ရန် ၎င်းတို့ကို စနစ်ထပ်မံထည့်သွင်းပါ။"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ကို စနစ်ထပ်မံထည့်သွင်းပါ"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"သင့်မျက်နှာနမူနာ သိပ်အဆင်မပြေသဖြင့် ဖျက်ထားသည်။ သင့်ဖုန်းကို မျက်နှာဖြင့်လော့ခ်ဖွင့်ရန် ၎င်းကို စနစ်ထပ်မံထည့်သွင်းပါ။"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"စနစ်ထည့်သွင်းရန်"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ယခုမလုပ်ပါ"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ad4ffc2..3939f48 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Talehjelp"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Låsing"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nytt varsel"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysisk tastatur"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Sikkerhet"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Åpne Meldinger"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Slik fungerer det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Venter …"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurer opplåsingen med fingeravtrykk på nytt"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> fungerte ikke skikkelig og ble slettet. Du kan konfigurere det på nytt for å låse opp telefonen med fingeravtrykket."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> og <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> fungerte ikke skikkelig og ble slettet. Du kan konfigurere dem på nytt for å låse opp telefonen med fingeravtrykket."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurer ansiktslåsen på nytt"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Ansiktsmodellen din fungerte ikke skikkelig og ble slettet. Du kan konfigurere den på nytt for å låse opp telefonen med ansiktet."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfigurer"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ikke nå"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 1cde247..3253afa 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"आवाज सहायता"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"लकडाउन गर्नु…"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"९९९+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"जवाफ दिनुहोस्"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"नयाँ सूचना"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"फिजिकल किबोर्ड"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string>
@@ -481,7 +482,7 @@
<string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"एपलाई तपाईंको Android टिभी डिभाइसको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>
<string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"एपलाई तपाईंको फोनको आउने र बाहिर जाने कलहरूको बारेको डेटा सहित कल लग परिमार्जन गर्न अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्दछ।"</string>
<string name="permlab_bodySensors" msgid="662918578601619569">"प्रयोग गरिएका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गर्नुहोस्"</string>
- <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"यसले यो एप प्रयोग गरिँदै गरेका बेला यसलाई हृदयको गति, शरीरको तापक्रम तथा रगतमा रहेको अक्सिजनको प्रतिशत जस्ता बडी सेन्सरसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिन्छ।"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"यसले यो एप प्रयोग गरिरहेका बेला यसलाई हृदयको गति, शरीरको तापक्रम तथा रगतमा रहेको अक्सिजनको प्रतिशत जस्ता बडी सेन्सरसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिन्छ।"</string>
<string name="permlab_bodySensors_background" msgid="4912560779957760446">"ब्याकग्राउन्डमा चलेका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गर्नुहोस्"</string>
<string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"यसले यो एप ब्याकग्राउन्डमा चलेका बेला यसलाई हृदयको गति, शरीरको तापक्रम तथा रगतमा रहेको अक्सिजनको प्रतिशत जस्ता बडी सेन्सरसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिन्छ।"</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"पात्रोका कार्यक्रम र विवरणहरू पढ्ने"</string>
@@ -873,30 +874,30 @@
<item msgid="4537253139152229577">"घरको फ्याक्स"</item>
<item msgid="6751245029698664340">"पेजर"</item>
<item msgid="1692790665884224905">"अन्य"</item>
- <item msgid="6216981255272016212">"आफू अनुकूल"</item>
+ <item msgid="6216981255272016212">" कस्टम"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="7786349763648997741">"गृह"</item>
<item msgid="435564470865989199">"काम"</item>
<item msgid="4199433197875490373">"अन्य"</item>
- <item msgid="3233938986670468328">"आफू अनुकूल"</item>
+ <item msgid="3233938986670468328">" कस्टम"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="3861463339764243038">"गृह"</item>
<item msgid="5472578890164979109">"काम"</item>
<item msgid="5718921296646594739">"अन्य"</item>
- <item msgid="5523122236731783179">"आफू अनुकूल"</item>
+ <item msgid="5523122236731783179">" कस्टम"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="588088543406993772">"गृह"</item>
<item msgid="5503060422020476757">"काम"</item>
<item msgid="2530391194653760297">"अन्य"</item>
- <item msgid="7640927178025203330">"आफू अनुकूल"</item>
+ <item msgid="7640927178025203330">" कस्टम"</item>
</string-array>
<string-array name="organizationTypes">
<item msgid="6144047813304847762">"काम गर्नुहोस्"</item>
<item msgid="7402720230065674193">"अन्य"</item>
- <item msgid="808230403067569648">"आफू अनुकूल"</item>
+ <item msgid="808230403067569648">" कस्टम"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="7535761744432206400">"AIM"</item>
@@ -908,7 +909,7 @@
<item msgid="4717545739447438044">"ICQ"</item>
<item msgid="8293711853624033835">"Jabber"</item>
</string-array>
- <string name="phoneTypeCustom" msgid="5120365721260686814">"आफू अनुकूल"</string>
+ <string name="phoneTypeCustom" msgid="5120365721260686814">" कस्टम"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"गृह"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"मोबाइल"</string>
<string name="phoneTypeWork" msgid="6604967163358864607">"काम"</string>
@@ -929,24 +930,24 @@
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"कार्य पेजर"</string>
<string name="phoneTypeAssistant" msgid="757550783842231039">"सहायक"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
- <string name="eventTypeCustom" msgid="3257367158986466481">"आफू अनुकूल"</string>
+ <string name="eventTypeCustom" msgid="3257367158986466481">" कस्टम"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"जन्मदिन"</string>
<string name="eventTypeAnniversary" msgid="4684702412407916888">"वार्षिक समारोह"</string>
<string name="eventTypeOther" msgid="530671238533887997">"अन्य"</string>
- <string name="emailTypeCustom" msgid="1809435350482181786">"आफू अनुकूल"</string>
+ <string name="emailTypeCustom" msgid="1809435350482181786">" कस्टम"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"गृह"</string>
<string name="emailTypeWork" msgid="2020095414401882111">"काम"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"अन्य"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"मोबाइल"</string>
- <string name="postalTypeCustom" msgid="5645590470242939129">"आफू अनुकूल"</string>
+ <string name="postalTypeCustom" msgid="5645590470242939129">" कस्टम"</string>
<string name="postalTypeHome" msgid="7562272480949727912">"गृह"</string>
<string name="postalTypeWork" msgid="8553425424652012826">"काम"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"अन्य"</string>
- <string name="imTypeCustom" msgid="5653384545085765570">"आफू अनुकूल"</string>
+ <string name="imTypeCustom" msgid="5653384545085765570">" कस्टम"</string>
<string name="imTypeHome" msgid="6996507981044278216">"गृह"</string>
<string name="imTypeWork" msgid="2099668940169903123">"काम"</string>
<string name="imTypeOther" msgid="8068447383276219810">"अन्य"</string>
- <string name="imProtocolCustom" msgid="4437878287653764692">"आफू अनुकूल"</string>
+ <string name="imProtocolCustom" msgid="4437878287653764692">" कस्टम"</string>
<string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string>
<string name="imProtocolMsn" msgid="2257148557766499232">"Windows Live"</string>
<string name="imProtocolYahoo" msgid="5373338758093392231">"Yahoo"</string>
@@ -958,8 +959,8 @@
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
<string name="orgTypeWork" msgid="8684458700669564172">"काम"</string>
<string name="orgTypeOther" msgid="5450675258408005553">"अन्य"</string>
- <string name="orgTypeCustom" msgid="1126322047677329218">"आफू अनुकूल"</string>
- <string name="relationTypeCustom" msgid="282938315217441351">"आफू अनुकूल"</string>
+ <string name="orgTypeCustom" msgid="1126322047677329218">" कस्टम"</string>
+ <string name="relationTypeCustom" msgid="282938315217441351">" कस्टम"</string>
<string name="relationTypeAssistant" msgid="4057605157116589315">"सहायक"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"भाइ"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"सन्तान"</string>
@@ -974,7 +975,7 @@
<string name="relationTypeRelative" msgid="3396498519818009134">"आफन्त"</string>
<string name="relationTypeSister" msgid="3721676005094140671">"बहिनी"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"पति-पत्नी"</string>
- <string name="sipAddressTypeCustom" msgid="6283889809842649336">"आफू अनुकूल"</string>
+ <string name="sipAddressTypeCustom" msgid="6283889809842649336">" कस्टम"</string>
<string name="sipAddressTypeHome" msgid="5918441930656878367">"गृह"</string>
<string name="sipAddressTypeWork" msgid="7873967986701216770">"काम गर्नुहोस्"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"अन्य"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages खोल्नुहोस्"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यसले काम गर्ने तरिका"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"विचाराधीन..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ले काम गरिरहेको थिएन र त्यसलाई मेटाइयो। फिंगरप्रिन्ट प्रयोग गरी आफ्नो फोन अनलक गर्न त्यसलाई फेरि सेट अप गर्नुहोस्।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> र <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ले राम्ररी काम गरिरहेका थिएनन् र तिनलाई मेटाइयो। फिंगरप्रिन्ट प्रयोग गरी आफ्नो फोन अनलक गर्न तिनलाई फेरि सेट अप गर्नुहोस्।"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"फेस अनलक फेरि सेटअप गर्नुहोस्"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"तपाईंको फेस मोडेलले राम्ररी काम गरिरहेको थिएन र त्यसलाई मेटाइयो। अनुहार प्रयोग गरी आफ्नो फोन अनलक गर्न फेस मोडेल फेरि सेट अप गर्नुहोस्।"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"सेटअप गर्नुहोस्"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"अहिले होइन"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7bae96e..6ece574 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Spraakassistent"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999 +"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Beantwoorden"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nieuwe melding"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysiek toetsenbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Beveiliging"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Berichten openen"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe het werkt"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"In behandeling…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Ontgrendelen met vingerafdruk weer instellen"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> werkte niet goed en is verwijderd. Stel deze opnieuw in om de telefoon met je vingerafdruk te ontgrendelen."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> en <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> werkten niet goed en zijn verwijderd. Stel ze opnieuw in om de telefoon met je vingerafdruk te ontgrendelen."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Ontgrendelen via gezichtsherkenning weer instellen"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Je gezichtsmodel werkte niet goed en is verwijderd. Stel het opnieuw in om de telefoon met je gezicht te ontgrendelen."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Instellen"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Niet nu"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index c00998a..ae67a74 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ଭଏସ୍ ସହାୟକ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ଲକ୍ କରନ୍ତୁ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ପ୍ରତ୍ୟୁତ୍ତର ଦିଅ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ନୂଆ ବିଜ୍ଞପ୍ତି"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ଫିଜିକଲ୍ କୀ’ବୋର୍ଡ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ସୁରକ୍ଷା"</string>
@@ -2144,7 +2145,7 @@
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ନିୟମିତ ମୋଡ୍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ବେଟେରୀ ସେଭର ଚାଲୁ କରାଯାଇଛି"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ବ୍ୟାଟେରୀ ଲାଇଫ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କମ୍ କରିବା"</string>
- <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ବ୍ୟାଟେରୀ ସେଭର୍ ଚାଲୁ ଅଛି"</string>
+ <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"ବେଟେରୀ ସେଭର ଚାଲୁ ଅଛି"</string>
<string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"ବେଟେରୀ ଲାଇଫକୁ ବଢ଼ାଇବା ପାଇଁ ବେଟେରୀ ସେଭରକୁ ଚାଲୁ କରାଯାଇଛି"</string>
<string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ବେଟେରୀ ସେଭର"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ବ୍ୟାଟେରୀ ସେଭର୍ ବନ୍ଦ ଅଛି"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ଖୋଲନ୍ତୁ"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ଏହା କିପରି କାମ କରେ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ବାକି ଅଛି…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ସଠିକ ଭାବେ କାମ କରୁନାହିଁ ଏବଂ ଏହାକୁ ଡିଲିଟ କରାଯାଇଛି। ଟିପଚିହ୍ନ ମାଧ୍ୟମରେ ଆପଣଙ୍କ ଫୋନକୁ ଅନଲକ କରିବାକୁ ଏହାକୁ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ଏବଂ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ସଠିକ ଭାବେ କାମ କରୁନାହିଁ ଏବଂ ଏଗୁଡ଼ିକୁ ଡିଲିଟ କରାଯାଇଛି। ଆପଣଙ୍କ ଟିପଚିହ୍ନ ମାଧ୍ୟମରେ ଆପଣଙ୍କ ଫୋନକୁ ଅନଲକ କରିବାକୁ ଏଗୁଡ଼ିକୁ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ଫେସ୍ ଅନଲକ୍ ପୁଣି ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"ଆପଣଙ୍କ ଫେସ ମଡେଲ ସଠିକ ଭାବେ କାମ କରୁନାହିଁ ଏବଂ ଏହାକୁ ଡିଲିଟ କରାଯାଇଛି। ଫେସ ମାଧ୍ୟମରେ ଆପଣଙ୍କ ଫୋନକୁ ଅନଲକ କରିବାକୁ ଏହାକୁ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ସେଟ ଅପ କରନ୍ତୁ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 77020ac..5e79a7c 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ਲਾਕਡਾਊਨ"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ਜਵਾਬ ਦਿਓ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"ਨਵੀਂ ਸੂਚਨਾ"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ਸੁਰੱਖਿਆ"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ਐਪ ਖੋਲ੍ਹੋ"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"ਵਿਚਾਰ-ਅਧੀਨ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ਚੰਗੀ ਤਰ੍ਹਾਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਸੀ ਅਤੇ ਉਸਨੂੰ ਮਿਟਾਇਆ ਗਿਆ ਸੀ। ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰਨ ਲਈ ਇਸਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ਚੰਗੀ ਤਰ੍ਹਾਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੇ ਸੀ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਮਿਟਾਇਆ ਗਿਆ ਸੀ। ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ਫ਼ੇਸ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"ਤੁਹਾਡਾ ਚਿਹਰੇ ਦਾ ਮਾਡਲ ਚੰਗੀ ਤਰ੍ਹਾਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਸੀ ਅਤੇ ਉਸਨੂੰ ਮਿਟਾਇਆ ਗਿਆ ਸੀ। ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਚਿਹਰੇ ਨਾਲ ਅਣਲਾਕ ਕਰਨ ਲਈ ਇਸਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ਹੁਣੇ ਨਹੀਂ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 0971ae4..d810710 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -285,6 +285,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asystent głosowy"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Blokada"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Odpowiedz"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nowe powiadomienie"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Klawiatura fizyczna"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bezpieczeństwo"</string>
@@ -2415,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otwórz Wiadomości"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to działa"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Oczekiwanie…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Skonfiguruj ponownie odblokowywanie odciskiem palca"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Odcisk palca <xliff:g id="FINGERPRINT">%s</xliff:g> nie sprawdzał się dobrze i został usunięty. Skonfiguruj go ponownie, aby odblokowywać telefon odciskiem palca."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Odciski palca <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> i <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nie sprawdzały się dobrze i zostały usunięte. Skonfiguruj je ponownie, aby odblokowywać telefon odciskiem palca."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Skonfiguruj ponownie rozpoznawanie twarzy"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Twój model twarzy nie sprawdzał się dobrze i został usunięty. Skonfiguruj go ponownie, aby odblokowywać telefon za pomocą skanu twarzy."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Skonfiguruj"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nie teraz"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b04cd4c..e3b49a0 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueio total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
@@ -2395,7 +2397,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toque para mudar."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toque para conferir os teclados"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Particular"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Privado"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Trabalho"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Trabalho 2"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurar o Desbloqueio por impressão digital de novo"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não estava funcionando bem e foi excluída. Configure de novo para desbloquear o smartphone com a impressão digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não estavam funcionando bem e foram excluídas. Configure de novo para desbloquear o smartphone com a impressão digital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial de novo"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Seu modelo de rosto não estava funcionando bem e foi excluído. Configure de novo para desbloquear o smartphone com o rosto."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuração"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 90f9eda..512f697 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -284,6 +284,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Assist. de voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloquear"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Responder"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
@@ -327,7 +328,7 @@
<string name="permgroupdesc_storage" msgid="5378659041354582769">"aceder aos ficheiros no seu dispositivo"</string>
<string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"Música e áudio"</string>
<string name="permgroupdesc_readMediaAural" msgid="7565467343667089595">"aceder a música e áudio no seu dispositivo"</string>
- <string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"fotos e vídeos"</string>
+ <string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"Fotos e vídeos"</string>
<string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"aceder a fotos e vídeos no seu dispositivo"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Microfone"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"gravar áudio"</string>
@@ -2414,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre a app Mensagens"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configure o Desbloqueio por impressão digital novamente"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"A <xliff:g id="FINGERPRINT">%s</xliff:g> não estava a funcionar bem e foi eliminada. Configure-a novamente para desbloquear o telemóvel com a impressão digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"A <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não estavam a funcionar bem e foram eliminadas. Configure-as novamente para desbloquear o telemóvel com a sua impressão digital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial novamente"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"O seu modelo de rosto não estava a funcionar bem e foi eliminado. Configure-o novamente para desbloquear o telemóvel com o rosto."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurar"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b04cd4c..e3b49a0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueio total"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nova notificação"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Teclado físico"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Segurança"</string>
@@ -2395,7 +2397,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toque para mudar."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toque para conferir os teclados"</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Particular"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Privado"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Trabalho"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Trabalho 2"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurar o Desbloqueio por impressão digital de novo"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"A impressão digital <xliff:g id="FINGERPRINT">%s</xliff:g> não estava funcionando bem e foi excluída. Configure de novo para desbloquear o smartphone com a impressão digital."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"As impressões digitais <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> e <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> não estavam funcionando bem e foram excluídas. Configure de novo para desbloquear o smartphone com a impressão digital."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Configure o Desbloqueio facial de novo"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Seu modelo de rosto não estava funcionando bem e foi excluído. Configure de novo para desbloquear o smartphone com o rosto."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configuração"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Agora não"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c43df4f..7de9952 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistent vocal"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Blocare strictă"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"˃999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificare nouă"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastatură fizică"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Securitate"</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Deschide Mesaje"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cum funcționează"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"În așteptare..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Configurează din nou Deblocarea cu amprenta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> nu funcționa bine și s-a șters. Configureaz-o din nou pentru a-ți debloca telefonul cu amprenta."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> și <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nu funcționau bine și s-au șters. Configurează-le din nou pentru a-ți debloca telefonul cu amprenta."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Reconfigurează Deblocarea facială"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Modelul tău facial nu funcționa bine și s-a șters. Configurează-l din nou pentru a-ți debloca telefonul folosindu-ți chipul."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Configurează"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Nu acum"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 32a2338..d999bf5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -285,6 +285,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Аудиоподсказки"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Блокировка входа"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">">999"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Новое уведомление"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физическая клавиатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безопасность"</string>
@@ -668,7 +670,7 @@
</string-array>
<string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отпечаток не распознан."</string>
<string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"Отпечаток не распознан."</string>
- <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"Лицо не распознано. Используйте отпечаток."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"Лицо не распознано. Сканируйте отпечаток пальца."</string>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечаток пальца проверен"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Лицо распознано"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Лицо распознано, нажмите кнопку \"Подтвердить\""</string>
@@ -2396,7 +2398,7 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Настроены раскладки клавиатуры для яз.: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> и др. Нажмите, чтобы изменить."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физические клавиатуры настроены"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Нажмите, чтобы посмотреть подключенные клавиатуры."</string>
- <string name="profile_label_private" msgid="6463418670715290696">"Личный"</string>
+ <string name="profile_label_private" msgid="6463418670715290696">"Частный"</string>
<string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
<string name="profile_label_work" msgid="3495359133038584618">"Рабочий"</string>
<string name="profile_label_work_2" msgid="4691533661598632135">"Рабочий 2"</string>
@@ -2415,22 +2417,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Открыть Сообщения"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Узнать принцип работы"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Обработка…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Настройте разблокировку по отпечатку пальца заново"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Отпечаток пальца \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" оказался неудачным и был удален. Чтобы использовать разблокировку с помощью отпечатка пальца, настройте ее заново."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Отпечатки пальцев \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" и \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" оказались неудачными и были удалены. Чтобы использовать разблокировку с помощью отпечатка пальца, настройте ее заново."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Настройте фейсконтроль заново"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Модель лица оказалась неудачной и была удалена. Чтобы пользоваться фейсконтролем, настройте его заново."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Настроить"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сейчас"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 9539cef..a8eda4f 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"හඬ සහායක"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"අගුලු දැමීම"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"නව දැනුම්දීම"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"භෞතික යතුරු පුවරුව"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ආරක්ෂාව"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages විවෘත කරන්න"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"එය ක්රියා කරන ආකාරය"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"පොරොත්තුයි..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ඇඟිලි සලකුණු අගුලු හැරීම නැවත සකසන්න"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> හොඳින් ක්රියා නොකළේය, එය මකන ලදි ඇඟිලි සලකුණ මගින් ඔබේ දුරකථනය අගුලු හැරීමට එය නැවත සකසන්න."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> සහ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> හොඳින් ක්රියා නොකළේය, කාර්යසාධනය දියුණූ කිරීමට ඒවා මකන ලදි. ඔබේ ඇඟිලි සලකුණ මගින් ඔබේ දුරකථනය අගුලු හැරීමට ඒවා නැවත සකසන්න."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"මුහුණෙන් අගුලු හැරීම නැවත සකසන්න"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"ඔබේ මුහුණු මාදිලිය හොඳින් ක්රියා නොකරයි, එය මකන ලදි. මුහුණ මගින් ඔබේ දුරකථනය අගුලු හැරීමට එය නැවත සකසන්න."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"සකසන්න"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"දැන් නොවේ"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c72a426d..46897cb 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -285,6 +285,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Hlasový asistent"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Uzamknúť"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Nové upozornenie"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyzická klávesnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Zabezpečenie"</string>
@@ -2415,22 +2417,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvoriť Správy"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ako to funguje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Nespracovaná…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Znova nastavte odomknutie odtlačkom prsta"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Odtlačok <xliff:g id="FINGERPRINT">%s</xliff:g> nefungoval správne a bol odstránený. Ak chcete odomykať telefón odtlačkom prsta, nastavte ho znova."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Odtlačky <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> a <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nefungovali správne a boli odstránené. Ak chcete odomykať telefón odtlačkom prsta, nastavte ich znova."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Znova nastavte odomknutie tvárou"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Váš model tváre nefungoval správne a bol odstránený. Ak chcete odomykať telefón tvárou, nastavte ho znova."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastaviť"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Teraz nie"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e1be803..5c3696a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -285,6 +285,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Glas. pomočnik"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Zakleni"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999 +"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Odgovori"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Novo obvestilo"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fizična tipkovnica"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Varnost"</string>
@@ -1733,7 +1734,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ogledovanje in upravljanje zaslona"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Bere lahko vso vsebino na zaslonu ter prikaže vsebino prek drugih aplikacij."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Ogledovanje in izvajanje dejanj"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Spremlja lahko vaše interakcije z aplikacijo ali tipalom strojne opreme ter komunicira z aplikacijami v vašem imenu."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Spremlja lahko vaše interakcije z aplikacijo ali tipalom ter komunicira z aplikacijami v vašem imenu."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Dovoli"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Zavrni"</string>
<string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Odmesti"</string>
@@ -2415,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Odpri Sporočila"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako deluje"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"V teku …"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Vnovična nastavitev odklepanja s prstnim odtisom"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> ni deloval pravilno in je bil izbrisan. Znova ga nastavite, če želite telefon odklepati s prstnim odtisom."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> in <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nista delovala pravilno in sta bila izbrisana. Znova ju nastavite, če želite telefon odklepati s prstnim odtisom."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Vnovična nastavitev odklepanja z obrazom"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Model obraza ni deloval pravilno in je bil izbrisan. Znova ga nastavite, če želite telefon odklepati z obrazom."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Nastavi"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Ne zdaj"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 4d79ce7..4a6bdcb 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ndihma zanore"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Blloko"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Njoftim i ri"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tastiera fizike"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Siguria"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Hap \"Mesazhet\""</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Si funksionon"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Në pritje..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\""</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> nuk po funksiononte mirë dhe u fshi. Konfiguroje përsëri për ta shkyçur telefonin tënd me gjurmën e gishtit."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> dhe <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> nuk po funksiononin mirë dhe u fshinë. Konfiguroji përsëri për ta shkyçur telefonin tënd me gjurmën e gishtit."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Konfiguro \"Shkyçjen me fytyrë\" përsëri"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Modeli yt i fytyrës nuk po funksiononte mirë dhe u fshi. Konfiguroje përsëri për ta shkyçur telefonin tënd me fytyrën."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Konfiguro"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Jo tani"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 95ccead..86387c9 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -284,6 +284,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Гласовна помоћ"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Закључавање"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Ново обавештење"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физичка тастатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безбедност"</string>
@@ -835,11 +837,11 @@
<string name="policylab_watchLogin" msgid="7599669460083719504">"Надзор покушаја откључавања екрана"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Прати број нетачно унетих лозинки приликом откључавања екрана и закључава таблет или брише податке са таблета ако је нетачна лозинка унета превише пута."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава Android TV уређај или брише све податке са Android TV уређаја ако се унесе превише нетачних лозинки."</string>
- <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Прати број нетачно унетих лозинки при откључавању екрана и закључава систем за инфо-забаву или брише све податке са система за инфо-забаву ако је нетачна лозинка унета превише пута."</string>
+ <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Прати број нетачно унетих лозинки при откључавању екрана и закључава систем за информације и забаву или брише све податке са система за информације и забаву ако је нетачна лозинка унета превише пута."</string>
<string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Прати број нетачно унетих лозинки при откључавању екрана и закључава телефон или брише све податке са телефона ако је нетачна лозинка унета превише пута."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава таблет или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава Android TV уређај или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава систем за инфо-забаву или брише све податке овог профила ако се унесе превише нетачних лозинки."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава систем за информације и забаву или брише све податке овог профила ако се унесе превише нетачних лозинки."</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава телефон или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"Промена закључавања екрана"</string>
<string name="policydesc_resetPassword" msgid="4626419138439341851">"Мења откључавање екрана."</string>
@@ -848,13 +850,13 @@
<string name="policylab_wipeData" msgid="1359485247727537311">"Брисање свих података"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Брисање података на таблету без упозорења ресетовањем на фабричка подешавања."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Брише податке Android TV уређаја без упозорења помоћу ресетовања на фабричка подешавања."</string>
- <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Брише податке на систему за инфо-забаву без упозорења ресетовањем на фабричка подешавања."</string>
+ <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Брише податке на систему за информације и забаву без упозорења ресетовањем на фабричка подешавања."</string>
<string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Брисање података на телефону без упозорења ресетовањем на фабричка подешавања."</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Брисање података профила"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Обриши податке корисника"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Брише податке овог корисника на овом таблету без упозорења."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Брише податке овог корисника на овом Android TV уређају без упозорења."</string>
- <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"Брише податке овог профила на овом систему за инфо-забаву без упозорења."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"Брише податке овог профила на овом систему за информације и забаву без упозорења."</string>
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"Брише податке овог корисника на овом телефону без упозорења."</string>
<string name="policylab_setGlobalProxy" msgid="215332221188670221">"Подесите глобални прокси сервер уређаја"</string>
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"Подешава глобални прокси уређаја који ће се користити док су смернице омогућене. Само власник уређаја може да подеси глобални прокси."</string>
@@ -2414,22 +2416,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Отвори Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Принцип рада"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"На чекању..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Поново подесите откључавање отиском прста"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> није функционисао и избрисали смо га. Поново га подесите да бисте телефон откључавали отиском прста."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> и <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> нису функционисали и избрисали смо их. Поново их подесите да бисте телефон откључавали отиском прста."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Поново подесите откључавање лицем"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Ваш модел лица није функционисао и избрисали смо га. Поново га подесите да бисте телефон откључавали лицем."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Подеси"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не сада"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 0cbdda1..6c15ad8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Låsning"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Ny avisering"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fysiskt tangentbord"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Säkerhet"</string>
@@ -623,12 +625,12 @@
<string name="permdesc_postNotification" msgid="5974977162462877075">"Tillåter att appen visar aviseringar"</string>
<string name="permlab_turnScreenOn" msgid="219344053664171492">"Slå på skärmen"</string>
<string name="permdesc_turnScreenOn" msgid="4394606875897601559">"Tillåter att appen slår på skärmen."</string>
- <string name="permlab_useBiometric" msgid="6314741124749633786">"använd biometrisk maskinvara"</string>
- <string name="permdesc_useBiometric" msgid="7502858732677143410">"Tillåter att appen använder biometrisk maskinvara vid autentisering"</string>
- <string name="permlab_manageFingerprint" msgid="7432667156322821178">"hantera maskinvara för fingeravtryck"</string>
+ <string name="permlab_useBiometric" msgid="6314741124749633786">"använd biometrisk hårdvara"</string>
+ <string name="permdesc_useBiometric" msgid="7502858732677143410">"Tillåter att appen använder biometrisk hårdvara vid autentisering"</string>
+ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"hantera hårdvara för fingeravtryck"</string>
<string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Tillåter att appen anropar metoder för att lägga till och radera fingeravtrycksmallar."</string>
- <string name="permlab_useFingerprint" msgid="1001421069766751922">"använda maskinvara för fingeravtryck"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"Tillåter att appen använder maskinvara för fingeravtryck vid autentisering"</string>
+ <string name="permlab_useFingerprint" msgid="1001421069766751922">"använda hårdvara för fingeravtryck"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"Tillåter att appen använder hårdvara för fingeravtryck vid autentisering"</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"göra ändringar i din musiksamling"</string>
<string name="permdesc_audioWrite" msgid="8057399517013412431">"Tillåter att appen gör ändringar i din musiksamling."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"göra ändringar i din videosamling"</string>
@@ -642,7 +644,7 @@
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiera din identitet"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Fortsätt med hjälp av din biometriska data"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Fortsätt med hjälp av din biometriska data eller skärmlåset"</string>
- <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvara är inte tillgänglig"</string>
+ <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk hårdvara är inte tillgänglig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string>
<string name="biometric_face_not_recognized" msgid="5535599455744525200">"Ansiktet känns inte igen"</string>
@@ -670,7 +672,7 @@
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrycket har autentiserats"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Ansiktet har autentiserats"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Ansiktet har autentiserats. Tryck på Bekräfta"</string>
- <string name="fingerprint_error_hw_not_available" msgid="7755729484334001137">"Det finns ingen maskinvara för fingeravtryck"</string>
+ <string name="fingerprint_error_hw_not_available" msgid="7755729484334001137">"Det finns ingen hårdvara för fingeravtryck"</string>
<string name="fingerprint_error_no_space" msgid="7285481581905967580">"Det gick inte att konfigurera fingeravtryck"</string>
<string name="fingerprint_error_timeout" msgid="7361192266621252164">"Tiden för fingeravtrycksinställning gick ut. Försök igen."</string>
<string name="fingerprint_error_canceled" msgid="5541771463159727513">"Fingeravtrycksåtgärden avbröts"</string>
@@ -732,7 +734,7 @@
<string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Något täcker ansiktet. Hela ansiktet måste synas."</string>
<string-array name="face_acquired_vendor">
</string-array>
- <string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansiktsverifiering går ej. Otillgänglig maskinvara."</string>
+ <string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansiktsverifiering går ej. Otillgänglig hårdvara."</string>
<string name="face_error_timeout" msgid="2598544068593889762">"Försök att använda ansiktslåset igen"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Kan inte lagra ny ansiktsdata. Radera först gammal data."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Ansiktsåtgärden har avbrutits."</string>
@@ -1731,7 +1733,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Visa och styra skärmen"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Den kan läsa allt innehåll på skärmen och visa innehåll över andra appar."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Visa och vidta åtgärder"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Den kan registrera din användning av en app eller maskinvarusensor och interagera med appar åt dig."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Den kan registrera din användning av en app eller hårdvarusensor och interagera med appar åt dig."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Tillåt"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Neka"</string>
<string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Avinstallera"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Öppna Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Så fungerar det"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Väntar …"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Konfigurera fingeravtryckslås igen"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> fungerade inte bra och har raderats. Konfigurera det igen för att låsa upp telefonen med fingeravtryck."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> och <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> fungerade inte bra och har raderats. Konfigurera dem igen för att låsa upp telefonen med fingeravtryck."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Konfigurera ansiktslås igen"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Ansiktsmodellen fungerade inte bra och har raderats. Konfigurera den igen för att låsa upp telefonen med ansiktet."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ställ in"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Inte nu"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 10f55af..e8ba087 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Usaidizi wa Sauti"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Funga"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Jibu"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Arifa mpya"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Kibodi halisi"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Usalama"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Fungua Programu ya Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Utaratibu wake"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Inashughulikiwa..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Weka tena mipangilio ya Kufungua kwa Alama ya Kidole"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Alama ya <xliff:g id="FINGERPRINT">%s</xliff:g> ilikuwa na hitilafu na imefutwa. Iweke tena ili ufungue simu yako kwa alama ya kidole."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Alama za <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> na <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> zilikuwa na hitilafu na zimefutwa. Ziweke tena ili ufungue simu yako kwa alama ya kidole."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Weka tena mipangilio ya Kufungua kwa Uso"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Muundo wako wa uso ulikuwa na hitilafu na umefutwa. Uweke tena ili ufungue simu yako kwa uso."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Weka mipangilio"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Si sasa"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 466e29a..231b14c 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"குரல் உதவி"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"புதிய அறிவிப்பு"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"கைமுறை கீபோர்டு"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"பாதுகாப்பு"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"இது செயல்படும் விதம்"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"நிலுவையிலுள்ளது..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> சரியாகச் செயல்படவில்லை என்பதால் அது நீக்கபட்டது. கைரேகை மூலம் உங்கள் மொபைலை அன்லாக் செய்ய அதை மீண்டும் அமையுங்கள்."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> மற்றும் <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> சரியாகச் செயல்படவில்லை என்பதால் அவை நீக்கப்பட்டன. கைரேகை மூலம் உங்கள் மொபைலை அன்லாக் செய்ய அவற்றை மீண்டும் அமையுங்கள்."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"\'முகம் காட்டித் திறத்தல்\' அம்சத்தை மீண்டும் அமையுங்கள்"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"உங்கள் முகத் தோற்றப் பதிவு சரியாகச் செயல்படவில்லை என்பதால் அது நீக்கப்பட்டது. உங்கள் முகத்தைப் பயன்படுத்தி மொபைலை அன்லாக் செய்ய அதை மீண்டும் அமையுங்கள்."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"அமை"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"இப்போது வேண்டாம்"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index db75aac..5517dbf 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"వాయిస్ అసిస్టెంట్"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"లాక్ చేయండి"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"రిప్లయి ఇవ్వండి"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"కొత్త నోటిఫికేషన్"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"భౌతిక కీబోర్డ్"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"సెక్యూరిటీ"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Messagesను తెరవండి"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ఇది ఎలా పని చేస్తుంది"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"పెండింగ్లో ఉంది..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"వేలిముద్ర అన్లాక్ను మళ్లీ సెటప్ చేయండి"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> సరిగ్గా పని చేయడం లేదు, తొలగించబడింది. వేలిముద్రతో మీ ఫోన్ను అన్లాక్ చేయడానికి దాన్ని మళ్లీ సెటప్ చేయండి."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>, <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> బాగా పని చేయడం లేదు, తొలగించబడ్డాయి. మీ వేలిముద్రతో మీ ఫోన్ను అన్లాక్ చేయడానికి వాటిని మళ్లీ సెటప్ చేయండి."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ఫేస్ అన్లాక్ను మళ్లీ సెటప్ చేయండి"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"మీ ఫేస్ మోడల్ సరిగ్గా పని చేయడం లేదు, తొలగించబడింది. ఫేస్తో మీ ఫోన్ను అన్లాక్ చేయడానికి దాన్ని మళ్లీ సెటప్ చేయండి."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"సెటప్ చేయండి"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ఇప్పుడు కాదు"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 284a5f2..070875f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"ตัวช่วยเสียง"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"ปิดล็อก"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"ตอบ"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"การแจ้งเตือนใหม่"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"แป้นพิมพ์จริง"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"ความปลอดภัย"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"เปิด Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"วิธีการทำงาน"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"รอดำเนินการ..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g>ทำงานได้ไม่ดีและถูกลบออกไปแล้ว ตั้งค่าอีกครั้งเพื่อปลดล็อกโทรศัพท์ด้วยลายนิ้วมือ"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> และ <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ทำงานได้ไม่ดีและถูกลบออกไปแล้ว ตั้งค่าอีกครั้งเพื่อปลดล็อกโทรศัพท์ด้วยลายนิ้วมือ"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"ตั้งค่าการปลดล็อกด้วยใบหน้าอีกครั้ง"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"รูปแบบใบหน้าของคุณทำงานได้ไม่ดีและถูกลบออกไปแล้ว ตั้งค่าอีกครั้งเพื่อปลดล็อกโทรศัพท์ด้วยใบหน้า"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"ตั้งค่า"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ไว้ทีหลัง"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4dd4886..45a66a3 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"I-lockdown"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Sumagot"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Bagong notification"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Pisikal na keyboard"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Seguridad"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Buksan ang Messages"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Paano ito gumagana"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Nakabinbin..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"I-set up ulit ang Pag-unlock Gamit ang Fingerprint"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Hindi gumagana nang maayos ang <xliff:g id="FINGERPRINT">%s</xliff:g> at na-delete na ito. I-set up ulit ito para ma-unlock ang iyong telepono sa pamamagitan ng fingerprint."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Hindi gumagana nang maayos ang <xliff:g id="FINGERPRINT_0">%1$s</xliff:g> at <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> at na-delete na ang mga ito. I-set up ulit ang mga ito para ma-unlock ang iyong telepono gamit ang fingerprint mo."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"I-set up ulit ang Pag-unlock Gamit ang Mukha"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Hindi gumagana nang maayos ang iyong face model at na-delete na ito. I-set up ulit ito para ma-unlock ang iyong telepono sa pamamagitan ng mukha."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"I-set up"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Huwag muna"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 2b616de..64498b5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Sesli Yardım"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Tam kilitleme"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Yeni bildirim"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fiziksel klavye"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Güvenlik"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajlar\'ı aç"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"İşleyiş şekli"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Bekliyor..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Parmak İzi Kilidi\'ni tekrar kurun"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> iyi çalışmadığı için silindi. Telefonunuzun kilidini parmak iziyle açmak için tekrar kurun."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> ve <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> iyi çalışmadığı için silindi. Telefonunuzun kilidini parmak izinizle açmak için tekrar kurun."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Yüz Tanıma Kilidi\'ni tekrar kurun"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Yüz modeliniz iyi çalışmadığı için silindi. Telefonunuzun kilidini yüzünüzle açmak için tekrar kurun."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Ayarla"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Şimdi değil"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 850e21b..fcea7bb 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -285,6 +285,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Голос. підказки"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Блокування"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Нове сповіщення"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Фізична клавіатура"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Безпека"</string>
@@ -2415,22 +2417,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Відкрийте Повідомлення"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як це працює"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Обробка…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Налаштуйте розблокування відбитком пальця повторно"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"Відбиток \"<xliff:g id="FINGERPRINT">%s</xliff:g>\" працював неналежним чином, і його видалено. Налаштуйте його ще раз, щоб розблоковувати телефон за допомогою відбитка пальця."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"Відбитки \"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>\" і \"<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>\" працювали неналежним чином, і їх видалено. Налаштуйте їх ще раз, щоб розблоковувати телефон за допомогою відбитка пальця."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Налаштуйте фейс-контроль повторно"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Модель обличчя працювала неналежним чином, і її видалено. Налаштуйте її ще раз, щоб розблоковувати телефон за допомогою фейс-контролю."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Налаштувати"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Не зараз"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index d3fde3c..da592a4 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"مقفل"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"جواب دیں"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"نئی اطلاع"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"فزیکل کی بورڈ"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"سیکیورٹی"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"پیغامات ایپ کو کھولیں"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"اس کے کام کرنے کا طریقہ"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"زیر التواء..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> اچھی طرح کام نہیں کر رہا تھا اور حذف کر دیا گیا تھا۔ اپنے فون کو فنگر پرنٹ سے غیر مقفل کرنے کے لیے، اسے دوبارہ سیٹ اپ کریں۔"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> اور <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> اچھی طرح کام نہیں کر رہے تھے اور انہیں حذف کر دیا گیا تھا۔ اپنے فون کو اپنے فنگر پرنٹ سے غیر مقفل کرنے کے لیے انہیں دوبارہ سیٹ اپ کریں۔"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"فیس اَن لاک کو دوبارہ سیٹ اپ کریں"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"آپ کے چہرے کا ماڈل اچھی طرح کام نہیں کر رہا تھا اور حذف کر دیا گیا تھا۔ اپنے فون کو چہرے سے غیر مقفل کرنے کے لیے، اسے دوبارہ سیٹ اپ کریں۔"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"سیٹ اپ کریں"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ابھی نہیں"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c143244..0ef4ddc 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Ovozli yordam"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Qulflash"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Yangi bildirishnoma"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Tashqi klaviatura"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Xavfsizlik"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Xabarlar ilovasini ochish"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ishlash tartibi"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Kutilmoqda..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Barmoq izi bilan ochish funksiyasini qayta sozlang"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> yaxshi ishlamadi va oʻchirib tashlandi. Telefonni barmoq izi bilan ochish uchun uni qayta sozlang."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> va <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> yaxshi ishlamadi va oʻchirib tashlandi. Telefonni barmoq izi bilan ochish uchun ularni qayta sozlang."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Yuz bilan ochishni qayta sozlash"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Yuzingiz mobeli yaxshi ishlamadi va oʻchirib tashlandi. Telefonni yuz bilan ochish uchun uni qayta sozlang."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Sozlash"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Hozir emas"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a0775d4..4f2a9fd 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Trợ lý thoại"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Khóa"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Trả lời"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Thông báo mới"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Bàn phím vật lý"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Bảo mật"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Mở ứng dụng Tin nhắn"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cách hoạt động"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Đang chờ xử lý..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Thiết lập lại tính năng Mở khoá bằng vân tay"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> không dùng được và đã bị xoá. Hãy thiết lập lại để mở khoá điện thoại bằng vân tay."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> và <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> không dùng được và đã bị xoá. Hãy thiết lập lại để mở khoá điện thoại bằng vân tay."</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Thiết lập lại tính năng Mở khoá bằng khuôn mặt"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Mẫu khuôn mặt của bạn không dùng được và đã bị xoá. Hãy thiết lập lại để mở khoá điện thoại bằng khuôn mặt."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Thiết lập"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Để sau"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 00dd3db..1024322 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"语音助理"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"实体键盘"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"打开“信息”应用"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"运作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待归档…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新设置指纹解锁功能"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"“<xliff:g id="FINGERPRINT">%s</xliff:g>”无法正常使用,系统已将其删除。如要通过指纹解锁功能来解锁手机,请重新设置。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"“<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>”和“<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>”无法正常使用,系统已将它们删除。如要通过指纹解锁功能来解锁手机,请重新设置。"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"重新设置“人脸解锁”功能"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"您的脸部模型无法正常使用,系统已将其删除。如要通过人脸解锁功能来解锁手机,请重新设置。"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"设置"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"以后再说"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 142940a..baf9ef5 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"語音助手"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"回覆"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"實體鍵盤"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
@@ -651,11 +652,11 @@
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定解鎖憑證"</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"請用力按住感應器"</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"請按住感應器"</string>
<string name="fingerprint_acquired_insufficient" msgid="2410176550915730974">"無法辨識指紋,請再試一次。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"請清潔指紋感應器,然後再試一次"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"請清潔感應器,然後再試一次"</string>
- <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"請用力按住感應器"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"請按住感應器"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"手指移動太慢,請重試。"</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定「指紋解鎖」功能"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"由於「<xliff:g id="FINGERPRINT">%s</xliff:g>」無法正常運作,因此系統已將其刪除。請重新設定,才能使用指紋解鎖手機。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"由於「<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>」和「<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>」無法正常運作,因此系統已將其刪除。請重新設定,才能使用指紋解鎖手機。"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"重新設定「面孔解鎖」功能"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"由於面部模型無法正常運作,因此系統已將其刪除。請重新設定,才能使用面孔解鎖手機。"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"暫時不要"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b7ee23c..9eeb6dc 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -270,7 +270,7 @@
<string name="bugreport_option_full_title" msgid="7681035745950045690">"完整報告"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"如果你的裝置沒有回應或運行速度過慢,或是當你需要所有區段的報告時,建議你使用這個選項來減少系統干擾。這個選項不支援你輸入更多資訊,也不會擷取其他螢幕畫面。"</string>
<string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{系統將在 # 秒後擷取錯誤報告的螢幕截圖。}other{系統將在 # 秒後擷取錯誤報告的螢幕截圖。}}"</string>
- <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"已拍攝錯誤報告的螢幕截圖"</string>
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"已擷取錯誤報告的螢幕截圖"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"無法拍攝錯誤報告的螢幕截圖"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"靜音模式"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"音效已關閉"</string>
@@ -283,6 +283,7 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"語音小幫手"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"超過 999"</string>
+ <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"回覆"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"新通知"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"實體鍵盤"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"安全性"</string>
@@ -2413,22 +2414,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」應用程式"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"重新設定指紋解鎖"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"「<xliff:g id="FINGERPRINT">%s</xliff:g>」無法正常運作,因此系統已將其刪除。請重新設定,才能用指紋解鎖手機。"</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"「<xliff:g id="FINGERPRINT_0">%1$s</xliff:g>」和「<xliff:g id="FINGERPRINT_1">%2$s</xliff:g>」無法正常運作,因此系統已將其刪除。請重新設定,才能用指紋解鎖手機。"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"重新設定人臉解鎖"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"臉部模型無法正常運作,因此系統已將其刪除。請重新設定,才能用臉解鎖手機。"</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"設定"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"暫時不要"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a967fb6..7749b1b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -283,6 +283,8 @@
<string name="global_action_voice_assist" msgid="6655788068555086695">"Isisekeli sezwi"</string>
<string name="global_action_lockdown" msgid="2475471405907902963">"Khiya"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
+ <!-- no translation found for notification_compact_heads_up_reply (2425293958371284340) -->
+ <skip />
<string name="notification_hidden_text" msgid="2835519769868187223">"Isaziso esisha"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Ikhibhodi ephathekayo"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"Ukuphepha"</string>
@@ -2413,22 +2415,15 @@
<string name="satellite_notification_open_message" msgid="4149234979688273729">"Vula Imilayezo"</string>
<string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Indlela esebenza ngayo"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Ilindile..."</string>
- <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) -->
+ <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Setha Ukuvula ngesigxivizo somunwe futhi"</string>
+ <!-- no translation found for fingerprint_dangling_notification_msg_1 (8517140433796229725) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) -->
+ <!-- no translation found for fingerprint_dangling_notification_msg_2 (7578829498452127613) -->
<skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) -->
- <skip />
- <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) -->
- <skip />
- <!-- no translation found for face_dangling_notification_title (947852541060975473) -->
- <skip />
- <!-- no translation found for face_dangling_notification_msg (8806849376915541655) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) -->
- <skip />
- <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) -->
- <skip />
+ <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"I-<xliff:g id="FINGERPRINT">%s</xliff:g> ibingasebenzi kahle futhi isuliwe. Phinde uyisethe ukuze uvule ifoni yakho ngesigxivizo somunwe."</string>
+ <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"I-<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> kanye ne-<xliff:g id="FINGERPRINT_1">%2$s</xliff:g> ibingasebenzi kahle futhi isuliwe. Phinde uyisethe ukuze uvule ifoni yakho ngesigxivizo somunwe wakho"</string>
+ <string name="face_dangling_notification_title" msgid="947852541060975473">"Setha Ukuvula Ngobuso futhi"</string>
+ <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Imodeli yobuso yakho ibingasebenzi kahle futhi isuliwe. Phinde uyisethe ukuze uvule ifoni yakho ngobuso."</string>
+ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Setha"</string>
+ <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Hhayi manje"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5fa13ba..405324b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2589,6 +2589,8 @@
<li>The framework will set {@link android.R.attr#statusBarColor},
{@link android.R.attr#navigationBarColor}, and
{@link android.R.attr#navigationBarDividerColor} to transparent.
+ <li>The frameworks will send Configuration no longer considering system insets.
+ The Configuration will be stable regardless of the system insets change.
</ul>
<p>If this is true, the edge-to-edge enforcement won't be applied. However, this
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5bd2033..0676f72 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4723,6 +4723,8 @@
<!-- The broadcast intent name for notifying when the on-device model has been unloaded -->
<string name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" translatable="false"></string>
+ <!-- The DeviceConfig namespace for the default system on-device sandboxed inference service. -->
+ <string name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" translatable="false"></string>
<!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent for
wearable sensing. -->
@@ -6951,9 +6953,6 @@
an app is not changed during subsequent reboots. -->
<bool name="config_stopSystemPackagesByDefault">true</bool>
- <!-- Whether to show weather on the lock screen by default. -->
- <bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
-
<!-- Whether we should persist the brightness value in nits for the default display even if
the underlying display device changes. -->
<bool name="config_persistBrightnessNitsForDefaultDisplay">false</bool>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index cc02a7e..e420ffe 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -365,4 +365,23 @@
<item>xcap</item>
</string-array>
<java-symbol type="array" name="config_force_cellular_transport_capabilities" />
+
+ <!-- The time duration in millis after which DemoSimulator will move to CONNECTED state from
+ NOT_CONNECTED state if the device is aligned to satellite.
+ -->
+ <integer name="config_demo_pointing_aligned_duration_millis">15000</integer>
+ <java-symbol type="integer" name="config_demo_pointing_aligned_duration_millis" />
+
+ <!-- The time duration in millis after which DemoSimulator will move to NOT_CONNECTED state from
+ CONNECTED state if the device is not aligned to satellite.
+ -->
+ <integer name="config_demo_pointing_not_aligned_duration_millis">30000</integer>
+ <java-symbol type="integer" name="config_demo_pointing_not_aligned_duration_millis" />
+
+ <!-- Boolean indicating whether Telephony should wait for device alignment with satellite
+ before sending or receiving datagrams in demo mode.
+ -->
+ <bool name="config_wait_for_device_alignment_in_demo_datagram">false</bool>
+ <java-symbol type="bool" name="config_wait_for_device_alignment_in_demo_datagram" />
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 52ce993..b885e03 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -846,6 +846,12 @@
<dimen name="conversation_face_pile_protection_width">2dp</dimen>
<!-- The width of the protection of the face pile layout when expanded-->
<dimen name="conversation_face_pile_protection_width_expanded">@dimen/conversation_face_pile_protection_width</dimen>
+ <!-- size of the compact face pile -->
+ <dimen name="conversation_compact_face_pile_size">24dp</dimen>
+ <!-- size of the face pile avatar -->
+ <dimen name="conversation_compact_face_pile_avatar_size">17dp</dimen>
+ <!-- size of the face pile protection -->
+ <dimen name="conversation_compact_face_pile_protection_width">1dp</dimen>
<!-- The padding of the expanded message container-->
<dimen name="expanded_group_conversation_message_padding">32dp</dimen>
<!-- The stroke width of the ring used to visually mark a conversation as important -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 28678c1..a956a43 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -528,6 +528,13 @@
<!-- Shows up as the reason for the work profile deletion when the admin of an organization-owend device relinquishes it. [CHAR LIMIT=NONE] -->
<string name="device_ownership_relinquished">Admin relinquished device for personal use</string>
+ <!-- Private space deleted by IT admin notification--> <skip />
+ <!-- Shows up in the notification's title when the system deletes the private space due to admin policy. [CHAR LIMIT=NONE] -->
+ <string name="private_space_deleted_by_admin">Private space removed</string>
+ <!-- Content text for an expanded notification. The Title of the notification is "Private space removed".
+ This further explains that the private space is deleted by the system as a result of the current admin policy. [CHAR LIMIT=NONE]-->
+ <string name="private_space_deleted_by_admin_details">Your organisation does not allow private spaces on this managed device.</string>
+
<!-- Content title for a notification. This notification indicates that the device is managed
and network logging was activated by a device owner. [CHAR LIMIT=NONE]-->
<string name="network_logging_notification_title">Device is managed</string>
@@ -6491,9 +6498,9 @@
<!-- Fingerprint dangling notification title -->
<string name="fingerprint_dangling_notification_title">Set up Fingerprint Unlock again</string>
<!-- Fingerprint dangling notification content for only 1 fingerprint deleted -->
- <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted to improve performance</string>
+ <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted</string>
<!-- Fingerprint dangling notification content for more than 1 fingerprints deleted -->
- <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted to improve performance</string>
+ <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted</string>
<!-- Fingerprint dangling notification content for only 1 fingerprint deleted and no fingerprint left-->
<string name="fingerprint_dangling_notification_msg_all_deleted_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint.</string>
<!-- Fingerprint dangling notification content for more than 1 fingerprints deleted and no fingerprint left -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index acd3b37..7e2c111 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3947,6 +3947,7 @@
<java-symbol type="string" name="config_defaultOnDeviceSandboxedInferenceService" />
<java-symbol type="string" name="config_onDeviceIntelligenceModelLoadedBroadcastKey" />
<java-symbol type="string" name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" />
+ <java-symbol type="string" name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" />
<java-symbol type="string" name="config_retailDemoPackage" />
<java-symbol type="string" name="config_retailDemoPackageSignature" />
@@ -4488,6 +4489,8 @@
<!-- For device policy -->
<java-symbol type="array" name="config_packagesExemptFromSuspension" />
+ <java-symbol type="string" name="private_space_deleted_by_admin" />
+ <java-symbol type="string" name="private_space_deleted_by_admin_details" />
<!-- Accessibility take screenshot -->
<java-symbol type="string" name="capability_desc_canTakeScreenshot" />
@@ -4542,6 +4545,9 @@
<java-symbol type="dimen" name="conversation_avatar_size_group_expanded" />
<java-symbol type="dimen" name="conversation_face_pile_avatar_size" />
<java-symbol type="dimen" name="conversation_face_pile_avatar_size_group_expanded" />
+ <java-symbol type="dimen" name="conversation_compact_face_pile_size" />
+ <java-symbol type="dimen" name="conversation_compact_face_pile_avatar_size" />
+ <java-symbol type="dimen" name="conversation_compact_face_pile_protection_width" />
<java-symbol type="dimen" name="conversation_face_pile_protection_width" />
<java-symbol type="dimen" name="conversation_face_pile_protection_width_expanded" />
<java-symbol type="dimen" name="conversation_badge_protrusion_group_expanded" />
@@ -5224,9 +5230,6 @@
<java-symbol type="bool" name="config_hotspotNetworksEnabledForService"/>
<java-symbol type="bool" name="config_knownNetworksEnabledForService"/>
- <!-- Whether to show weather on the lockscreen by default. -->
- <java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
-
<!-- For keyboard notification -->
<java-symbol type="string" name="keyboard_layout_notification_selected_title"/>
<java-symbol type="string" name="keyboard_layout_notification_one_selected_message"/>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 4d7c009..67cceb5 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -60,6 +60,9 @@
<!-- Belgium: 4 digits, plus EU: http://www.mobileweb.be/en/mobileweb/sms-numberplan.asp -->
<shortcode country="be" premium="\\d{4}" free="8\\d{3}|116\\d{3}" />
+ <!-- Burkina Faso: 1-4 digits (standard system default, not country specific) -->
+ <shortcode country="bf" pattern="\\d{1,4}" free="3558" />
+
<!-- Bulgaria: 4-5 digits, plus EU -->
<shortcode country="bg" pattern="\\d{4,5}" premium="18(?:16|423)|19(?:1[56]|35)" free="116\\d{3}|1988|1490" />
@@ -175,8 +178,8 @@
<!-- Israel: 1-5 digits, known premium codes listed -->
<shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" />
- <!-- Iran: 4-6 digits, known premium codes listed -->
- <shortcode country="ir" pattern="\\d{4,6}" free="700791|700792" />
+ <!-- Iran: 4-8 digits, known premium codes listed -->
+ <shortcode country="ir" pattern="\\d{4,8}" free="700791|700792|100016|30008360" />
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
@@ -352,7 +355,7 @@
<shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" />
<!-- Yemen -->
- <shortcode country="ye" pattern="\\d{1,4}" free="5081" />
+ <shortcode country="ye" pattern="\\d{1,4}" free="5079" />
<!-- Zimbabwe -->
<shortcode country="zw" pattern="\\d{1,5}" free="33679" />
diff --git a/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodInfoSafeListTest.java b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodInfoSafeListTest.java
new file mode 100644
index 0000000..9d532e6
--- /dev/null
+++ b/core/tests/InputMethodCoreTests/src/com/android/internal/inputmethod/InputMethodInfoSafeListTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.view.inputmethod.InputMethodInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public final class InputMethodInfoSafeListTest {
+
+ @NonNull
+ private static InputMethodInfo createFakeInputMethodInfo(String packageName, String name) {
+ final ResolveInfo ri = new ResolveInfo();
+ final ServiceInfo si = new ServiceInfo();
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = packageName;
+ ai.enabled = true;
+ ai.flags |= ApplicationInfo.FLAG_SYSTEM;
+ si.applicationInfo = ai;
+ si.enabled = true;
+ si.packageName = packageName;
+ si.name = name;
+ si.exported = true;
+ si.nonLocalizedLabel = name;
+ ri.serviceInfo = si;
+ return new InputMethodInfo(ri, false, "", Collections.emptyList(), 1, false);
+ }
+
+ @NonNull
+ private static List<InputMethodInfo> createTestInputMethodList() {
+ final ArrayList<InputMethodInfo> list = new ArrayList<>();
+ list.add(createFakeInputMethodInfo("com.android.test.ime1", "TestIme1"));
+ list.add(createFakeInputMethodInfo("com.android.test.ime1", "TestIme2"));
+ list.add(createFakeInputMethodInfo("com.android.test.ime2", "TestIme"));
+ return list;
+ }
+
+ @Test
+ public void testCreate() {
+ assertNotNull(InputMethodInfoSafeList.create(createTestInputMethodList()));
+ }
+
+ @Test
+ public void testExtract() {
+ assertItemsAfterExtract(createTestInputMethodList(), InputMethodInfoSafeList::create);
+ }
+
+ @Test
+ public void testExtractAfterParceling() {
+ assertItemsAfterExtract(createTestInputMethodList(),
+ originals -> cloneViaParcel(InputMethodInfoSafeList.create(originals)));
+ }
+
+ @Test
+ public void testExtractEmptyList() {
+ assertItemsAfterExtract(Collections.emptyList(), InputMethodInfoSafeList::create);
+ }
+
+ @Test
+ public void testExtractAfterParcelingEmptyList() {
+ assertItemsAfterExtract(Collections.emptyList(),
+ originals -> cloneViaParcel(InputMethodInfoSafeList.create(originals)));
+ }
+
+ private static void assertItemsAfterExtract(@NonNull List<InputMethodInfo> originals,
+ @NonNull Function<List<InputMethodInfo>, InputMethodInfoSafeList> factory) {
+ final InputMethodInfoSafeList list = factory.apply(originals);
+ final List<InputMethodInfo> extracted = InputMethodInfoSafeList.extractFrom(list);
+ assertEquals(originals.size(), extracted.size());
+ for (int i = 0; i < originals.size(); ++i) {
+ assertNotSame("InputMethodInfoSafeList.extractFrom() must clone each instance",
+ originals.get(i), extracted.get(i));
+ assertEquals("Verify the cloned instances have the equal value",
+ originals.get(i).getPackageName(), extracted.get(i).getPackageName());
+ }
+
+ // Subsequent calls of InputMethodInfoSafeList.extractFrom() return an empty list.
+ final List<InputMethodInfo> extracted2 = InputMethodInfoSafeList.extractFrom(list);
+ assertTrue(extracted2.isEmpty());
+ }
+
+ @NonNull
+ private static InputMethodInfoSafeList cloneViaParcel(
+ @NonNull InputMethodInfoSafeList original) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final InputMethodInfoSafeList newInstance =
+ InputMethodInfoSafeList.CREATOR.createFromParcel(parcel);
+ assertNotNull(newInstance);
+ return newInstance;
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index eb3c84a..0e855af1 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -123,6 +123,7 @@
sdk_version: "core_platform",
test_suites: [
"device-tests",
+ "device-platinum-tests",
"automotive-tests",
],
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
index a0aff6e..3735274 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
@@ -35,6 +35,7 @@
import android.util.ArrayMap;
import android.util.MergedConfiguration;
import android.view.IWindow;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.window.ActivityWindowInfo;
import android.window.ClientWindowFrames;
@@ -85,6 +86,7 @@
private ClientWindowFrames mFrames;
private MergedConfiguration mMergedConfiguration;
private ActivityWindowInfo mActivityWindowInfo;
+ private InsetsSourceControl.Array mActiveControls;
@Before
public void setup() {
@@ -97,6 +99,7 @@
mFrames = new ClientWindowFrames();
mMergedConfiguration = new MergedConfiguration(mGlobalConfig, mConfiguration);
mActivityWindowInfo = new ActivityWindowInfo();
+ mActiveControls = new InsetsSourceControl.Array();
doReturn(mActivity).when(mHandler).getActivity(mActivityToken);
doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed();
@@ -164,4 +167,13 @@
true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,
true /* dragResizing */, mActivityWindowInfo);
}
+
+ @Test
+ public void testWindowStateInsetsControlChangeItem_execute() throws RemoteException {
+ final WindowStateInsetsControlChangeItem item = WindowStateInsetsControlChangeItem.obtain(
+ mWindow, mInsetsState, mActiveControls);
+ item.execute(mHandler, mPendingActions);
+
+ verify(mWindow).insetsControlChanged(mInsetsState, mActiveControls);
+ }
}
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index f34b8fd..f81b31d 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -16,16 +16,25 @@
package android.os;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.stream.Collectors.toList;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.xml.sax.InputSource;
+
+import java.io.StringReader;
+import java.util.stream.Stream;
+
+import javax.xml.parsers.DocumentBuilderFactory;
@RunWith(AndroidJUnit4.class)
@IgnoreUnderRavenwood(blockedBy = VintfObject.class)
@@ -39,12 +48,26 @@
@Test
public void testReport() {
String[] xmls = VintfObject.report();
- assertTrue(xmls.length > 0);
- // From /system/manifest.xml
- assertTrue(String.join("", xmls).contains(
- "<manifest version=\"1.0\" type=\"framework\">"));
- // From /system/compatibility-matrix.xml
- assertTrue(String.join("", xmls).contains(
- "<compatibility-matrix version=\"1.0\" type=\"framework\""));
+
+ assertThat(Stream.of(xmls).map(xml -> rootAndType(xml)).collect(toList()))
+ .containsExactly(
+ Pair.create("manifest", "framework"),
+ Pair.create("compatibility-matrix", "framework"),
+ Pair.create("manifest", "device"),
+ Pair.create("compatibility-matrix", "device")
+ );
+ }
+
+ private static Pair<String, String> rootAndType(String content) {
+ try {
+ var factory = DocumentBuilderFactory.newInstance();
+ var builder = factory.newDocumentBuilder();
+ var inputSource = new InputSource(new StringReader(content));
+ var document = builder.parse(inputSource);
+ var root = document.getDocumentElement();
+ return Pair.create(root.getTagName(), root.getAttribute("type"));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
index 5917cc1..58e5be2 100644
--- a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
+++ b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
@@ -99,6 +99,8 @@
} catch (WindowManager.BadTokenException e) {
// activity isn't running, we will ignore BadTokenException.
}
+ mViewRoot.setOnContentApplyWindowInsetsListener(
+ mock(Window.OnContentApplyWindowInsetsListener.class));
mBackAnimationController = new ImeBackAnimationController(mViewRoot, mInsetsController);
when(mWindowInsetsAnimationController.getHiddenStateInsets()).thenReturn(Insets.NONE);
@@ -132,6 +134,19 @@
}
@Test
+ public void testAdjustResizeWithEdgeToEdgePlaysAnim() {
+ // set OnContentApplyWindowInsetsListener to null (to simulate edge-to-edge enabled) and
+ // softInputMode=adjustResize
+ mViewRoot.mWindowAttributes.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+ mViewRoot.setOnContentApplyWindowInsetsListener(null);
+ // start back gesture
+ mBackAnimationController.onBackStarted(new BackEvent(0f, 0f, 0f, EDGE_LEFT));
+ // verify that ImeBackAnimationController takes control over IME insets
+ verify(mInsetsController, times(1)).controlWindowInsetsAnimation(anyInt(), any(), any(),
+ anyBoolean(), anyLong(), any(), anyInt(), anyBoolean());
+ }
+
+ @Test
public void testAdjustResizeWithoutAppWindowInsetsListenerNotPlayingAnim() {
// setup ViewRoot with softInputMode=adjustResize
mViewRoot.mWindowAttributes.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index d560ef2..6b9dbba 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -634,6 +634,42 @@
}
@Test
+ @EnableFlags({
+ Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS,
+ Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE})
+ public void testOnAccessibilityShortcut_settingNull_dialogShown_enablesDefaultShortcut()
+ throws Exception {
+ configureDefaultAccessibilityService();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
+ // Setting is only `null` during SUW.
+ Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
+ getController().performAccessibilityShortcut();
+
+ verify(mAccessibilityManagerService).enableShortcutsForTargets(
+ eq(true), eq(HARDWARE), mListCaptor.capture(), anyInt());
+ assertThat(mListCaptor.getValue()).containsExactly(SERVICE_NAME_STRING);
+ verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
+ @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
+ public void testOnAccessibilityShortcut_settingNull_dialogShown_writesDefaultSetting()
+ throws Exception {
+ configureDefaultAccessibilityService();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
+ // Setting is only `null` during SUW.
+ Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null);
+ getController().performAccessibilityShortcut();
+
+ assertThat(Settings.Secure.getString(mContentResolver,
+ ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEqualTo(SERVICE_NAME_STRING);
+ verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
+ }
+
+ @Test
public void getFrameworkFeatureMap_shouldBeUnmodifiable() {
final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
frameworkFeatureMap =
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b93cd46..500e9b7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -79,24 +79,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1789854065584848502": {
- "message": "startingData was nulled out before handling mAddStartingWindow: %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"5659016061937922595": {
"message": "Add starting %s: startingData=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-9066702108316454290": {
- "message": "Aborted starting %s: startingData=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STARTING_WINDOW",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"7506106334102501360": {
"message": "Added starting %s: startingWindow=%s startingView=%s",
"level": "VERBOSE",
@@ -1123,12 +1111,6 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/BlackFrame.java"
},
- "5256889109971284149": {
- "message": "CameraManager cannot be found.",
- "level": "ERROR",
- "group": "WM_DEBUG_STATES",
- "at": "com\/android\/server\/wm\/CameraStateMonitor.java"
- },
"8116030277393789125": {
"message": "Display id=%d is notified that Camera %s is open for package %s",
"level": "VERBOSE",
@@ -4189,18 +4171,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-707915937966769475": {
- "message": "unable to update pointer icon",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
- "-8663841671650918687": {
- "message": "unable to restore pointer icon",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-6186782212018913664": {
"message": "Invalid displayId for requestScrollCapture: %d",
"level": "ERROR",
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index bd13276..5a7b0bb 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -25,6 +25,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.text.FontConfig;
import android.util.SparseIntArray;
@@ -151,6 +152,7 @@
* @return A variable font family. null if a variable font cannot be built from the given
* fonts.
*/
+ @SuppressLint("BuilderSetStyle")
@FlaggedApi(FLAG_NEW_FONTS_FALLBACK_XML)
public @Nullable FontFamily buildVariableFamily() {
int variableFamilyType = analyzeAndResolveVariableType(mFonts);
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index 7d55928..5a1086c 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -23,6 +23,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.ActivityThread;
import android.os.Build;
import android.os.LocaleList;
@@ -314,6 +315,7 @@
* @param config an override line break config
* @return This {@code Builder}.
*/
+ @SuppressLint("BuilderSetStyle")
@FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public @NonNull Builder merge(@NonNull LineBreakConfig config) {
if (config.mLineBreakStyle != LINE_BREAK_STYLE_UNSPECIFIED) {
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index d8cf21e..94de066 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -18,6 +18,8 @@
import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
import static com.android.text.flags.Flags.FLAG_LETTER_SPACING_JUSTIFICATION;
+import static com.android.text.flags.Flags.FLAG_MISSING_GETTER_APIS;
+
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
@@ -488,6 +490,12 @@
private final long mNativePtr;
+ private final @BreakStrategy int mBreakStrategy;
+ private final @HyphenationFrequency int mHyphenationFrequency;
+ private final @JustificationMode int mJustificationMode;
+ private final int[] mIndents;
+ private final boolean mUseBoundsForWidth;
+
/**
* Use Builder instead.
*/
@@ -497,6 +505,67 @@
mNativePtr = nInit(breakStrategy, hyphenationFrequency,
justify == JUSTIFICATION_MODE_INTER_WORD, indents, useBoundsForWidth);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePtr);
+
+ mBreakStrategy = breakStrategy;
+ mHyphenationFrequency = hyphenationFrequency;
+ mJustificationMode = justify;
+ mIndents = indents;
+ mUseBoundsForWidth = useBoundsForWidth;
+ }
+
+ /**
+ * Returns the break strategy used for this line breaker.
+ *
+ * @return the break strategy used for this line breaker.
+ * @see Builder#setBreakStrategy(int)
+ */
+ @FlaggedApi(FLAG_MISSING_GETTER_APIS)
+ public @BreakStrategy int getBreakStrategy() {
+ return mBreakStrategy;
+ }
+
+ /**
+ * Returns the hyphenation frequency used for this line breaker.
+ *
+ * @return the hyphenation frequency used for this line breaker.
+ * @see Builder#setHyphenationFrequency(int)
+ */
+ @FlaggedApi(FLAG_MISSING_GETTER_APIS)
+ public @HyphenationFrequency int getHyphenationFrequency() {
+ return mHyphenationFrequency;
+ }
+
+ /**
+ * Returns the justification mode used for this line breaker.
+ *
+ * @return the justification mode used for this line breaker.
+ * @see Builder#setJustificationMode(int)
+ */
+ @FlaggedApi(FLAG_MISSING_GETTER_APIS)
+ public @JustificationMode int getJustificationMode() {
+ return mJustificationMode;
+ }
+
+ /**
+ * Returns the indents used for this line breaker.
+ *
+ * @return the indents used for this line breaker.
+ * @see Builder#setIndents(int[])
+ */
+ @FlaggedApi(FLAG_MISSING_GETTER_APIS)
+ public @Nullable int[] getIndents() {
+ return mIndents;
+ }
+
+ /**
+ * Returns true if this line breaker uses bounds as width for line breaking.
+ *
+ * @return true if this line breaker uses bounds as width for line breaking.
+ * @see Builder#setUseBoundsForWidth(boolean)
+ */
+ @FlaggedApi(FLAG_MISSING_GETTER_APIS)
+ public boolean getUseBoundsForWidth() {
+ return mUseBoundsForWidth;
}
/**
diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java
index 268e0a5..dfe485a 100644
--- a/keystore/java/android/security/AndroidProtectedConfirmation.java
+++ b/keystore/java/android/security/AndroidProtectedConfirmation.java
@@ -59,10 +59,6 @@
/**
* Requests keystore call into the confirmationui HAL to display a prompt.
- * @deprecated Android Protected Confirmation had a low adoption rate among Android device
- * makers and developers alike. Given the lack of devices supporting the
- * feature, it is deprecated. Developers can use auth-bound Keystore keys
- * as a partial replacement.
*
* @param listener the binder to use for callbacks.
* @param promptText the prompt to display.
@@ -72,7 +68,6 @@
* @return one of the {@code CONFIRMATIONUI_*} constants, for
* example {@code KeyStore.CONFIRMATIONUI_OK}.
*/
- @Deprecated
public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText,
byte[] extraData, String locale, int uiOptionsAsFlags) {
try {
@@ -89,16 +84,11 @@
/**
* Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
- * @deprecated Android Protected Confirmation had a low adoption rate among Android device
- * makers and developers alike. Given the lack of devices supporting the
- * feature, it is deprecated. Developers can use auth-bound Keystore keys
- * as a partial replacement.
*
* @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
* @return one of the {@code CONFIRMATIONUI_*} constants, for
* example {@code KeyStore.CONFIRMATIONUI_OK}.
*/
- @Deprecated
public int cancelConfirmationPrompt(IConfirmationCallback listener) {
try {
getService().cancelPrompt(listener);
@@ -113,14 +103,9 @@
/**
* Requests keystore to check if the confirmationui HAL is available.
- * @deprecated Android Protected Confirmation had a low adoption rate among Android device
- * makers and developers alike. Given the lack of devices supporting the
- * feature, it is deprecated. Developers can use auth-bound Keystore keys
- * as a partial replacement.
*
* @return whether the confirmationUI HAL is available.
*/
- @Deprecated
public boolean isConfirmationPromptSupported() {
try {
return getService().isSupported();
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 1fbaeea..29936cc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -33,7 +33,9 @@
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT;
import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP;
-import android.annotation.DimenRes;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
@@ -53,9 +55,11 @@
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.window.InputTransferToken;
@@ -97,6 +101,16 @@
@VisibleForTesting
static final int DEFAULT_DIVIDER_WIDTH_DP = 24;
+ @VisibleForTesting
+ static final PathInterpolator FLING_ANIMATION_INTERPOLATOR =
+ new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ @VisibleForTesting
+ static final int FLING_ANIMATION_DURATION = 250;
+ @VisibleForTesting
+ static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+ @VisibleForTesting
+ static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+
private final int mTaskId;
@NonNull
@@ -109,6 +123,14 @@
private final Executor mCallbackExecutor;
/**
+ * The VelocityTracker of the divider, used to track the dragging velocity. This field is
+ * {@code null} until dragging starts.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ VelocityTracker mVelocityTracker;
+
+ /**
* 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.
@@ -370,13 +392,11 @@
applicationContext.getResources().getDisplayMetrics());
}
- private static int getDimensionDp(@DimenRes 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());
+ private static float getDisplayDensity() {
+ // TODO(b/329193115) support divider on secondary display
+ final Context applicationContext =
+ ActivityThread.currentActivityThread().getApplication();
+ return applicationContext.getResources().getDisplayMetrics().density;
}
/**
@@ -487,24 +507,27 @@
@Override
public boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {
synchronized (mLock) {
- final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
- mDividerPosition = calculateDividerPosition(
- event, taskBounds, mRenderer.mDividerWidthPx, mProperties.mDividerAttributes,
- mProperties.mIsVerticalSplit, calculateMinPosition(), calculateMaxPosition());
- mRenderer.setDividerPosition(mDividerPosition);
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- onStartDragging();
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- onFinishDragging();
- break;
- case MotionEvent.ACTION_MOVE:
- onDrag();
- break;
- default:
- break;
+ if (mProperties != null && mRenderer != null) {
+ final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+ mDividerPosition = calculateDividerPosition(
+ event, taskBounds, mRenderer.mDividerWidthPx,
+ mProperties.mDividerAttributes, mProperties.mIsVerticalSplit,
+ calculateMinPosition(), calculateMaxPosition());
+ mRenderer.setDividerPosition(mDividerPosition);
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ onStartDragging(event);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ onFinishDragging(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onDrag(event);
+ break;
+ default:
+ break;
+ }
}
}
@@ -514,7 +537,10 @@
}
@GuardedBy("mLock")
- private void onStartDragging() {
+ private void onStartDragging(@NonNull MotionEvent event) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(event);
+
mRenderer.mIsDragging = true;
mRenderer.mDragHandle.setPressed(mRenderer.mIsDragging);
mRenderer.updateSurface();
@@ -536,16 +562,81 @@
}
@GuardedBy("mLock")
- private void onDrag() {
+ private void onDrag(@NonNull MotionEvent event) {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ }
mRenderer.updateSurface();
}
@GuardedBy("mLock")
- private void onFinishDragging() {
- mDividerPosition = adjustDividerPositionForSnapPoints(mDividerPosition);
- mRenderer.setDividerPosition(mDividerPosition);
- mRenderer.updateSurface();
+ private void onFinishDragging(@NonNull MotionEvent event) {
+ float velocity = 0.0f;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ mVelocityTracker.computeCurrentVelocity(1000 /* units */);
+ velocity = mProperties.mIsVerticalSplit
+ ? mVelocityTracker.getXVelocity()
+ : mVelocityTracker.getYVelocity();
+ mVelocityTracker.recycle();
+ }
+ final int prevDividerPosition = mDividerPosition;
+ mDividerPosition = dividerPositionForSnapPoints(mDividerPosition, velocity);
+ if (mDividerPosition != prevDividerPosition) {
+ ValueAnimator animator = getFlingAnimator(prevDividerPosition, mDividerPosition);
+ animator.start();
+ } else {
+ onDraggingEnd();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ @VisibleForTesting
+ ValueAnimator getFlingAnimator(int prevDividerPosition, int snappedDividerPosition) {
+ final ValueAnimator animator =
+ getValueAnimator(prevDividerPosition, snappedDividerPosition);
+ animator.addUpdateListener(animation -> {
+ synchronized (mLock) {
+ updateDividerPosition((int) animation.getAnimatedValue());
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ synchronized (mLock) {
+ onDraggingEnd();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ synchronized (mLock) {
+ onDraggingEnd();
+ }
+ }
+ });
+ return animator;
+ }
+
+ @VisibleForTesting
+ static ValueAnimator getValueAnimator(int prevDividerPosition, int snappedDividerPosition) {
+ ValueAnimator animator = ValueAnimator
+ .ofInt(prevDividerPosition, snappedDividerPosition)
+ .setDuration(FLING_ANIMATION_DURATION);
+ animator.setInterpolator(FLING_ANIMATION_INTERPOLATOR);
+ return animator;
+ }
+
+ @GuardedBy("mLock")
+ private void updateDividerPosition(int position) {
+ mRenderer.setDividerPosition(position);
+ mRenderer.updateSurface();
+ }
+
+ @GuardedBy("mLock")
+ private void onDraggingEnd() {
// Veil visibility change should be applied together with the surface boost transaction in
// the wct.
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -570,38 +661,78 @@
/**
* Returns the divider position adjusted for the min max ratio and fullscreen expansion.
- *
- * If the dragging position is above the {@link DividerAttributes#getPrimaryMaxRatio()} or below
- * {@link DividerAttributes#getPrimaryMinRatio()} and
- * {@link DividerAttributes#isDraggingToFullscreenAllowed} is {@code true}, the system will
- * choose a snap algorithm to adjust the ending position to either fully expand one container or
- * move the divider back to the specified min/max ratio.
- *
- * TODO(b/327067596) implement snap algorithm
- *
* The adjusted divider position is in the range of [minPosition, maxPosition] for a split, 0
* for expanded right (bottom) container, or task width (height) minus the divider width for
* expanded left (top) container.
*/
@GuardedBy("mLock")
- private int adjustDividerPositionForSnapPoints(int dividerPosition) {
+ private int dividerPositionForSnapPoints(int dividerPosition, float velocity) {
final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
final int minPosition = calculateMinPosition();
final int maxPosition = calculateMaxPosition();
final int fullyExpandedPosition = mProperties.mIsVerticalSplit
? taskBounds.right - mRenderer.mDividerWidthPx
: taskBounds.bottom - mRenderer.mDividerWidthPx;
+
if (isDraggingToFullscreenAllowed(mProperties.mDividerAttributes)) {
- if (dividerPosition < minPosition) {
- return 0;
- }
- if (dividerPosition > maxPosition) {
- return fullyExpandedPosition;
- }
+ final float displayDensity = getDisplayDensity();
+ return dividerPositionWithDraggingToFullscreenAllowed(
+ dividerPosition,
+ minPosition,
+ maxPosition,
+ fullyExpandedPosition,
+ velocity,
+ displayDensity);
}
return Math.clamp(dividerPosition, minPosition, maxPosition);
}
+ /**
+ * Returns the divider position given a set of position options. A snap algorithm is used to
+ * adjust the ending position to either fully expand one container or move the divider back to
+ * the specified min/max ratio depending on the dragging velocity.
+ */
+ @VisibleForTesting
+ static int dividerPositionWithDraggingToFullscreenAllowed(int dividerPosition, int minPosition,
+ int maxPosition, int fullyExpandedPosition, float velocity, float displayDensity) {
+ final float minDismissVelocityPxPerSecond =
+ MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity;
+ final float minFlingVelocityPxPerSecond =
+ MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity;
+ if (dividerPosition < minPosition && velocity < -minDismissVelocityPxPerSecond) {
+ return 0;
+ }
+ if (dividerPosition > maxPosition && velocity > minDismissVelocityPxPerSecond) {
+ return fullyExpandedPosition;
+ }
+ if (Math.abs(velocity) < minFlingVelocityPxPerSecond) {
+ if (dividerPosition >= minPosition && dividerPosition <= maxPosition) {
+ return dividerPosition;
+ }
+ int[] possiblePositions = {0, minPosition, maxPosition, fullyExpandedPosition};
+ return snap(dividerPosition, possiblePositions);
+ }
+ if (velocity < 0) {
+ return 0;
+ } else {
+ return fullyExpandedPosition;
+ }
+ }
+
+ /** Calculates the snapped divider position based on the possible positions and distance. */
+ private static int snap(int dividerPosition, int[] possiblePositions) {
+ int snappedPosition = dividerPosition;
+ float minDistance = Float.MAX_VALUE;
+ for (int position : possiblePositions) {
+ float distance = Math.abs(dividerPosition - position);
+ if (distance < minDistance) {
+ snappedPosition = position;
+ minDistance = distance;
+ }
+ }
+ return snappedPosition;
+ }
+
private static void setDecorSurfaceBoosted(
@NonNull WindowContainerTransaction wct,
@Nullable IBinder decorSurfaceOwner,
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 13c2d1f..b764b6e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -50,6 +50,7 @@
import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;
+import static androidx.window.extensions.embedding.TaskFragmentContainer.OverlayContainerRestoreParams;
import android.annotation.CallbackExecutor;
import android.app.Activity;
@@ -133,6 +134,13 @@
private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
/**
+ * Stores the token of the associated Activity that maps to the
+ * {@link OverlayContainerRestoreParams} of the most recent created overlay container.
+ */
+ @GuardedBy("mLock")
+ final ArrayMap<IBinder, OverlayContainerRestoreParams> mOverlayRestoreParams = new ArrayMap<>();
+
+ /**
* A developer-defined {@link SplitAttributes} calculator to compute the current
* {@link SplitAttributes} with the current device and window states.
* It is registered via {@link #setSplitAttributesCalculator(Function)}
@@ -686,11 +694,20 @@
exception);
break;
case TYPE_ACTIVITY_REPARENTED_TO_TASK:
+ final IBinder candidateAssociatedActToken, lastOverlayToken;
+ if (Flags.fixPipRestoreToOverlay()) {
+ candidateAssociatedActToken = change.getOtherActivityToken();
+ lastOverlayToken = change.getTaskFragmentToken();
+ } else {
+ candidateAssociatedActToken = lastOverlayToken = null;
+ }
onActivityReparentedToTask(
wct,
taskId,
change.getActivityIntent(),
- change.getActivityToken());
+ change.getActivityToken(),
+ candidateAssociatedActToken,
+ lastOverlayToken);
break;
default:
throw new IllegalArgumentException(
@@ -917,11 +934,28 @@
* different process, the server will generate a temporary token that
* the organizer can use to reparent the activity through
* {@link WindowContainerTransaction} if needed.
+ * @param candidateAssociatedActToken The token of the candidate associated-activity.
+ * @param lastOverlayToken The last parent overlay container token.
*/
@VisibleForTesting
@GuardedBy("mLock")
void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
- int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {
+ int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken,
+ @Nullable IBinder candidateAssociatedActToken, @Nullable IBinder lastOverlayToken) {
+ // Reparent the activity to an overlay container if needed.
+ final OverlayContainerRestoreParams params = getOverlayContainerRestoreParams(
+ candidateAssociatedActToken, lastOverlayToken);
+ if (params != null) {
+ final Activity associatedActivity = getActivity(candidateAssociatedActToken);
+ final TaskFragmentContainer targetContainer = createOrUpdateOverlayTaskFragmentIfNeeded(
+ wct, params.mOptions, params.mIntent, associatedActivity);
+ if (targetContainer != null) {
+ wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
+ activityToken);
+ return;
+ }
+ }
+
// If the activity belongs to the current app process, we treat it as a new activity
// launch.
final Activity activity = getActivity(activityToken);
@@ -966,6 +1000,43 @@
}
/**
+ * Returns the {@link OverlayContainerRestoreParams} that stored last time the {@code
+ * associatedActivityToken} associated with and only if data matches the {@code overlayToken}.
+ * Otherwise, return {@code null}.
+ */
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ @Nullable
+ OverlayContainerRestoreParams getOverlayContainerRestoreParams(
+ @Nullable IBinder associatedActivityToken, @Nullable IBinder overlayToken) {
+ if (!Flags.fixPipRestoreToOverlay()) {
+ return null;
+ }
+
+ if (associatedActivityToken == null || overlayToken == null) {
+ return null;
+ }
+
+ final TaskFragmentContainer.OverlayContainerRestoreParams params =
+ mOverlayRestoreParams.get(associatedActivityToken);
+ if (params == null) {
+ return null;
+ }
+
+ if (params.mOverlayToken != overlayToken) {
+ // Not the same overlay container, no need to restore.
+ return null;
+ }
+
+ final Activity associatedActivity = getActivity(associatedActivityToken);
+ if (associatedActivity == null || associatedActivity.isFinishing()) {
+ return null;
+ }
+
+ return params;
+ }
+
+ /**
* Called when the {@link WindowContainerTransaction} created with
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
*
@@ -1433,6 +1504,8 @@
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
mTaskContainers.valueAt(i).onFinishingActivityPaused(wct, activityToken);
}
+
+ mOverlayRestoreParams.remove(activity.getActivityToken());
updateCallbackIfNecessary();
}
@@ -1450,6 +1523,8 @@
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
mTaskContainers.valueAt(i).onActivityDestroyed(wct, activityToken);
}
+
+ mOverlayRestoreParams.remove(activity.getActivityToken());
// We didn't trigger the callback if there were any pending appeared activities, so check
// again after the pending is removed.
updateCallbackIfNecessary();
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 4825543..d0b6a01 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -36,6 +36,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import java.util.ArrayList;
import java.util.Collections;
@@ -274,6 +275,15 @@
addPendingAppearedActivity(pendingAppearedActivity);
}
mPendingAppearedIntent = pendingAppearedIntent;
+
+ // Save the information necessary for restoring the overlay when needed.
+ if (Flags.fixPipRestoreToOverlay() && overlayTag != null && pendingAppearedIntent != null
+ && associatedActivity != null && !associatedActivity.isFinishing()) {
+ final IBinder associatedActivityToken = associatedActivity.getActivityToken();
+ final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(mToken,
+ launchOptions, pendingAppearedIntent);
+ mController.mOverlayRestoreParams.put(associatedActivityToken, params);
+ }
}
/**
@@ -1105,4 +1115,25 @@
}
return sb.append("]").toString();
}
+
+ static class OverlayContainerRestoreParams {
+ /** The token of the overlay container */
+ @NonNull
+ final IBinder mOverlayToken;
+
+ /** The launch options to create this container. */
+ @NonNull
+ final Bundle mOptions;
+
+ /** The Intent that used to be started in the overlay container. */
+ @NonNull
+ final Intent mIntent;
+
+ OverlayContainerRestoreParams(@NonNull IBinder overlayToken, @NonNull Bundle options,
+ @NonNull Intent intent) {
+ mOverlayToken = overlayToken;
+ mOptions = options;
+ mIntent = intent;
+ }
+ }
}
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 b0a45e2..746607c 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
@@ -19,6 +19,10 @@
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.FLING_ANIMATION_DURATION;
+import static androidx.window.extensions.embedding.DividerPresenter.FLING_ANIMATION_INTERPOLATOR;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_DISMISS_VELOCITY_DP_PER_SECOND;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_FLING_VELOCITY_DP_PER_SECOND;
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;
@@ -35,6 +39,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -637,6 +642,105 @@
DividerPresenter.getContainerBackgroundColor(container, defaultColor));
}
+ @Test
+ public void testGetValueAnimator() {
+ ValueAnimator animator =
+ DividerPresenter.getValueAnimator(
+ 375 /* prevDividerPosition */,
+ 500 /* snappedDividerPosition */);
+
+ assertEquals(animator.getDuration(), FLING_ANIMATION_DURATION);
+ assertEquals(animator.getInterpolator(), FLING_ANIMATION_INTERPOLATOR);
+ }
+
+ @Test
+ public void testDividerPositionWithDraggingToFullscreenAllowed() {
+ final float displayDensity = 600F;
+ final float dismissVelocity = MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+ final float nonFlingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity - 10f;
+ final float flingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+
+ // Divider position is less than minPosition and the velocity is enough to be dismissed
+ assertEquals(
+ 0, // Closed position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 10 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ -dismissVelocity,
+ displayDensity));
+
+ // Divider position is greater than maxPosition and the velocity is enough to be dismissed
+ assertEquals(
+ 1200, // Fully expanded position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 1000 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ dismissVelocity,
+ displayDensity));
+
+ // Divider position is returned when the velocity is not fast enough for fling and is in
+ // between minPosition and maxPosition
+ assertEquals(
+ 500, // dividerPosition is not snapped
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 500 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is snapped when the velocity is not fast enough for fling and larger
+ // than maxPosition
+ assertEquals(
+ 900, // Closest position is maxPosition
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 950 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is snapped when the velocity is not fast enough for fling and smaller
+ // than minPosition
+ assertEquals(
+ 30, // Closest position is minPosition
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 20 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ nonFlingVelocity,
+ displayDensity));
+
+ // Divider position is greater than minPosition and the velocity is enough for fling
+ assertEquals(
+ 0, // Closed position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 50 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ -flingVelocity,
+ displayDensity));
+
+ // Divider position is less than maxPosition and the velocity is enough for fling
+ assertEquals(
+ 1200, // Fully expanded position
+ DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+ 800 /* dividerPosition */,
+ 30 /* minPosition */,
+ 900 /* maxPosition */,
+ 1200 /* fullyExpandedPosition */,
+ flingVelocity,
+ displayDensity));
+ }
+
private TaskFragmentContainer createMockTaskFragmentContainer(
@NonNull IBinder token, @NonNull Rect bounds) {
final TaskFragmentContainer container = mock(TaskFragmentContainer.class);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 9ebcb759..f322257 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -836,6 +836,30 @@
any());
}
+ @Test
+ public void testOnActivityReparentedToTask_overlayRestoration() {
+ mSetFlagRule.enableFlags(Flags.FLAG_FIX_PIP_RESTORE_TO_OVERLAY);
+
+ // Prepares and mock the data necessary for the test.
+ final IBinder activityToken = mActivity.getActivityToken();
+ final Intent intent = new Intent();
+ final IBinder fillTaskActivityToken = new Binder();
+ final IBinder lastOverlayToken = new Binder();
+ final TaskFragmentContainer overlayContainer = mSplitController.newContainer(intent,
+ mActivity, TASK_ID);
+ final TaskFragmentContainer.OverlayContainerRestoreParams params = mock(
+ TaskFragmentContainer.OverlayContainerRestoreParams.class);
+ doReturn(params).when(mSplitController).getOverlayContainerRestoreParams(any(), any());
+ doReturn(overlayContainer).when(mSplitController).createOrUpdateOverlayTaskFragmentIfNeeded(
+ any(), any(), any(), any());
+
+ // Verify the activity should be reparented to the overlay container.
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+ fillTaskActivityToken, lastOverlayToken);
+ verify(mTransaction).reparentActivityToTaskFragment(
+ eq(overlayContainer.getTaskFragmentToken()), eq(activityToken));
+ }
+
/**
* A simplified version of {@link SplitController#createOrUpdateOverlayTaskFragmentIfNeeded}
*/
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 7d86ec2..35353db 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
@@ -397,7 +397,8 @@
@Test
public void testOnActivityReparentedToTask_sameProcess() {
mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, new Intent(),
- mActivity.getActivityToken());
+ mActivity.getActivityToken(), null /* fillTaskActivityToken */,
+ null /* lastOverlayToken */);
// Treated as on activity created, but allow to split as primary.
verify(mSplitController).resolveActivityToContainer(mTransaction,
@@ -413,7 +414,8 @@
final IBinder activityToken = new Binder();
final Intent intent = new Intent();
- mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken);
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+ null /* fillTaskActivityToken */, null /* lastOverlayToken */);
// Treated as starting new intent
verify(mSplitController, never()).resolveActivityToContainer(any(), any(), anyBoolean());
@@ -1210,7 +1212,7 @@
mSplitController.onTransactionReady(transaction);
verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
- eq(activityToken));
+ eq(activityToken), any(), any());
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
anyInt(), anyBoolean());
}
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 8977d5c..67f1650 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -78,3 +78,17 @@
description: "Allow opening bubbles overflow UI without bubbles being visible"
bug: "340337839"
}
+
+flag {
+ name: "enable_bubble_stashing"
+ namespace: "multitasking"
+ description: "Allow the floating bubble stack to stash on the edge of the screen"
+ bug: "341361249"
+}
+
+flag {
+ name: "enable_tiny_taskbar"
+ namespace: "multitasking"
+ description: "Enables Taskbar on phones"
+ bug: "341784466"
+}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
index 8487e379..9e1440d 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
@@ -218,11 +218,10 @@
insets = Insets.of(10, 20, 5, 15),
windowBounds = Rect(0, 0, 1800, 2600)
)
- val bubbleBarBounds = Rect(1700, 2500, 1780, 2600)
positioner.setShowingInBubbleBar(true)
positioner.update(deviceConfig)
- positioner.bubbleBarBounds = bubbleBarBounds
+ positioner.bubbleBarTopOnScreen = 2500
val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680
val expandedViewVerticalSpacing =
@@ -246,10 +245,9 @@
insets = Insets.of(10, 20, 5, 15),
windowBounds = Rect(0, 0, screenWidth, 2600)
)
- val bubbleBarBounds = Rect(100, 2500, 280, 2550)
positioner.setShowingInBubbleBar(true)
positioner.update(deviceConfig)
- positioner.bubbleBarBounds = bubbleBarBounds
+ positioner.bubbleBarTopOnScreen = 2500
val spaceBetweenTopInsetAndBubbleBarInLandscape = 180
val expandedViewSpacing =
@@ -597,16 +595,19 @@
private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) {
positioner.setShowingInBubbleBar(true)
+ val windowBounds = Rect(0, 0, 2000, 2600)
+ val insets = Insets.of(10, 20, 5, 15)
val deviceConfig =
defaultDeviceConfig.copy(
isLargeScreen = true,
isLandscape = true,
- insets = Insets.of(10, 20, 5, 15),
- windowBounds = Rect(0, 0, 2000, 2600)
+ insets = insets,
+ windowBounds = windowBounds
)
positioner.update(deviceConfig)
- positioner.bubbleBarBounds = getBubbleBarBounds(onLeft, deviceConfig)
+ val bubbleBarHeight = 100
+ positioner.bubbleBarTopOnScreen = windowBounds.bottom - insets.bottom - bubbleBarHeight
val expandedViewPadding =
context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding)
@@ -624,7 +625,7 @@
left = right - positioner.getExpandedViewWidthForBubbleBar(isOverflow)
}
// Above the bubble bar
- val bottom = positioner.bubbleBarBounds.top - expandedViewPadding
+ val bottom = positioner.bubbleBarTopOnScreen - expandedViewPadding
// Calculate right and top based on size
val top = bottom - positioner.getExpandedViewHeightForBubbleBar(isOverflow)
val expectedBounds = Rect(left, top, right, bottom)
@@ -666,21 +667,4 @@
positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent
}
-
- private fun getBubbleBarBounds(onLeft: Boolean, deviceConfig: DeviceConfig): Rect {
- val width = 200
- val height = 100
- val bottom = deviceConfig.windowBounds.bottom - deviceConfig.insets.bottom
- val top = bottom - height
- val left: Int
- val right: Int
- if (onLeft) {
- left = deviceConfig.insets.left
- right = left + width
- } else {
- right = deviceConfig.windowBounds.right - deviceConfig.insets.right
- left = right - width
- }
- return Rect(left, top, right, bottom)
- }
}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
index 0764141..12d1927 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
@@ -53,7 +53,6 @@
const val SCREEN_WIDTH = 2000
const val SCREEN_HEIGHT = 1000
- const val BUBBLE_BAR_WIDTH = 100
const val BUBBLE_BAR_HEIGHT = 50
}
@@ -84,14 +83,8 @@
insets = Insets.of(10, 20, 30, 40)
)
positioner.update(deviceConfig)
- positioner.bubbleBarBounds =
- Rect(
- SCREEN_WIDTH - deviceConfig.insets.right - BUBBLE_BAR_WIDTH,
- SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT,
- SCREEN_WIDTH - deviceConfig.insets.right,
- SCREEN_HEIGHT - deviceConfig.insets.bottom
- )
-
+ positioner.bubbleBarTopOnScreen =
+ SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT
controller = BubbleExpandedViewPinController(context, container, positioner)
testListener = TestLocationChangeListener()
controller.setListener(testListener)
@@ -247,9 +240,10 @@
private val dropTargetView: View?
get() = container.findViewById(R.id.bubble_bar_drop_target)
- private fun getExpectedDropTargetBounds(onLeft: Boolean): Rect = Rect().also {
- positioner.getBubbleBarExpandedViewBounds(onLeft, false /* isOveflowExpanded */, it)
- }
+ private fun getExpectedDropTargetBounds(onLeft: Boolean): Rect =
+ Rect().also {
+ positioner.getBubbleBarExpandedViewBounds(onLeft, false /* isOveflowExpanded */, it)
+ }
private fun runOnMainSync(runnable: Runnable) {
InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable)
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_header_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_background.xml
new file mode 100644
index 0000000..50c5ca9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_background.xml
@@ -0,0 +1,28 @@
+<?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.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/backLayer">
+ <shape android:shape="rectangle">
+ <solid android:color="#000000" />
+ </shape>
+ </item>
+
+ <item android:id="@+id/frontLayer">
+ <shape android:shape="rectangle">
+ <solid android:color="#000000" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index fa18e2b..4d06dd3 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -19,6 +19,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/desktop_mode_caption"
+ android:background="@drawable/desktop_mode_header_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
@@ -96,7 +97,6 @@
android:paddingHorizontal="10dp"
android:paddingVertical="8dp"
android:layout_marginEnd="8dp"
- android:tint="?androidprv:attr/materialColorOnSurface"
android:background="?android:selectableItemBackgroundBorderless"
android:contentDescription="@string/close_button_text"
android:src="@drawable/desktop_mode_header_ic_close"
diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
index 296c8956..77507a4 100644
--- a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
+++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
@@ -31,8 +31,6 @@
android:layout_height="34dp"
android:padding="5dp"
android:contentDescription="@string/maximize_button_text"
- android:tint="?androidprv:attr/materialColorOnSurface"
- android:background="?android:selectableItemBackgroundBorderless"
android:src="@drawable/decor_desktop_mode_maximize_button_dark"
android:scaleType="fitCenter" />
</merge>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 8d24c16..aa4fb44 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -247,13 +247,11 @@
<!-- Padding for the bubble popup view contents. -->
<dimen name="bubble_popup_padding">24dp</dimen>
<!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
- <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
+ <dimen name="bubble_bar_expanded_view_caption_height">36dp</dimen>
<!-- The width of the caption bar at the top of bubble bar expanded view. -->
- <dimen name="bubble_bar_expanded_view_caption_width">128dp</dimen>
- <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
- <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>
- <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->
- <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen>
+ <dimen name="bubble_bar_expanded_view_caption_width">80dp</dimen>
+ <!-- The height of the handle shown for the caption menu in the bubble bar expanded view. -->
+ <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>
<!-- Width of the expanded bubble bar view shown when the bubble is expanded. -->
<dimen name="bubble_bar_expanded_view_width">412dp</dimen>
<!-- Minimum width of the bubble bar manage menu. -->
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
index bdd89c0..8d8655a 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
@@ -67,6 +67,16 @@
private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
"persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
+ /** Override density for tasks when they're inside the desktop. */
+ public static final int DESKTOP_DENSITY_OVERRIDE =
+ SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284);
+
+ /** The minimum override density allowed for tasks inside the desktop. */
+ private static final int DESKTOP_DENSITY_MIN = 100;
+
+ /** The maximum override density allowed for tasks inside the desktop. */
+ private static final int DESKTOP_DENSITY_MAX = 1000;
+
/**
* Default value for {@code MAX_TASK_LIMIT}.
*/
@@ -145,4 +155,12 @@
public static boolean canEnterDesktopMode(@NonNull Context context) {
return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled();
}
+
+ /**
+ * Return {@code true} if the override desktop density is set.
+ */
+ public static boolean isDesktopDensityOverrideSet() {
+ return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN
+ && DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX;
+ }
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
index 785e30d..6ca6517 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
@@ -322,7 +322,7 @@
null,
new Rect(change.getStartAbsBounds()),
taskInfo,
- change.getAllowEnterPip(),
+ change.isAllowEnterPip(),
INVALID_WINDOW_TYPE
);
target.setWillShowImeOnTarget(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index c988c2f..7c0837e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -41,6 +41,9 @@
import android.window.BackNavigationInfo
import android.window.BackProgressAnimator
import android.window.IOnBackInvokedCallback
+import com.android.internal.dynamicanimation.animation.FloatValueHolder
+import com.android.internal.dynamicanimation.animation.SpringAnimation
+import com.android.internal.dynamicanimation.animation.SpringForce
import com.android.internal.jank.Cuj
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.protolog.common.ProtoLog
@@ -70,6 +73,7 @@
protected val backAnimRect = Rect()
private val cropRect = Rect()
+ private val tempRectF = RectF()
private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
@@ -83,7 +87,7 @@
private var triggerBack = false
private var finishCallback: IRemoteAnimationFinishedCallback? = null
private val progressAnimator = BackProgressAnimator()
- private val displayBoundsMargin =
+ protected val displayBoundsMargin =
context.resources.getDimension(R.dimen.cross_task_back_vertical_margin)
private val gestureInterpolator = Interpolators.BACK_GESTURE
@@ -98,6 +102,12 @@
private var rightLetterboxLayer: SurfaceControl? = null
private var letterboxColor: Int = 0
+ private val postCommitFlingScale = FloatValueHolder(SPRING_SCALE)
+ private var lastPostCommitFlingScale = SPRING_SCALE
+ private val postCommitFlingSpring = SpringForce(SPRING_SCALE)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+
/** Background color to be used during the animation, also see [getBackgroundColor] */
protected var customizedBackgroundColor = 0
@@ -107,6 +117,12 @@
abstract val allowEnteringYShift: Boolean
/**
+ * Subclasses must set the [startClosingRect] and [targetClosingRect] to define the movement
+ * of the closingTarget during pre-commit phase.
+ */
+ abstract fun preparePreCommitClosingRectMovement(@BackEvent.SwipeEdge swipeEdge: Int)
+
+ /**
* Subclasses must set the [startEnteringRect] and [targetEnteringRect] to define the movement
* of the enteringTarget during pre-commit phase.
*/
@@ -160,18 +176,7 @@
// Offset start rectangle to align task bounds.
backAnimRect.offsetTo(0, 0)
- startClosingRect.set(backAnimRect)
-
- // scale closing target into the middle for rhs and to the right for lhs
- targetClosingRect.set(startClosingRect)
- targetClosingRect.scaleCentered(MAX_SCALE)
- if (backMotionEvent.swipeEdge != BackEvent.EDGE_RIGHT) {
- targetClosingRect.offset(
- startClosingRect.right - targetClosingRect.right - displayBoundsMargin,
- 0f
- )
- }
-
+ preparePreCommitClosingRectMovement(backMotionEvent.swipeEdge)
preparePreCommitEnteringRectMovement()
background.ensureBackground(
@@ -231,7 +236,7 @@
return deltaY
}
- protected open fun onGestureCommitted() {
+ protected open fun onGestureCommitted(velocity: Float) {
if (
closingTarget?.leash == null ||
enteringTarget?.leash == null ||
@@ -242,6 +247,14 @@
return
}
+ // kick off spring animation with the current velocity from the pre-commit phase, this
+ // affects the scaling of the closing activity during post-commit
+ val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE)
+ .setStartVelocity(min(0f, -velocity * SPRING_SCALE))
+ .setStartValue(SPRING_SCALE)
+ .setSpring(postCommitFlingSpring)
+ flingAnimation.start()
+
val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION)
valueAnimator.addUpdateListener { animation: ValueAnimator ->
val progress = animation.animatedFraction
@@ -291,6 +304,7 @@
removeLetterbox()
isLetterboxed = false
enteringHasSameLetterbox = false
+ lastPostCommitFlingScale = SPRING_SCALE
}
protected fun applyTransform(
@@ -300,7 +314,15 @@
baseTransformation: Transformation? = null
) {
if (leash == null || !leash.isValid) return
- val scale = rect.width() / backAnimRect.width()
+ tempRectF.set(rect)
+ if (leash == closingTarget?.leash) {
+ lastPostCommitFlingScale = (postCommitFlingScale.value / SPRING_SCALE).coerceIn(
+ minimumValue = MAX_FLING_SCALE, maximumValue = lastPostCommitFlingScale
+ )
+ // apply an additional scale to the closing target to account for fling velocity
+ tempRectF.scaleCentered(lastPostCommitFlingScale)
+ }
+ val scale = tempRectF.width() / backAnimRect.width()
val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() }
val scalePivotX =
if (isLetterboxed && enteringHasSameLetterbox) {
@@ -309,7 +331,7 @@
0f
}
matrix.postScale(scale, scale, scalePivotX, 0f)
- matrix.postTranslate(rect.left, rect.top)
+ matrix.postTranslate(tempRectF.left, tempRectF.top)
transaction
.setAlpha(leash, keepMinimumAlpha(alpha))
.setMatrix(leash, matrix, tmpFloat9)
@@ -461,7 +483,7 @@
override fun onBackInvoked() {
progressAnimator.reset()
- onGestureCommitted()
+ onGestureCommitted(progressAnimator.velocity)
}
}
@@ -497,6 +519,8 @@
private const val MAX_SCRIM_ALPHA_DARK = 0.8f
private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f
private const val POST_COMMIT_DURATION = 300L
+ private const val SPRING_SCALE = 100f
+ private const val MAX_FLING_SCALE = 0.6f
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
index e6ec2b4..ab359bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -23,6 +23,7 @@
import android.view.SurfaceControl
import android.view.animation.Animation
import android.view.animation.Transformation
+import android.window.BackEvent
import android.window.BackMotionEvent
import android.window.BackNavigationInfo
import com.android.internal.R
@@ -74,6 +75,21 @@
)
)
+ override fun preparePreCommitClosingRectMovement(swipeEdge: Int) {
+ startClosingRect.set(backAnimRect)
+
+ // scale closing target to the left for right-hand-swipe and to the right for
+ // left-hand-swipe
+ targetClosingRect.set(startClosingRect)
+ targetClosingRect.scaleCentered(MAX_SCALE)
+ val offset = if (swipeEdge != BackEvent.EDGE_RIGHT) {
+ startClosingRect.right - targetClosingRect.right - displayBoundsMargin
+ } else {
+ -targetClosingRect.left + displayBoundsMargin
+ }
+ targetClosingRect.offset(offset, 0f)
+ }
+
override fun preparePreCommitEnteringRectMovement() {
// No movement for the entering rect
startEnteringRect.set(startClosingRect)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
index f33c5b9..9f07e5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.view.Choreographer
import android.view.SurfaceControl
+import android.window.BackEvent
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.Interpolators
@@ -47,6 +48,20 @@
context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
override val allowEnteringYShift = true
+ override fun preparePreCommitClosingRectMovement(swipeEdge: Int) {
+ startClosingRect.set(backAnimRect)
+
+ // scale closing target into the middle for rhs and to the right for lhs
+ targetClosingRect.set(startClosingRect)
+ targetClosingRect.scaleCentered(MAX_SCALE)
+ if (swipeEdge != BackEvent.EDGE_RIGHT) {
+ targetClosingRect.offset(
+ startClosingRect.right - targetClosingRect.right - displayBoundsMargin,
+ 0f
+ )
+ }
+ }
+
override fun preparePreCommitEnteringRectMovement() {
// the entering target starts 96dp to the left of the screen edge...
startEnteringRect.set(startClosingRect)
@@ -56,7 +71,7 @@
targetEnteringRect.scaleCentered(MAX_SCALE)
}
- override fun onGestureCommitted() {
+ override fun onGestureCommitted(velocity: Float) {
// We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
// coordinate of the gesture driven phase. Let's update the start and target rects and kick
// off the animator in the superclass
@@ -65,7 +80,7 @@
targetEnteringRect.set(backAnimRect)
targetClosingRect.set(backAnimRect)
targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
- super.onGestureCommitted()
+ super.onGestureCommitted(velocity)
}
override fun onPostCommitProgress(linearProgress: Float) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 38c3443..42a4ab2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1189,10 +1189,12 @@
* A bubble is no longer being dragged in Launcher. And was released in given location.
* Will be called only when bubble bar is expanded.
*
- * @param location location where bubble was released
+ * @param location location where bubble was released
+ * @param topOnScreen top coordinate of the bubble bar on the screen after release
*/
- public void stopBubbleDrag(BubbleBarLocation location) {
+ public void stopBubbleDrag(BubbleBarLocation location, int topOnScreen) {
mBubblePositioner.setBubbleBarLocation(location);
+ mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
if (mBubbleData.getSelectedBubble() != null) {
mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ true);
}
@@ -1248,8 +1250,8 @@
* <p>This is used by external callers (launcher).
*/
@VisibleForTesting
- public void expandStackAndSelectBubbleFromLauncher(String key, Rect bubbleBarBounds) {
- mBubblePositioner.setBubbleBarBounds(bubbleBarBounds);
+ public void expandStackAndSelectBubbleFromLauncher(String key, int topOnScreen) {
+ mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
if (BubbleOverflow.KEY.equals(key)) {
mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
@@ -2364,10 +2366,9 @@
}
@Override
- public void showBubble(String key, Rect bubbleBarBounds) {
+ public void showBubble(String key, int topOnScreen) {
mMainExecutor.execute(
- () -> mController.expandStackAndSelectBubbleFromLauncher(
- key, bubbleBarBounds));
+ () -> mController.expandStackAndSelectBubbleFromLauncher(key, topOnScreen));
}
@Override
@@ -2386,8 +2387,8 @@
}
@Override
- public void stopBubbleDrag(BubbleBarLocation location) {
- mMainExecutor.execute(() -> mController.stopBubbleDrag(location));
+ public void stopBubbleDrag(BubbleBarLocation location, int topOnScreen) {
+ mMainExecutor.execute(() -> mController.stopBubbleDrag(location, topOnScreen));
}
@Override
@@ -2408,9 +2409,9 @@
}
@Override
- public void setBubbleBarBounds(Rect bubbleBarBounds) {
+ public void updateBubbleBarTopOnScreen(int topOnScreen) {
mMainExecutor.execute(() -> {
- mBubblePositioner.setBubbleBarBounds(bubbleBarBounds);
+ mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
if (mLayerView != null) mLayerView.updateExpandedView();
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index a35a004..1e482ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -98,7 +98,7 @@
private boolean mShowingInBubbleBar;
private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
- private final Rect mBubbleBarBounds = new Rect();
+ private int mBubbleBarTopOnScreen;
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
@@ -846,17 +846,17 @@
}
/**
- * Sets the position of the bubble bar in display coordinates.
+ * Set top coordinate of bubble bar on screen
*/
- public void setBubbleBarBounds(Rect bubbleBarBounds) {
- mBubbleBarBounds.set(bubbleBarBounds);
+ public void setBubbleBarTopOnScreen(int topOnScreen) {
+ mBubbleBarTopOnScreen = topOnScreen;
}
/**
- * Returns the display coordinates of the bubble bar.
+ * Returns the top coordinate of bubble bar on screen
*/
- public Rect getBubbleBarBounds() {
- return mBubbleBarBounds;
+ public int getBubbleBarTopOnScreen() {
+ return mBubbleBarTopOnScreen;
}
/**
@@ -908,7 +908,7 @@
/** The bottom position of the expanded view when showing above the bubble bar. */
public int getExpandedViewBottomForBubbleBar() {
- return mBubbleBarBounds.top - mExpandedViewPadding;
+ return mBubbleBarTopOnScreen - mExpandedViewPadding;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 1eff149..1db556c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -31,7 +31,7 @@
oneway void unregisterBubbleListener(in IBubblesListener listener) = 2;
- oneway void showBubble(in String key, in Rect bubbleBarBounds) = 3;
+ oneway void showBubble(in String key, in int topOnScreen) = 3;
oneway void dragBubbleToDismiss(in String key) = 4;
@@ -45,7 +45,7 @@
oneway void setBubbleBarLocation(in BubbleBarLocation location) = 9;
- oneway void setBubbleBarBounds(in Rect bubbleBarBounds) = 10;
+ oneway void updateBubbleBarTopOnScreen(in int topOnScreen) = 10;
- oneway void stopBubbleDrag(in BubbleBarLocation location) = 11;
+ oneway void stopBubbleDrag(in BubbleBarLocation location, in int topOnScreen) = 11;
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 45ad631..8e58db1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -237,12 +237,10 @@
private void setScaleFromBubbleBar(AnimatableScaleMatrix matrix, float scale) {
// Set the pivot point for the scale, so the view animates out from the bubble bar.
- Rect bubbleBarBounds = mPositioner.getBubbleBarBounds();
- matrix.setScale(
- scale,
- scale,
- bubbleBarBounds.centerX(),
- bubbleBarBounds.top);
+ Rect availableRect = mPositioner.getAvailableRect();
+ float pivotX = mPositioner.isBubbleBarOnLeft() ? availableRect.left : availableRect.right;
+ float pivotY = mPositioner.getBubbleBarTopOnScreen();
+ matrix.setScale(scale, scale, pivotX, pivotY);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
index 2b7a070..d54a6b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -37,15 +37,11 @@
*/
public class BubbleBarHandleView extends View {
private static final long COLOR_CHANGE_DURATION = 120;
-
- // The handle view is currently rendered as 3 evenly spaced dots.
- private int mDotSize;
- private int mDotSpacing;
// Path used to draw the dots
private final Path mPath = new Path();
- private @ColorInt int mHandleLightColor;
- private @ColorInt int mHandleDarkColor;
+ private final @ColorInt int mHandleLightColor;
+ private final @ColorInt int mHandleDarkColor;
private @Nullable ObjectAnimator mColorChangeAnim;
public BubbleBarHandleView(Context context) {
@@ -63,10 +59,8 @@
public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mDotSize = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_caption_dot_size);
- mDotSpacing = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_caption_dot_spacing);
+ final int handleHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_height);
mHandleLightColor = ContextCompat.getColor(getContext(),
R.color.bubble_bar_expanded_view_handle_light);
mHandleDarkColor = ContextCompat.getColor(getContext(),
@@ -76,27 +70,13 @@
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- final int handleCenterX = view.getWidth() / 2;
final int handleCenterY = view.getHeight() / 2;
- final int handleTotalWidth = mDotSize * 3 + mDotSpacing * 2;
- final int handleLeft = handleCenterX - handleTotalWidth / 2;
- final int handleTop = handleCenterY - mDotSize / 2;
- final int handleBottom = handleTop + mDotSize;
- RectF dot1 = new RectF(
- handleLeft, handleTop,
- handleLeft + mDotSize, handleBottom);
- RectF dot2 = new RectF(
- dot1.right + mDotSpacing, handleTop,
- dot1.right + mDotSpacing + mDotSize, handleBottom
- );
- RectF dot3 = new RectF(
- dot2.right + mDotSpacing, handleTop,
- dot2.right + mDotSpacing + mDotSize, handleBottom
- );
+ final int handleTop = handleCenterY - handleHeight / 2;
+ final int handleBottom = handleTop + handleHeight;
+ final int radius = handleHeight / 2;
+ RectF handle = new RectF(/* left = */ 0, handleTop, view.getWidth(), handleBottom);
mPath.reset();
- mPath.addOval(dot1, Path.Direction.CW);
- mPath.addOval(dot2, Path.Direction.CW);
- mPath.addOval(dot3, Path.Direction.CW);
+ mPath.addRoundRect(handle, radius, radius, Path.Direction.CW);
outline.setPath(mPath);
}
});
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 da414cc..ef33b38 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
@@ -353,7 +353,7 @@
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {}
+ InsetsSourceControl.Array activeControls) {}
@Override
public void showInsets(int types, boolean fromIme, @Nullable ImeTracker.Token statsToken) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 607a3b5..2234041 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -347,7 +347,7 @@
if (mMoving) {
final int position = mSplitLayout.getDividerPosition() + touchPos - mStartPos;
mLastDraggingPosition = position;
- mSplitLayout.updateDividerBounds(position);
+ mSplitLayout.updateDividerBounds(position, true /* shouldUseParallaxEffect */);
}
break;
case MotionEvent.ACTION_UP:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 30eb8b5d..de016d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -31,7 +31,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -57,7 +56,13 @@
import java.util.function.Consumer;
/**
- * Handles split decor like showing resizing hint for a specific split.
+ * Handles additional layers over a running task in a split pair, for example showing a veil with an
+ * app icon when the task is being resized (usually to hide weird layouts while the app is being
+ * stretched). One SplitDecorManager is initialized on each window.
+ * <br>
+ * Currently, we show a veil when:
+ * a) Task is resizing down from a fullscreen window.
+ * b) Task is being stretched past its original bounds.
*/
public class SplitDecorManager extends WindowlessWindowManager {
private static final String TAG = SplitDecorManager.class.getSimpleName();
@@ -78,7 +83,11 @@
private boolean mShown;
private boolean mIsResizing;
- private final Rect mOldBounds = new Rect();
+ /** The original bounds of the main task, captured at the beginning of a resize transition. */
+ private final Rect mOldMainBounds = new Rect();
+ /** The original bounds of the side task, captured at the beginning of a resize transition. */
+ private final Rect mOldSideBounds = new Rect();
+ /** The current bounds of the main task, mid-resize. */
private final Rect mResizingBounds = new Rect();
private final Rect mTempRect = new Rect();
private ValueAnimator mFadeAnimator;
@@ -184,29 +193,38 @@
mResizingIconView = null;
mIsResizing = false;
mShown = false;
- mOldBounds.setEmpty();
+ mOldMainBounds.setEmpty();
+ mOldSideBounds.setEmpty();
mResizingBounds.setEmpty();
}
/** Showing resizing hint. */
public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
Rect sideBounds, SurfaceControl.Transaction t, int offsetX, int offsetY,
- boolean immediately) {
+ boolean immediately, float[] veilColor) {
if (mResizingIconView == null) {
return;
}
if (!mIsResizing) {
mIsResizing = true;
- mOldBounds.set(newBounds);
+ mOldMainBounds.set(newBounds);
+ mOldSideBounds.set(sideBounds);
}
mResizingBounds.set(newBounds);
mOffsetX = offsetX;
mOffsetY = offsetY;
- final boolean show =
- newBounds.width() > mOldBounds.width() || newBounds.height() > mOldBounds.height();
- final boolean update = show != mShown;
+ // Show a veil when:
+ // a) Task is resizing down from a fullscreen window.
+ // b) Task is being stretched past its original bounds.
+ final boolean isResizingDownFromFullscreen =
+ mOldSideBounds.width() <= 1 || mOldSideBounds.height() <= 1;
+ final boolean isStretchingPastOriginalBounds =
+ newBounds.width() > mOldMainBounds.width()
+ || newBounds.height() > mOldMainBounds.height();
+ final boolean showVeil = isResizingDownFromFullscreen || isStretchingPastOriginalBounds;
+ final boolean update = showVeil != mShown;
if (update && mFadeAnimator != null && mFadeAnimator.isRunning()) {
// If we need to animate and animator still running, cancel it before we ensure both
// background and icon surfaces are non null for next animation.
@@ -216,18 +234,18 @@
if (mBackgroundLeash == null) {
mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
- t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ t.setColor(mBackgroundLeash, veilColor)
.setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1);
}
if (mGapBackgroundLeash == null && !immediately) {
final boolean isLandscape = newBounds.height() == sideBounds.height();
- final int left = isLandscape ? mOldBounds.width() : 0;
- final int top = isLandscape ? 0 : mOldBounds.height();
+ final int left = isLandscape ? mOldMainBounds.width() : 0;
+ final int top = isLandscape ? 0 : mOldMainBounds.height();
mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession);
// Fill up another side bounds area.
- t.setColor(mGapBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ t.setColor(mGapBackgroundLeash, veilColor)
.setLayer(mGapBackgroundLeash, Integer.MAX_VALUE - 2)
.setPosition(mGapBackgroundLeash, left, top)
.setWindowCrop(mGapBackgroundLeash, sideBounds.width(), sideBounds.height());
@@ -251,12 +269,12 @@
if (update) {
if (immediately) {
- t.setVisibility(mBackgroundLeash, show);
- t.setVisibility(mIconLeash, show);
+ t.setVisibility(mBackgroundLeash, showVeil);
+ t.setVisibility(mIconLeash, showVeil);
} else {
- startFadeAnimation(show, false, null);
+ startFadeAnimation(showVeil, false, null);
}
- mShown = show;
+ mShown = showVeil;
}
}
@@ -309,7 +327,8 @@
mIsResizing = false;
mOffsetX = 0;
mOffsetY = 0;
- mOldBounds.setEmpty();
+ mOldMainBounds.setEmpty();
+ mOldSideBounds.setEmpty();
mResizingBounds.setEmpty();
if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
if (!mShown) {
@@ -346,14 +365,14 @@
/** Screenshot host leash and attach on it if meet some conditions */
public void screenshotIfNeeded(SurfaceControl.Transaction t) {
- if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+ if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
} else if (mScreenshot != null) {
t.remove(mScreenshot);
}
- mTempRect.set(mOldBounds);
+ mTempRect.set(mOldMainBounds);
mTempRect.offsetTo(0, 0);
mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
Integer.MAX_VALUE - 1);
@@ -364,7 +383,7 @@
public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
if (screenshot == null || !screenshot.isValid()) return;
- if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+ if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
} else if (mScreenshot != null) {
@@ -465,9 +484,4 @@
mIcon = null;
}
}
-
- private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
- return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents();
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 2ea32f4..8ced76f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -496,10 +496,10 @@
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
*/
- void updateDividerBounds(int position) {
+ void updateDividerBounds(int position, boolean shouldUseParallaxEffect) {
updateBounds(position);
mSplitLayoutHandler.onLayoutSizeChanging(this, mSurfaceEffectPolicy.mParallaxOffset.x,
- mSurfaceEffectPolicy.mParallaxOffset.y);
+ mSurfaceEffectPolicy.mParallaxOffset.y, shouldUseParallaxEffect);
}
void setDividerPosition(int position, boolean applyLayoutChange) {
@@ -620,10 +620,15 @@
}
/** Fling divider from current position to center position. */
- public void flingDividerToCenter() {
+ public void flingDividerToCenter(@Nullable Runnable finishCallback) {
final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
flingDividerPosition(getDividerPosition(), pos, FLING_ENTER_DURATION,
- () -> setDividerPosition(pos, true /* applyLayoutChange */));
+ () -> {
+ setDividerPosition(pos, true /* applyLayoutChange */);
+ if (finishCallback != null) {
+ finishCallback.run();
+ }
+ });
}
@VisibleForTesting
@@ -647,7 +652,9 @@
.setDuration(duration);
mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mDividerFlingAnimator.addUpdateListener(
- animation -> updateDividerBounds((int) animation.getAnimatedValue()));
+ animation -> updateDividerBounds(
+ (int) animation.getAnimatedValue(), false /* shouldUseParallaxEffect */)
+ );
mDividerFlingAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -897,7 +904,8 @@
* @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
* SurfaceControl, SurfaceControl, boolean)
*/
- void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY);
+ void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+ boolean shouldUseParallaxEffect);
/**
* Calls when finish resizing the split bounds.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index f9259e7..e8226051 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.common.split;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED;
-
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -26,25 +24,18 @@
import android.app.ActivityManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Rect;
-import android.os.UserHandle;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.util.ArrayUtils;
import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
-import java.util.Arrays;
-import java.util.List;
-
/** Helper utility class for split screen components to use. */
public class SplitScreenUtils {
/** Reverse the split position. */
@@ -137,4 +128,10 @@
return isLandscape;
}
}
+
+ /** Returns the specified background color that matches a RunningTaskInfo. */
+ public static Color getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+ final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+ return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index fb0a1ab..4e9e8f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -100,6 +100,7 @@
import com.android.wm.shell.unfold.qualifier.UnfoldTransition;
import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
+import com.android.wm.shell.windowdecor.ResizeHandleSizeRepository;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import dagger.Binds;
@@ -220,7 +221,8 @@
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopTasksController> desktopTasksController,
- RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
if (DesktopModeStatus.canEnterDesktopMode(context)) {
return new DesktopModeWindowDecorViewModel(
context,
@@ -237,7 +239,8 @@
syncQueue,
transitions,
desktopTasksController,
- rootTaskDisplayAreaOrganizer);
+ rootTaskDisplayAreaOrganizer,
+ resizeHandleSizeRepository);
}
return new CaptionWindowDecorViewModel(
context,
@@ -247,7 +250,8 @@
displayController,
rootTaskDisplayAreaOrganizer,
syncQueue,
- transitions);
+ transitions,
+ resizeHandleSizeRepository);
}
//
@@ -529,7 +533,8 @@
exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler,
dragToDesktopTransitionHandler, desktopModeTaskRepository,
desktopModeLoggerTransitionObserver, launchAdjacentController,
- recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter);
+ recentsTransitionHandler, multiInstanceHelper,
+ mainExecutor, desktopTasksLimiter);
}
@WMSingleton
@@ -622,6 +627,12 @@
return new DesktopModeEventLogger();
}
+ @WMSingleton
+ @Provides
+ static ResizeHandleSizeRepository provideResizeHandleSizeRepository() {
+ return new ResizeHandleSizeRepository();
+ }
+
//
// Drag and drop
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index d644006..677fd5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -60,6 +60,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.HomeTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import dagger.Module;
@@ -192,11 +193,12 @@
PipBoundsState pipBoundsState, PipDisplayLayoutState pipDisplayLayoutState,
PipTransitionState pipTransitionState, PhonePipMenuController pipMenuController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ HomeTransitionObserver homeTransitionObserver,
Optional<SplitScreenController> splitScreenOptional) {
return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
pipBoundsState, pipDisplayLayoutState, pipTransitionState, pipMenuController,
pipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper,
- splitScreenOptional);
+ homeTransitionObserver, splitScreenOptional);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 01364d1..6968317 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -46,6 +46,7 @@
import com.android.wm.shell.pip2.phone.PipTransition;
import com.android.wm.shell.pip2.phone.PipTransitionState;
import com.android.wm.shell.shared.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -82,6 +83,7 @@
@Provides
static Optional<PipController> providePipController(Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellController shellController,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
@@ -97,9 +99,10 @@
return Optional.empty();
} else {
return Optional.ofNullable(PipController.create(
- context, shellInit, shellController, displayController, displayInsetsController,
- pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler,
- taskStackListener, shellTaskOrganizer, pipTransitionState, mainExecutor));
+ context, shellInit, shellCommandHandler, shellController, displayController,
+ displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
+ pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
+ pipTransitionState, mainExecutor));
}
}
@@ -129,6 +132,7 @@
@Provides
static PipTouchHandler providePipTouchHandler(Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
PhonePipMenuController menuPhoneController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
@@ -140,10 +144,10 @@
PipUiEventLogger pipUiEventLogger,
@ShellMainThread ShellExecutor mainExecutor,
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
- return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
- pipBoundsState, pipTransitionState, pipScheduler, sizeSpecSource, pipMotionHelper,
- floatingContentCoordinator, pipUiEventLogger, mainExecutor,
- pipPerfHintControllerOptional);
+ return new PipTouchHandler(context, shellInit, shellCommandHandler, menuPhoneController,
+ pipBoundsAlgorithm, pipBoundsState, pipTransitionState, pipScheduler,
+ sizeSpecSource, pipMotionHelper, floatingContentCoordinator, pipUiEventLogger,
+ mainExecutor, pipPerfHintControllerOptional);
}
@WMSingleton
@@ -163,7 +167,7 @@
@WMSingleton
@Provides
- static PipTransitionState providePipStackListenerController() {
- return new PipTransitionState();
+ static PipTransitionState providePipTransitionState(@ShellMainThread Handler handler) {
+ return new PipTransitionState(handler);
}
}
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 2dc4573..e5bf53a 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
@@ -73,6 +73,8 @@
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.DesktopModeStatus
+import com.android.wm.shell.shared.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
+import com.android.wm.shell.shared.DesktopModeStatus.isDesktopDensityOverrideSet
import com.android.wm.shell.shared.annotations.ExternalThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.splitscreen.SplitScreenController
@@ -906,18 +908,22 @@
task.taskId
)
return WindowContainerTransaction().also { wct ->
- addMoveToFullscreenChanges(wct, task)
+ bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
+ wct.reorder(task.token, true)
}
}
+ val wct = WindowContainerTransaction()
+ if (isDesktopDensityOverrideSet()) {
+ wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE)
+ }
// Desktop Mode is showing and we're launching a new Task - we might need to minimize
// a Task.
- val wct = WindowContainerTransaction()
val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task)
if (taskToMinimize != null) {
addPendingMinimizeTransition(transition, taskToMinimize)
return wct
}
- return null
+ return if (wct.isEmpty) null else wct
}
private fun handleFullscreenTaskLaunch(
@@ -985,7 +991,7 @@
wct.setWindowingMode(taskInfo.token, targetWindowingMode)
wct.reorder(taskInfo.token, true /* onTop */)
if (isDesktopDensityOverrideSet()) {
- wct.setDensityDpi(taskInfo.token, getDesktopDensityDpi())
+ wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE)
}
}
@@ -1089,10 +1095,6 @@
return context.resources.displayMetrics.densityDpi
}
- private fun getDesktopDensityDpi(): Int {
- return DESKTOP_DENSITY_OVERRIDE
- }
-
/** Creates a new instance of the external interface to pass to another process. */
private fun createExternalInterface(): ExternalInterfaceBinder {
return IDesktopModeImpl(this)
@@ -1466,21 +1468,9 @@
}
companion object {
- private val DESKTOP_DENSITY_OVERRIDE =
- SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284)
- private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
-
@JvmField
val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties
.getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f
-
- /**
- * Check if desktop density override is enabled
- */
- @JvmStatic
- fun isDesktopDensityOverrideSet(): Boolean {
- return DESKTOP_DENSITY_OVERRIDE in DESKTOP_DENSITY_ALLOWED_RANGE
- }
}
/** The positions on a screen that a task can snap to. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 165feec..7e70d6a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -316,7 +316,8 @@
}
// TODO(b/290391688): Also update the session data with task stack changes
pd.dragSession = new DragSession(ActivityTaskManager.getInstance(),
- mDisplayController.getDisplayLayout(displayId), event.getClipData());
+ mDisplayController.getDisplayLayout(displayId), event.getClipData(),
+ event.getDragFlags());
pd.dragSession.update();
pd.activeDragCount++;
pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
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 6a7d297..a42ca19 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,10 +16,9 @@
package com.android.wm.shell.draganddrop;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
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;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
@@ -47,7 +46,6 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
-import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
@@ -265,13 +263,14 @@
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true);
+ // Put BAL flags to avoid activity start aborted.
+ baseActivityOpts.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ baseActivityOpts.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
final Bundle opts = baseActivityOpts.toBundle();
if (session.appData.hasExtra(EXTRA_ACTIVITY_OPTIONS)) {
opts.putAll(session.appData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS));
}
- // 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);
final UserHandle user = session.appData.getParcelableExtra(EXTRA_USER);
if (isTask) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 59d6969..4bb10df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -22,11 +22,11 @@
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
@@ -41,7 +41,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
@@ -278,7 +277,7 @@
final int activityType = taskInfo1.getActivityType();
if (activityType == ACTIVITY_TYPE_STANDARD) {
Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
- int bgColor1 = getResizingBackgroundColor(taskInfo1);
+ int bgColor1 = getResizingBackgroundColor(taskInfo1).toArgb();
mDropZoneView1.setAppInfo(bgColor1, icon1);
mDropZoneView2.setAppInfo(bgColor1, icon1);
updateDropZoneSizes(null, null); // passing null splits the views evenly
@@ -298,10 +297,10 @@
mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
if (topOrLeftTask != null && bottomOrRightTask != null) {
Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo);
- int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask);
+ int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask).toArgb();
Drawable bottomOrRightIcon = mIconProvider.getIcon(
bottomOrRightTask.topActivityInfo);
- int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask);
+ int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask).toArgb();
mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon);
mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon);
}
@@ -556,11 +555,6 @@
}
}
- private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
- final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
- return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
- }
-
/**
* Dumps information about this drag layout.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
index 8f1bc59..0addd43 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -40,6 +40,7 @@
public class DragSession {
private final ActivityTaskManager mActivityTaskManager;
private final ClipData mInitialDragData;
+ private final int mInitialDragFlags;
final DisplayLayout displayLayout;
// The activity info associated with the activity in the appData or the launchableIntent
@@ -62,9 +63,10 @@
boolean dragItemSupportsSplitscreen;
DragSession(ActivityTaskManager activityTaskManager,
- DisplayLayout dispLayout, ClipData data) {
+ DisplayLayout dispLayout, ClipData data, int dragFlags) {
mActivityTaskManager = activityTaskManager;
mInitialDragData = data;
+ mInitialDragFlags = dragFlags;
displayLayout = dispLayout;
}
@@ -94,6 +96,6 @@
dragItemSupportsSplitscreen = activityInfo == null
|| ActivityInfo.isResizeableMode(activityInfo.resizeMode);
appData = mInitialDragData.getItemAt(0).getIntent();
- launchableIntent = DragUtils.getLaunchIntent(mInitialDragData);
+ launchableIntent = DragUtils.getLaunchIntent(mInitialDragData, mInitialDragFlags);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
index 24f8e18..e215870 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -24,6 +24,7 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.view.DragEvent;
+import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -67,14 +68,18 @@
*/
@Nullable
public static PendingIntent getLaunchIntent(@NonNull DragEvent dragEvent) {
- return getLaunchIntent(dragEvent.getClipData());
+ return getLaunchIntent(dragEvent.getClipData(), dragEvent.getDragFlags());
}
/**
* Returns a launchable intent in the given `ClipData` or `null` if there is none.
*/
@Nullable
- public static PendingIntent getLaunchIntent(@NonNull ClipData data) {
+ public static PendingIntent getLaunchIntent(@NonNull ClipData data, int dragFlags) {
+ if ((dragFlags & View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) == 0) {
+ // Disallow launching the intent if the app does not want to delegate it to the system
+ return null;
+ }
for (int i = 0; i < data.getItemCount(); i++) {
final ClipData.Item item = data.getItemAt(i);
if (item.getIntentSender() != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 2082756..3c7713d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -75,6 +75,7 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.CounterRotatorHelper;
+import com.android.wm.shell.transition.HomeTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -107,6 +108,7 @@
private final PipDisplayLayoutState mPipDisplayLayoutState;
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
+ private final HomeTransitionObserver mHomeTransitionObserver;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final PipAnimationController mPipAnimationController;
private @PipAnimationController.AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS;
@@ -164,6 +166,7 @@
PipBoundsAlgorithm pipBoundsAlgorithm,
PipAnimationController pipAnimationController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ HomeTransitionObserver homeTransitionObserver,
Optional<SplitScreenController> splitScreenOptional) {
super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
pipBoundsAlgorithm);
@@ -174,6 +177,7 @@
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mHomeTransitionObserver = homeTransitionObserver;
mSplitScreenOptional = splitScreenOptional;
}
@@ -196,6 +200,9 @@
animator.cancel();
}
mExitTransition = mTransitions.startTransition(type, out, this);
+ if (mPipOrganizer.getOutPipWindowingMode() == WINDOWING_MODE_UNDEFINED) {
+ mHomeTransitionObserver.notifyHomeVisibilityChanged(false /* isVisible */);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index a12882f..f5afeea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -58,9 +58,12 @@
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import java.io.PrintWriter;
+
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
@@ -72,6 +75,7 @@
private static final String SWIPE_TO_PIP_OVERLAY = "swipe_to_pip_overlay";
private final Context mContext;
+ private final ShellCommandHandler mShellCommandHandler;
private final ShellController mShellController;
private final DisplayController mDisplayController;
private final DisplayInsetsController mDisplayInsetsController;
@@ -111,6 +115,7 @@
private PipController(Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellController shellController,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
@@ -123,6 +128,7 @@
PipTransitionState pipTransitionState,
ShellExecutor mainExecutor) {
mContext = context;
+ mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
@@ -146,6 +152,7 @@
*/
public static PipController create(Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellController shellController,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
@@ -162,13 +169,14 @@
"%s: Device doesn't support Pip feature", TAG);
return null;
}
- return new PipController(context, shellInit, shellController, displayController,
- displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState,
- pipScheduler, taskStackListener, shellTaskOrganizer, pipTransitionState,
- mainExecutor);
+ return new PipController(context, shellInit, shellCommandHandler, shellController,
+ displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
+ pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
+ pipTransitionState, mainExecutor);
}
private void onInit() {
+ mShellCommandHandler.addDumpCallback(this::dump, this);
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId());
@@ -338,6 +346,14 @@
}
}
+ private void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = " ";
+ pw.println(TAG);
+ mPipBoundsAlgorithm.dump(pw, innerPrefix);
+ mPipBoundsState.dump(pw, innerPrefix);
+ mPipDisplayLayoutState.dump(pw, innerPrefix);
+ }
+
/**
* The interface for calls from outside the host process.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index be10151..aed493f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -696,6 +696,19 @@
case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break;
+ if (mPipBoundsState.getBounds().equals(
+ mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) {
+ // Avoid scheduling transitions for bounds that don't change, such transition is
+ // a no-op and would be aborted.
+ settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
+ cleanUpHighPerfSessionMaybe();
+ // SCHEDULED_BOUNDS_CHANGE can have multiple active listeners making
+ // actual changes (e.g. PipTouchHandler). So post state update onto handler,
+ // to run after synchronous dispatch is complete.
+ mPipTransitionState.postState(PipTransitionState.CHANGED_PIP_BOUNDS);
+ break;
+ }
+
// If touch is turned off and we are in a fling animation, schedule a transition.
mWaitingForBoundsChangeTransition = true;
mPipScheduler.scheduleAnimateResizePip(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
index b55a41d..7dffe54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
@@ -514,6 +514,20 @@
switch (newState) {
case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
if (!extra.getBoolean(RESIZE_BOUNDS_CHANGE)) break;
+
+ if (mPipBoundsState.getBounds().equals(mLastResizeBounds)) {
+ // If the bounds are invariant move the destination bounds by a single pixel
+ // to top/bottom to avoid a no-op transition. This trick helps keep the
+ // animation a part of the transition.
+ float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
+ mPipBoundsState.getBounds());
+
+ // Move to the top if closer to the bottom edge and vice versa.
+ boolean inTopHalf = snapFraction < 1.5 || snapFraction > 3.5;
+ int offsetY = inTopHalf ? 1 : -1;
+ mLastResizeBounds.offset(0 /* dx */, offsetY);
+ }
+
mWaitingForBoundsChangeTransition = true;
mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds);
break;
@@ -527,17 +541,14 @@
PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
Rect destinationBounds = extra.getParcelable(
PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
- startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
- destinationBounds.left, destinationBounds.top);
startTx.apply();
// All motion operations have actually finished, so make bounds cache updates.
+ mUpdateResizeBoundsCallback.accept(destinationBounds);
cleanUpHighPerfSessionMaybe();
// Setting state to CHANGED_PIP_BOUNDS applies finishTx and notifies Core.
mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS);
-
- mUpdateResizeBoundsCallback.accept(destinationBounds);
break;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 319d199..56a465a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -64,6 +64,7 @@
import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
@@ -81,6 +82,7 @@
// Allow PIP to resize to a slightly bigger state upon touch
private boolean mEnableResize;
private final Context mContext;
+ private final ShellCommandHandler mShellCommandHandler;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@NonNull private final PipBoundsState mPipBoundsState;
@NonNull private final PipTransitionState mPipTransitionState;
@@ -170,6 +172,7 @@
@SuppressLint("InflateParams")
public PipTouchHandler(Context context,
ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
PhonePipMenuController menuController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
@@ -182,6 +185,7 @@
ShellExecutor mainExecutor,
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
mContext = context;
+ mShellCommandHandler = shellCommandHandler;
mMainExecutor = mainExecutor;
mPipPerfHintController = pipPerfHintControllerOptional.orElse(null);
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -235,6 +239,7 @@
mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
reloadResources();
+ mShellCommandHandler.addDumpCallback(this::dump, this);
mMotionHelper.init();
mPipResizeGestureHandler.init();
mPipDismissTargetHandler.init();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 8204d41..9d599ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Handler;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;
@@ -26,6 +27,7 @@
import androidx.annotation.Nullable;
import com.android.internal.util.Preconditions;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -109,6 +111,13 @@
private int mState;
//
+ // Dependencies
+ //
+
+ @ShellMainThread
+ private final Handler mMainHandler;
+
+ //
// Swipe up to enter PiP related state
//
@@ -149,6 +158,10 @@
private final List<PipTransitionStateChangedListener> mCallbacks = new ArrayList<>();
+ public PipTransitionState(@ShellMainThread Handler handler) {
+ mMainHandler = handler;
+ }
+
/**
* @return the state of PiP in the context of transitions.
*/
@@ -182,6 +195,32 @@
}
}
+ /**
+ * Posts the state update for PiP in the context of transitions onto the main handler.
+ *
+ * <p>This is done to guarantee that any callback dispatches for the present state are
+ * complete. This is relevant for states that have multiple listeners, such as
+ * <code>SCHEDULED_BOUNDS_CHANGE</code> that helps turn off touch interactions along with
+ * the actual transition scheduling.</p>
+ */
+ public void postState(@TransitionState int state) {
+ postState(state, null /* extra */);
+ }
+
+ /**
+ * Posts the state update for PiP in the context of transitions onto the main handler.
+ *
+ * <p>This is done to guarantee that any callback dispatches for the present state are
+ * complete. This is relevant for states that have multiple listeners, such as
+ * <code>SCHEDULED_BOUNDS_CHANGE</code> that helps turn off touch interactions along with
+ * the actual transition scheduling.</p>
+ *
+ * @param extra a bundle passed to the subscribed listeners to resolve/cache extra info.
+ */
+ public void postState(@TransitionState int state, @Nullable Bundle extra) {
+ mMainHandler.post(() -> setState(state, extra));
+ }
+
private void dispatchPipTransitionStateChanged(@TransitionState int oldState,
@TransitionState int newState, @Nullable Bundle extra) {
mCallbacks.forEach(l -> l.onPipTransitionStateChanged(oldState, newState, extra));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a7829c9..3a266d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -402,6 +402,11 @@
}
}
+ /**
+ * Cleans up the recents transition. This should generally not be called directly
+ * to cancel a transition after it has started, instead callers should call one of
+ * the cancel() methods to ensure that Launcher is notified.
+ */
void cleanUp() {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.cleanup", mInstanceId);
@@ -438,7 +443,8 @@
if (mListener == null || mTransition == null) {
Slog.e(TAG, "Missing listener or transition, hasListener=" + (mListener != null) +
" hasTransition=" + (mTransition != null));
- cleanUp();
+ cancel("No listener (" + (mListener == null)
+ + ") or no transition (" + (mTransition == null) + ")");
return false;
}
// First see if this is a valid recents transition.
@@ -462,7 +468,7 @@
if (mRecentsTask == null && !hasPausingTasks) {
// Recents is already running apparently, so this is a no-op.
Slog.e(TAG, "Tried to start recents while it is already running.");
- cleanUp();
+ cancel("No recents task and no pausing tasks");
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 6e5b767..0541a02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -501,10 +501,11 @@
mAnimatingTransition = null;
mOnFinish.run();
- if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(wct /* wct */);
- mFinishCallback = null;
- }
+ if (mFinishCallback != null) {
+ Transitions.TransitionFinishCallback currentFinishCallback = mFinishCallback;
+ mFinishCallback = null;
+ currentFinishCallback.onTransitionFinished(wct /* wct */);
+ }
}
private void startFadeAnimation(@NonNull SurfaceControl leash, boolean show) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8e97068..82ef422 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -16,10 +16,8 @@
package com.android.wm.shell.splitscreen;
-import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
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;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -43,11 +41,11 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
-import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
@@ -1887,13 +1885,15 @@
}
private void addActivityOptions(Bundle opts, @Nullable StageTaskListener launchTarget) {
+ ActivityOptions options = ActivityOptions.fromBundle(opts);
if (launchTarget != null) {
- opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, launchTarget.mRootTaskInfo.token);
+ options.setLaunchRootTask(launchTarget.mRootTaskInfo.token);
}
// Put BAL flags to avoid activity start aborted. Otherwise, flows like shortcut to split
// will be canceled.
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
+ options.setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
+ opts.putAll(options.toBundle());
}
void updateActivityOptions(Bundle opts, @SplitPosition int position) {
@@ -2129,7 +2129,7 @@
mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
- mSplitLayout.flingDividerToCenter();
+ mSplitLayout.flingDividerToCenter(/*finishCallback*/ null);
}
});
}
@@ -2329,7 +2329,7 @@
mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
- mSplitLayout.flingDividerToCenter();
+ mSplitLayout.flingDividerToCenter(/*finishCallback*/ null);
}
});
}
@@ -2388,14 +2388,20 @@
}
@Override
- public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY) {
+ public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+ boolean shouldUseParallaxEffect) {
final SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- updateSurfaceBounds(layout, t, true /* applyResizingOffset */);
+ updateSurfaceBounds(layout, t, shouldUseParallaxEffect);
getMainStageBounds(mTempRect1);
getSideStageBounds(mTempRect2);
- mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
- mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+ // TODO (b/307490004): "commonColor" below is a temporary fix to ensure the colors on both
+ // sides match. When b/307490004 is fixed, this code can be reverted.
+ float[] commonColor = getResizingBackgroundColor(mSideStage.mRootTaskInfo).getComponents();
+ mMainStage.onResizing(
+ mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
+ mSideStage.onResizing(
+ mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
t.apply();
mTransactionPool.release(t);
}
@@ -3166,7 +3172,10 @@
final TransitionInfo.Change finalMainChild = mainChild;
final TransitionInfo.Change finalSideChild = sideChild;
enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
- notifySplitAnimationFinished();
+ if (!enterTransition.mResizeAnim) {
+ // If resizing, we'll call notify at the end of the resizing animation (below)
+ notifySplitAnimationFinished();
+ }
if (finalMainChild != null) {
if (!mainNotContainOpenTask) {
mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
@@ -3186,7 +3195,7 @@
}
if (enterTransition.mResizeAnim) {
mShowDecorImmediately = true;
- mSplitLayout.flingDividerToCenter();
+ mSplitLayout.flingDividerToCenter(this::notifySplitAnimationFinished);
}
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
mPausingTasks.clear();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index f77c80d..0f3d6ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -314,10 +314,10 @@
}
void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX,
- int offsetY, boolean immediately) {
+ int offsetY, boolean immediately, float[] veilColor) {
if (mSplitDecorManager != null && mRootTaskInfo != null) {
mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t, offsetX,
- offsetY, immediately);
+ offsetY, immediately, veilColor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index e85cb64..bfa163c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -63,6 +63,7 @@
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Transitions mTransitions;
+ private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
private TaskOperations mTaskOperations;
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
@@ -75,7 +76,8 @@
DisplayController displayController,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
SyncTransactionQueue syncQueue,
- Transitions transitions) {
+ Transitions transitions,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
mContext = context;
mMainHandler = mainHandler;
mMainChoreographer = mainChoreographer;
@@ -84,6 +86,7 @@
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mSyncQueue = syncQueue;
mTransitions = transitions;
+ mResizeHandleSizeRepository = resizeHandleSizeRepository;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
}
@@ -231,7 +234,8 @@
taskSurface,
mMainHandler,
mMainChoreographer,
- mSyncQueue);
+ mSyncQueue,
+ mResizeHandleSizeRepository);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final FluidResizeTaskPositioner taskPositioner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 6671391..8a49a73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -16,11 +16,11 @@
package com.android.wm.shell.windowdecor;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getFineResizeCornerPixels;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getLargeResizeCornerPixels;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
@@ -45,6 +45,8 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import java.util.function.Consumer;
+
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
* {@link CaptionWindowDecorViewModel}. The caption bar contains a back button, minimize button,
@@ -58,12 +60,28 @@
private View.OnClickListener mOnCaptionButtonClickListener;
private View.OnTouchListener mOnCaptionTouchListener;
private DragPositioningCallback mDragPositioningCallback;
+ // Listener for handling drag resize events. Will be null if the task cannot be resized.
+ @Nullable
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
private RelayoutParams mRelayoutParams = new RelayoutParams();
private final RelayoutResult<WindowDecorLinearLayout> mResult =
new RelayoutResult<>();
+ private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
+ private final Consumer<ResizeHandleSizeRepository> mResizeHandleSizeChangedFunction =
+ (ResizeHandleSizeRepository sizeRepository) -> {
+ if (mDragResizeListener == null) {
+ return;
+ }
+ final Resources res = mResult.mRootView.getResources();
+ mDragResizeListener.setGeometry(
+ new DragResizeWindowGeometry(0 /* taskCornerRadius */,
+ new Size(mResult.mWidth, mResult.mHeight),
+ sizeRepository.getResizeEdgeHandlePixels(res),
+ getFineResizeCornerPixels(res), getLargeResizeCornerPixels(res)),
+ mDragDetector.getTouchSlop());
+ };
CaptionWindowDecoration(
Context context,
@@ -73,13 +91,15 @@
SurfaceControl taskSurface,
Handler handler,
Choreographer choreographer,
- SyncTransactionQueue syncQueue) {
- super(context, displayController, taskOrganizer, taskInfo, taskSurface,
- taskInfo.getConfiguration());
+ SyncTransactionQueue syncQueue,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
+ super(context, displayController, taskOrganizer, taskInfo, taskSurface);
mHandler = handler;
mChoreographer = choreographer;
mSyncQueue = syncQueue;
+ mResizeHandleSizeRepository = resizeHandleSizeRepository;
+ mResizeHandleSizeRepository.registerSizeChangeFunction(mResizeHandleSizeChangedFunction);
}
void setCaptionListeners(
@@ -238,10 +258,7 @@
.getScaledTouchSlop();
mDragDetector.setTouchSlop(touchSlop);
- final Resources res = mResult.mRootView.getResources();
- mDragResizeListener.setGeometry(new DragResizeWindowGeometry(0 /* taskCornerRadius */,
- new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(res),
- getFineResizeCornerSize(res), getLargeResizeCornerSize(res)), touchSlop);
+ mResizeHandleSizeChangedFunction.accept(mResizeHandleSizeRepository);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 9afb057..10ab13a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -149,6 +149,7 @@
new DesktopModeKeyguardChangeListener();
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
private final DisplayInsetsController mDisplayInsetsController;
+ private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
private final Region mExclusionRegion = Region.obtain();
private boolean mInImmersiveMode;
@@ -181,7 +182,8 @@
SyncTransactionQueue syncQueue,
Transitions transitions,
Optional<DesktopTasksController> desktopTasksController,
- RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ ResizeHandleSizeRepository resizeHandleSizeRepository
) {
this(
context,
@@ -202,7 +204,8 @@
new InputMonitorFactory(),
SurfaceControl.Transaction::new,
rootTaskDisplayAreaOrganizer,
- new SparseArray<>());
+ new SparseArray<>(),
+ resizeHandleSizeRepository);
}
@VisibleForTesting
@@ -225,7 +228,8 @@
InputMonitorFactory inputMonitorFactory,
Supplier<SurfaceControl.Transaction> transactionFactory,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
- SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId) {
+ SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
mContext = context;
mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
@@ -246,6 +250,7 @@
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mInputManager = mContext.getSystemService(InputManager.class);
mWindowDecorByTaskId = windowDecorByTaskId;
+ mResizeHandleSizeRepository = resizeHandleSizeRepository;
shellInit.addInitCallback(this::onInit, this);
}
@@ -1060,7 +1065,8 @@
mMainHandler,
mMainChoreographer,
mSyncQueue,
- mRootTaskDisplayAreaOrganizer);
+ mRootTaskDisplayAreaOrganizer,
+ mResizeHandleSizeRepository);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final DragPositioningCallback dragPositioningCallback;
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 4d4dc3c..9c92791 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
@@ -24,11 +24,11 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getFineResizeCornerPixels;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getLargeResizeCornerPixels;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
@@ -60,13 +60,13 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
+import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.shared.DesktopModeStatus;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.DesktopModeAppControlsWindowDecorationViewHolder;
@@ -75,6 +75,7 @@
import kotlin.Unit;
+import java.util.function.Function;
import java.util.function.Supplier;
/**
@@ -96,6 +97,8 @@
private View.OnLongClickListener mOnCaptionLongClickListener;
private View.OnGenericMotionListener mOnCaptionGenericMotionListener;
private DragPositioningCallback mDragPositioningCallback;
+ // Listener for handling drag resize events. Will be null if the task cannot be resized.
+ @Nullable
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
@@ -118,22 +121,35 @@
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+ private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
+ private final Function<ResizeHandleSizeRepository, Boolean> mResizeHandleSizeChangedFunction =
+ (ResizeHandleSizeRepository sizeRepository) -> {
+ final Resources res = mResult.mRootView.getResources();
+ return mDragResizeListener == null || mDragResizeListener.setGeometry(
+ new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius,
+ new Size(mResult.mWidth, mResult.mHeight),
+ sizeRepository.getResizeEdgeHandlePixels(res),
+ getFineResizeCornerPixels(res),
+ getLargeResizeCornerPixels(res)),
+ mDragDetector.getTouchSlop());
+ };
+
DesktopModeWindowDecoration(
Context context,
DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
- Configuration windowDecorConfig,
Handler handler,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
- this (context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
+ this (context, displayController, taskOrganizer, taskInfo, taskSurface,
handler, choreographer, syncQueue, rootTaskDisplayAreaOrganizer,
- SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
- WindowContainerTransaction::new, SurfaceControl::new,
- new SurfaceControlViewHostFactory() {});
+ resizeHandleSizeRepository, SurfaceControl.Builder::new,
+ SurfaceControl.Transaction::new, WindowContainerTransaction::new,
+ SurfaceControl::new, new SurfaceControlViewHostFactory() {});
}
DesktopModeWindowDecoration(
@@ -142,17 +158,17 @@
ShellTaskOrganizer taskOrganizer,
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
- Configuration windowDecorConfig,
Handler handler,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ ResizeHandleSizeRepository resizeHandleSizeRepository,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
- super(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig,
+ super(context, displayController, taskOrganizer, taskInfo, taskSurface,
surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
surfaceControlViewHostFactory);
@@ -160,6 +176,9 @@
mChoreographer = choreographer;
mSyncQueue = syncQueue;
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+ mResizeHandleSizeRepository = resizeHandleSizeRepository;
+ mResizeHandleSizeRepository.registerSizeChangeFunction(
+ mResizeHandleSizeChangedFunction::apply);
}
void setCaptionListeners(
@@ -305,11 +324,7 @@
// If either task geometry or position have changed, update this task's
// exclusion region listener
- final Resources res = mResult.mRootView.getResources();
- if (mDragResizeListener.setGeometry(
- new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius,
- new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(res),
- getFineResizeCornerSize(res), getLargeResizeCornerSize(res)), touchSlop)
+ if (mResizeHandleSizeChangedFunction.apply(mResizeHandleSizeRepository)
|| !mTaskInfo.positionInParent.equals(mPositionInParent)) {
updateExclusionRegion();
}
@@ -332,13 +347,16 @@
boolean applyStartTransactionOnDraw,
boolean shouldSetTaskPositionAndCrop) {
final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
+ final boolean isAppHeader =
+ captionLayoutId == R.layout.desktop_mode_app_controls_window_decor;
+ final boolean isAppHandle = captionLayoutId == R.layout.desktop_mode_focused_window_decor;
relayoutParams.reset();
relayoutParams.mRunningTaskInfo = taskInfo;
relayoutParams.mLayoutResId = captionLayoutId;
relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
- if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
+ if (isAppHeader) {
if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
// If the app is requesting to customize the caption bar, allow input to fall
// through to the windows below so that the app can respond to input events on
@@ -359,7 +377,7 @@
controlsElement.mWidthResId = R.dimen.desktop_mode_customizable_caption_margin_end;
controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
relayoutParams.mOccludingCaptionElements.add(controlsElement);
- } else if (captionLayoutId == R.layout.desktop_mode_focused_window_decor) {
+ } else if (isAppHandle) {
// The focused decor (fullscreen/split) does not need to handle input because input in
// the App Handle is handled by the InputMonitor in DesktopModeWindowDecorViewModel.
relayoutParams.mInputFeatures
@@ -372,19 +390,25 @@
}
relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayoutParams.mSetTaskPositionAndCrop = shouldSetTaskPositionAndCrop;
- // The configuration used to lay out the window decoration. The system context's config is
- // used when the task density has been overridden to a custom density so that the resources
- // and views of the decoration aren't affected and match the rest of the System UI, if not
- // then just use the task's configuration. A copy is made instead of using the original
- // reference so that the configuration isn't mutated on config changes and diff checks can
- // be made in WindowDecoration#relayout using the pre/post-relayout configuration.
- // See b/301119301.
+
+ // The configuration used to layout the window decoration. A copy is made instead of using
+ // the original reference so that the configuration isn't mutated on config changes and
+ // diff checks can be made in WindowDecoration#relayout using the pre/post-relayout
+ // configuration. See b/301119301.
// TODO(b/301119301): consider moving the config data needed for diffs to relayout params
// instead of using a whole Configuration as a parameter.
final Configuration windowDecorConfig = new Configuration();
- windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet()
- ? context.getResources().getConfiguration() // Use system context.
- : taskInfo.configuration); // Use task configuration.
+ if (Flags.enableAppHeaderWithTaskDensity() && isAppHeader) {
+ // Should match the density of the task. The task may have had its density overridden
+ // to be different that SysUI's.
+ windowDecorConfig.setTo(taskInfo.configuration);
+ } else if (DesktopModeStatus.isDesktopDensityOverrideSet()) {
+ // The task has had its density overridden, but keep using the system's density to
+ // layout the header.
+ windowDecorConfig.setTo(context.getResources().getConfiguration());
+ } else {
+ windowDecorConfig.setTo(taskInfo.configuration);
+ }
relayoutParams.mWindowDecorConfig = windowDecorConfig;
if (DesktopModeStatus.useRoundedCorners()) {
@@ -936,22 +960,19 @@
Handler handler,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
- RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
- final Configuration windowDecorConfig =
- DesktopTasksController.isDesktopDensityOverrideSet()
- ? context.getResources().getConfiguration() // Use system context
- : taskInfo.configuration; // Use task configuration
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ ResizeHandleSizeRepository resizeHandleSizeRepository) {
return new DesktopModeWindowDecoration(
context,
displayController,
taskOrganizer,
taskInfo,
taskSurface,
- windowDecorConfig,
handler,
choreographer,
syncQueue,
- rootTaskDisplayAreaOrganizer);
+ rootTaskDisplayAreaOrganizer,
+ resizeHandleSizeRepository);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index da26898..a3b0a71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -119,6 +119,10 @@
mTouchSlop = touchSlop;
}
+ int getTouchSlop() {
+ return mTouchSlop;
+ }
+
private void resetState() {
mIsDragEvent = false;
mInputDownPoint.set(0, 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index 4f513f0..80d60d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -26,7 +26,6 @@
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED;
import android.annotation.NonNull;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -36,8 +35,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.wm.shell.R;
-
import java.util.Objects;
/**
@@ -63,6 +60,10 @@
// Extra-large edge bounds for logging to help debug when an edge resize is ignored.
private final @Nullable TaskEdges mDebugTaskEdges;
+ /**
+ * Constructs an instance representing the drag resize touch input regions, where all sizes
+ * are represented in pixels.
+ */
DragResizeWindowGeometry(int taskCornerRadius, @NonNull Size taskSize,
int resizeHandleThickness, int fineCornerSize, int largeCornerSize) {
mTaskCornerRadius = taskCornerRadius;
@@ -82,31 +83,6 @@
}
/**
- * Returns the resource value to use for the resize handle on the edge of the window.
- */
- static int getResizeEdgeHandleSize(@NonNull Resources res) {
- return enableWindowingEdgeDragResize()
- ? res.getDimensionPixelSize(R.dimen.desktop_mode_edge_handle)
- : res.getDimensionPixelSize(R.dimen.freeform_resize_handle);
- }
-
- /**
- * Returns the resource value to use for course input, such as touch, that benefits from a large
- * square on each of the window's corners.
- */
- static int getLargeResizeCornerSize(@NonNull Resources res) {
- return res.getDimensionPixelSize(R.dimen.desktop_mode_corner_resize_large);
- }
-
- /**
- * Returns the resource value to use for fine input, such as stylus, that can use a smaller
- * square on each of the window's corners.
- */
- static int getFineResizeCornerSize(@NonNull Resources res) {
- return res.getDimensionPixelSize(R.dimen.freeform_resize_corner);
- }
-
- /**
* Returns the size of the task this geometry is calculated for.
*/
@NonNull Size getTaskSize() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index b2f8cfd..53bdda1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -20,15 +20,19 @@
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.ColorStateList
+import android.graphics.Color
+import android.graphics.drawable.RippleDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageButton
import android.widget.ProgressBar
+import androidx.annotation.ColorInt
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import androidx.core.content.ContextCompat
+import com.android.window.flags.Flags
import com.android.wm.shell.R
private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
@@ -90,17 +94,70 @@
progressBar.visibility = View.INVISIBLE
}
- fun setAnimationTints(darkMode: Boolean) {
- if (darkMode) {
- progressBar.progressTintList = ColorStateList.valueOf(
- resources.getColor(R.color.desktop_mode_maximize_menu_progress_dark))
- maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
- R.color.desktop_mode_caption_button_color_selector_dark))
+ /**
+ * Set the color tints of the maximize button views.
+ *
+ * @param darkMode whether the app's theme is in dark mode.
+ * @param iconForegroundColor the color tint to use for the maximize icon to match the rest of
+ * the App Header icons
+ * @param baseForegroundColor the base foreground color tint used by the App Header, used to style
+ * views within this button using the same base color but with different opacities.
+ */
+ fun setAnimationTints(
+ darkMode: Boolean,
+ iconForegroundColor: ColorStateList? = null,
+ baseForegroundColor: Int? = null
+ ) {
+ if (Flags.enableThemedAppHeaders()) {
+ requireNotNull(iconForegroundColor) { "Icon foreground color must be non-null" }
+ requireNotNull(baseForegroundColor) { "Base foreground color must be non-null" }
+ maximizeWindow.imageTintList = iconForegroundColor
+ maximizeWindow.background = RippleDrawable(
+ ColorStateList(
+ arrayOf(
+ intArrayOf(android.R.attr.state_hovered),
+ intArrayOf(android.R.attr.state_pressed),
+ intArrayOf(),
+ ),
+ intArrayOf(
+ replaceColorAlpha(baseForegroundColor, OPACITY_8),
+ replaceColorAlpha(baseForegroundColor, OPACITY_12),
+ Color.TRANSPARENT
+ )
+ ),
+ null,
+ null
+ )
+ progressBar.progressTintList = ColorStateList.valueOf(baseForegroundColor)
+ .withAlpha(OPACITY_12)
+ progressBar.progressBackgroundTintList = ColorStateList.valueOf(Color.TRANSPARENT)
} else {
- progressBar.progressTintList = ColorStateList.valueOf(
+ if (darkMode) {
+ progressBar.progressTintList = ColorStateList.valueOf(
+ resources.getColor(R.color.desktop_mode_maximize_menu_progress_dark))
+ maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
+ R.color.desktop_mode_caption_button_color_selector_dark))
+ } else {
+ progressBar.progressTintList = ColorStateList.valueOf(
resources.getColor(R.color.desktop_mode_maximize_menu_progress_light))
- maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
+ maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
R.color.desktop_mode_caption_button_color_selector_light))
+ }
}
}
+
+ @ColorInt
+ private fun replaceColorAlpha(@ColorInt color: Int, alpha: Int): Int {
+ return Color.argb(
+ alpha,
+ Color.red(color),
+ Color.green(color),
+ Color.blue(color)
+ )
+ }
+
+ companion object {
+ private const val OPACITY_8 = 20
+ private const val OPACITY_12 = 31
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt
new file mode 100644
index 0000000..be7a301
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.windowdecor
+
+import android.content.res.Resources
+import com.android.window.flags.Flags.enableWindowingEdgeDragResize
+import com.android.wm.shell.R
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.util.KtProtoLog
+import java.util.function.Consumer
+
+/** Repository for desktop mode drag resize handle sizes. */
+class ResizeHandleSizeRepository {
+ private val TAG = "ResizeHandleSizeRepository"
+ private var edgeResizeHandleSizePixels: Int? = null
+ private var sizeChangeFunctions: MutableList<Consumer<ResizeHandleSizeRepository>> =
+ mutableListOf()
+
+ /**
+ * Resets the window edge resize handle size if necessary.
+ */
+ fun resetResizeEdgeHandlePixels() {
+ if (enableWindowingEdgeDragResize() && edgeResizeHandleSizePixels != null) {
+ edgeResizeHandleSizePixels = null
+ applyToAll()
+ }
+ }
+
+ /**
+ * Sets the window edge resize handle to the given size in pixels.
+ */
+ fun setResizeEdgeHandlePixels(sizePixels: Int) {
+ if (enableWindowingEdgeDragResize()) {
+ KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "$TAG: Set edge handle size to $sizePixels")
+ if (edgeResizeHandleSizePixels != null && edgeResizeHandleSizePixels == sizePixels) {
+ // Skip updating since override is the same size
+ return
+ }
+ edgeResizeHandleSizePixels = sizePixels
+ applyToAll()
+ } else {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "$TAG: Can't set edge handle size to $sizePixels since " +
+ "enable_windowing_edge_drag_resize disabled"
+ )
+ }
+ }
+
+ /**
+ * Returns the resource value, in pixels, to use for the resize handle on the edge of the
+ * window.
+ */
+ fun getResizeEdgeHandlePixels(res: Resources): Int {
+ try {
+ return if (enableWindowingEdgeDragResize()) {
+ val resPixelSize = res.getDimensionPixelSize(R.dimen.desktop_mode_edge_handle)
+ val size = edgeResizeHandleSizePixels ?: resPixelSize
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "$TAG: Get edge handle size of $size from (vs base value $resPixelSize)"
+ )
+ size
+ } else {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "$TAG: Get edge handle size from freeform since flag is disabled"
+ )
+ res.getDimensionPixelSize(R.dimen.freeform_resize_handle)
+ }
+ } catch (e: Resources.NotFoundException) {
+ KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get edge handle size", e)
+ return 0
+ }
+ }
+
+ /** Register function to run when the resize handle size changes. */
+ fun registerSizeChangeFunction(function: Consumer<ResizeHandleSizeRepository>) {
+ sizeChangeFunctions.add(function)
+ }
+
+ private fun applyToAll() {
+ for (f in sizeChangeFunctions) {
+ f.accept(this)
+ }
+ }
+
+ companion object {
+ private val TAG = "ResizeHandleSizeRepositoryCompanion"
+
+ /**
+ * Returns the resource value in pixels to use for course input, such as touch, that
+ * benefits from a large square on each of the window's corners.
+ */
+ @JvmStatic
+ fun getLargeResizeCornerPixels(res: Resources): Int {
+ return try {
+ res.getDimensionPixelSize(R.dimen.desktop_mode_corner_resize_large)
+ } catch (e: Resources.NotFoundException) {
+ KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get large corner size", e)
+ 0
+ }
+ }
+
+ /**
+ * Returns the resource value, in pixels, to use for fine input, such as stylus, that can
+ * use a smaller square on each of the window's corners.
+ */
+ @JvmStatic
+ fun getFineResizeCornerPixels(res: Resources): Int {
+ return try {
+ res.getDimensionPixelSize(R.dimen.freeform_resize_corner)
+ } catch (e: Resources.NotFoundException) {
+ KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get fine corner size", e)
+ 0
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 5418254..2cbe472 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
@@ -145,9 +146,8 @@
DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
- SurfaceControl taskSurface,
- Configuration windowDecorConfig) {
- this(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig,
+ SurfaceControl taskSurface) {
+ this(context, displayController, taskOrganizer, taskInfo, taskSurface,
SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
WindowContainerTransaction::new, SurfaceControl::new,
new SurfaceControlViewHostFactory() {});
@@ -159,7 +159,6 @@
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
@NonNull SurfaceControl taskSurface,
- Configuration windowDecorConfig,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
@@ -176,8 +175,6 @@
mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
- mWindowDecorConfig = windowDecorConfig;
- mDecorWindowContext = mContext.createConfigurationContext(mWindowDecorConfig);
}
/**
@@ -220,8 +217,11 @@
outResult.mRootView = rootView;
rootView = null; // Clear it just in case we use it accidentally
- final int oldDensityDpi = mWindowDecorConfig.densityDpi;
- final int oldNightMode = mWindowDecorConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ final int oldDensityDpi = mWindowDecorConfig != null
+ ? mWindowDecorConfig.densityDpi : DENSITY_DPI_UNDEFINED;
+ final int oldNightMode = mWindowDecorConfig != null
+ ? (mWindowDecorConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ : Configuration.UI_MODE_NIGHT_UNDEFINED;
mWindowDecorConfig = params.mWindowDecorConfig != null ? params.mWindowDecorConfig
: mTaskInfo.getConfiguration();
final int newDensityDpi = mWindowDecorConfig.densityDpi;
@@ -230,7 +230,8 @@
|| mDisplay == null
|| mDisplay.getDisplayId() != mTaskInfo.displayId
|| oldLayoutResId != mLayoutResId
- || oldNightMode != newNightMode) {
+ || oldNightMode != newNightMode
+ || mDecorWindowContext == null) {
releaseViews(wct);
if (!obtainDisplayOrRegisterListener()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index 58bbb03..1c4b742 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -4,8 +4,11 @@
import android.app.ActivityManager.RunningTaskInfo
import android.content.res.ColorStateList
import android.content.res.Configuration
+import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.graphics.Bitmap
import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
import android.view.View
import android.view.View.OnLongClickListener
import android.widget.ImageButton
@@ -15,10 +18,13 @@
import androidx.core.view.isVisible
import com.android.internal.R.attr.materialColorOnSecondaryContainer
import com.android.internal.R.attr.materialColorOnSurface
+import com.android.internal.R.attr.materialColorOnSurfaceInverse
import com.android.internal.R.attr.materialColorSecondaryContainer
import com.android.internal.R.attr.materialColorSurfaceContainerHigh
import com.android.internal.R.attr.materialColorSurfaceContainerLow
import com.android.internal.R.attr.materialColorSurfaceDim
+import com.android.internal.R.attr.materialColorSurfaceInverse
+import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.windowdecor.MaximizeButtonView
import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance
@@ -71,6 +77,14 @@
}
override fun bindData(taskInfo: RunningTaskInfo) {
+ if (Flags.enableThemedAppHeaders()) {
+ bindDataWithThemedHeaders(taskInfo)
+ } else {
+ bindDataLegacy(taskInfo)
+ }
+ }
+
+ private fun bindDataLegacy(taskInfo: RunningTaskInfo) {
captionView.setBackgroundColor(getCaptionBackgroundColor(taskInfo))
val color = getAppNameAndButtonColor(taskInfo)
val alpha = Color.alpha(color)
@@ -87,6 +101,45 @@
maximizeButtonView.setAnimationTints(isDarkMode())
}
+ private fun bindDataWithThemedHeaders(taskInfo: RunningTaskInfo) {
+ val header = fillHeaderInfo(taskInfo)
+ val headerStyle = getHeaderStyle(header)
+
+ // Caption Background
+ val headerBackground = captionView.background as LayerDrawable
+ val backLayer = headerBackground.findDrawableByLayerId(R.id.backLayer) as GradientDrawable
+ val frontLayer = headerBackground.findDrawableByLayerId(R.id.frontLayer) as GradientDrawable
+ when (headerStyle.background) {
+ is HeaderStyle.Background.Opaque -> {
+ backLayer.setColor(headerStyle.background.backLayerColor ?: Color.BLACK)
+ frontLayer.setColor(headerStyle.background.frontLayerColor)
+ frontLayer.alpha = headerStyle.background.frontLayerOpacity
+ }
+ HeaderStyle.Background.Transparent -> {
+ backLayer.setColor(Color.TRANSPARENT)
+ frontLayer.setColor(Color.TRANSPARENT)
+ frontLayer.alpha = OPACITY_100
+ }
+ }
+
+ // Caption Foreground
+ val foregroundColor = headerStyle.foreground.color
+ val foregroundAlpha = headerStyle.foreground.opacity
+ val colorStateList = ColorStateList.valueOf(foregroundColor).withAlpha(foregroundAlpha)
+ closeWindowButton.imageTintList = colorStateList
+ expandMenuButton.imageTintList = colorStateList
+ with (appNameTextView) {
+ isVisible = header.type == Header.Type.DEFAULT
+ setTextColor(colorStateList)
+ }
+ appIconImageView.imageAlpha = foregroundAlpha
+ maximizeButtonView.setAnimationTints(
+ darkMode = header.appTheme == Header.Theme.DARK,
+ iconForegroundColor = colorStateList,
+ baseForegroundColor = foregroundColor
+ )
+ }
+
override fun onHandleMenuOpened() {}
override fun onHandleMenuClosed() {}
@@ -107,6 +160,273 @@
maximizeButtonView.startHoverAnimation()
}
+ private fun getHeaderStyle(header: Header): HeaderStyle {
+ return HeaderStyle(
+ background = getHeaderBackground(header),
+ foreground = getHeaderForeground(header)
+ )
+ }
+
+ private fun getHeaderBackground(
+ header: Header
+ ): HeaderStyle.Background {
+ when (header.type) {
+ Header.Type.DEFAULT -> {
+ if (header.systemTheme.isLight() && header.appTheme.isLight() && header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSecondaryContainer),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isLight() &&
+ !header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceContainerLow),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isDark() && header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceContainerHigh),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isDark() && !header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceDim),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isDark() && header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceInverse),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isDark() && !header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceInverse),
+ frontLayerOpacity = OPACITY_30,
+ backLayerColor = Color.BLACK
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isLight() && header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceInverse),
+ frontLayerOpacity = OPACITY_100,
+ backLayerColor = null
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isLight() && !header.isFocused) {
+ return HeaderStyle.Background.Opaque(
+ frontLayerColor = attrToColor(materialColorSurfaceInverse),
+ frontLayerOpacity = OPACITY_55,
+ backLayerColor = Color.WHITE
+ )
+ }
+ error("No other combination expected header=$header")
+ }
+ Header.Type.CUSTOM -> return HeaderStyle.Background.Transparent
+ }
+ }
+
+ private fun getHeaderForeground(header: Header): HeaderStyle.Foreground {
+ when (header.type) {
+ Header.Type.DEFAULT -> {
+ if (header.systemTheme.isLight() && header.appTheme.isLight() && header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSecondaryContainer),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isLight() &&
+ !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSecondaryContainer),
+ opacity = OPACITY_65
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isDark() && header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurface),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isDark() && !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurface),
+ opacity = OPACITY_55
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isDark() && header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isLight() && header.appTheme.isDark() && !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_65
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isLight() && header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isDark() && header.appTheme.isLight() && !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_70
+ )
+ }
+ error("No other combination expected header=$header")
+ }
+ Header.Type.CUSTOM -> {
+ if (header.systemTheme.isLight() && header.isAppearanceCaptionLight &&
+ header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSecondaryContainer),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isLight() && header.isAppearanceCaptionLight &&
+ !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSecondaryContainer),
+ opacity = OPACITY_65
+ )
+ }
+ if (header.systemTheme.isDark() && !header.isAppearanceCaptionLight &&
+ header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurface),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isDark() && !header.isAppearanceCaptionLight &&
+ !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurface),
+ opacity = OPACITY_55
+ )
+ }
+ if (header.systemTheme.isLight() && !header.isAppearanceCaptionLight &&
+ header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isLight() && !header.isAppearanceCaptionLight &&
+ !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_65
+ )
+ }
+ if (header.systemTheme.isDark() && header.isAppearanceCaptionLight &&
+ header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_100
+ )
+ }
+ if (header.systemTheme.isDark() && header.isAppearanceCaptionLight &&
+ !header.isFocused) {
+ return HeaderStyle.Foreground(
+ color = attrToColor(materialColorOnSurfaceInverse),
+ opacity = OPACITY_70
+ )
+ }
+ error("No other combination expected header=$header")
+ }
+ }
+ }
+
+ private fun fillHeaderInfo(taskInfo: RunningTaskInfo): Header {
+ return Header(
+ type = if (taskInfo.isTransparentCaptionBarAppearance) {
+ Header.Type.CUSTOM
+ } else {
+ Header.Type.DEFAULT
+ },
+ systemTheme = getSystemTheme(),
+ appTheme = getAppTheme(taskInfo),
+ isFocused = taskInfo.isFocused,
+ isAppearanceCaptionLight = taskInfo.isLightCaptionBarAppearance
+ )
+ }
+
+ private fun getSystemTheme(): Header.Theme {
+ return if ((context.resources.configuration.uiMode and UI_MODE_NIGHT_MASK) ==
+ Configuration.UI_MODE_NIGHT_YES) {
+ Header.Theme.DARK
+ } else {
+ Header.Theme.LIGHT
+ }
+ }
+
+ private fun getAppTheme(taskInfo: RunningTaskInfo): Header.Theme {
+ // TODO: use app's uiMode to find its actual light/dark value. It needs to be added to the
+ // TaskInfo/TaskDescription.
+ val backgroundColor = taskInfo.taskDescription?.backgroundColor ?: return getSystemTheme()
+ return if (Color.valueOf(backgroundColor).luminance() < 0.5) {
+ Header.Theme.DARK
+ } else {
+ Header.Theme.LIGHT
+ }
+ }
+
+ @ColorInt
+ private fun attrToColor(attr: Int): Int {
+ context.withStyledAttributes(null, intArrayOf(attr), 0, 0) {
+ return getColor(0, 0)
+ }
+ return Color.BLACK
+ }
+
+ data class Header(
+ val type: Type,
+ val systemTheme: Theme,
+ val appTheme: Theme,
+ val isFocused: Boolean,
+ val isAppearanceCaptionLight: Boolean,
+ ) {
+ enum class Type { DEFAULT, CUSTOM }
+ enum class Theme { LIGHT, DARK }
+ }
+
+ private fun Header.Theme.isLight(): Boolean = this == Header.Theme.LIGHT
+
+ private fun Header.Theme.isDark(): Boolean = this == Header.Theme.DARK
+
+ data class HeaderStyle(
+ val background: Background,
+ val foreground: Foreground
+ ) {
+ data class Foreground(
+ @ColorInt val color: Int,
+ val opacity: Int
+ )
+
+ sealed class Background {
+ data object Transparent : Background()
+ data class Opaque(
+ @ColorInt val frontLayerColor: Int,
+ val frontLayerOpacity: Int,
+ @ColorInt val backLayerColor: Int?
+ ) : Background()
+ }
+ }
+
@ColorInt
private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
if (taskInfo.isTransparentCaptionBarAppearance) {
@@ -171,8 +491,15 @@
companion object {
private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder"
+
private const val DARK_THEME_UNFOCUSED_OPACITY = 140 // 55%
private const val LIGHT_THEME_UNFOCUSED_OPACITY = 166 // 65%
private const val FOCUSED_OPACITY = 255
+
+ private const val OPACITY_100 = 255
+ private const val OPACITY_30 = 77
+ private const val OPACITY_55 = 140
+ private const val OPACITY_65 = 166
+ private const val OPACITY_70 = 179
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/service/Android.bp b/libs/WindowManager/Shell/tests/flicker/service/Android.bp
index 4f1a68a..a5bc261 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/service/Android.bp
@@ -65,6 +65,10 @@
package_name: "com.android.wm.shell.flicker.service",
instrumentation_target_package: "com.android.wm.shell.flicker.service",
test_config_template: "AndroidTestTemplate.xml",
+ test_suites: [
+ "device-tests",
+ "device-platinum-tests",
+ ],
srcs: [":WMShellFlickerServicePlatinumTests-src"],
static_libs: ["WMShellFlickerTestsBase"],
data: ["trace_config/*"],
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 8de60b7..cfe8e07 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -26,6 +26,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -115,9 +116,9 @@
@Test
public void testUpdateDivideBounds() {
- mSplitLayout.updateDividerBounds(anyInt());
+ mSplitLayout.updateDividerBounds(anyInt(), anyBoolean());
verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class), anyInt(),
- anyInt());
+ anyInt(), anyBoolean());
}
@Test
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 f67da55..d8d534b 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
@@ -25,6 +25,7 @@
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.content.Intent
import android.content.pm.ActivityInfo
+import android.content.pm.ActivityInfo.CONFIG_DENSITY
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
@@ -115,6 +116,8 @@
import org.mockito.kotlin.capture
import org.mockito.quality.Strictness
import java.util.Optional
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.mockito.Mockito.`when` as whenever
/**
@@ -1045,17 +1048,6 @@
}
@Test
- fun handleRequest_freeformTask_freeformVisible_returnNull() {
- assumeTrue(ENABLE_SHELL_TRANSITIONS)
-
- val freeformTask1 = setUpFreeformTask()
- markTaskVisible(freeformTask1)
-
- val freeformTask2 = createFreeformTask()
- assertThat(controller.handleRequest(Binder(), createTransition(freeformTask2))).isNull()
- }
-
- @Test
fun handleRequest_freeformTask_freeformVisible_aboveTaskLimit_minimize() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -1072,7 +1064,7 @@
}
@Test
- fun handleRequest_freeformTask_freeformNotVisible_returnSwitchToFullscreenWCT() {
+ fun handleRequest_freeformTask_freeformNotVisible_reorderedToTop() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
val freeformTask1 = setUpFreeformTask()
@@ -1084,30 +1076,60 @@
Binder(),
createTransition(freeformTask2, type = TRANSIT_TO_FRONT)
)
- assertThat(result?.changes?.get(freeformTask2.token.asBinder())?.windowingMode)
- .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+
+ assertThat(result?.hierarchyOps?.size).isEqualTo(2)
+ result!!.assertReorderAt(1, freeformTask2, toTop = true)
}
@Test
- fun handleRequest_freeformTask_noOtherTasks_returnSwitchToFullscreenWCT() {
+ fun handleRequest_freeformTask_noOtherTasks_reorderedToTop() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
val task = createFreeformTask()
val result = controller.handleRequest(Binder(), createTransition(task))
- assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
- .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+
+ assertThat(result?.hierarchyOps?.size).isEqualTo(1)
+ result!!.assertReorderAt(0, task, toTop = true)
}
@Test
- fun handleRequest_freeformTask_freeformOnOtherDisplayOnly_returnSwitchToFullscreenWCT() {
+ fun handleRequest_freeformTask_freeformOnOtherDisplayOnly_reorderedToTop() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
val taskDefaultDisplay = createFreeformTask(displayId = DEFAULT_DISPLAY)
- createFreeformTask(displayId = SECOND_DISPLAY)
+ val taskSecondDisplay = createFreeformTask(displayId = SECOND_DISPLAY)
val result = controller.handleRequest(Binder(), createTransition(taskDefaultDisplay))
- assertThat(result?.changes?.get(taskDefaultDisplay.token.asBinder())?.windowingMode)
- .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ assertThat(result?.hierarchyOps?.size).isEqualTo(1)
+ result!!.assertReorderAt(0, taskDefaultDisplay, toTop = true)
+ }
+
+ @Test
+ fun handleRequest_freeformTask_alreadyInDesktop_noOverrideDensity_noConfigDensityChange() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isDesktopDensityOverrideSet()).thenReturn(false)
+
+ val freeformTask1 = setUpFreeformTask()
+ markTaskVisible(freeformTask1)
+
+ val freeformTask2 = createFreeformTask()
+ val result = controller.handleRequest(freeformTask2.token.asBinder(),
+ createTransition(freeformTask2))
+ assertFalse(result.anyDensityConfigChange(freeformTask2.token))
+ }
+
+ @Test
+ fun handleRequest_freeformTask_alreadyInDesktop_overrideDensity_hasConfigDensityChange() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.isDesktopDensityOverrideSet()).thenReturn(true)
+
+ val freeformTask1 = setUpFreeformTask()
+ markTaskVisible(freeformTask1)
+
+ val freeformTask2 = createFreeformTask()
+ val result = controller.handleRequest(freeformTask2.token.asBinder(),
+ createTransition(freeformTask2))
+ assertTrue(result.anyDensityConfigChange(freeformTask2.token))
}
@Test
@@ -1811,3 +1833,11 @@
assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_PENDING_INTENT)
assertThat(op.pendingIntent?.intent?.component).isEqualTo(intent.component)
}
+
+private fun WindowContainerTransaction?.anyDensityConfigChange(
+ token: WindowContainerToken
+): Boolean {
+ return this?.changes?.any { change ->
+ change.key == token.asBinder() && ((change.value.configSetMask and CONFIG_DENSITY) != 0)
+ } ?: false
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 5dd9d8a..6e72e8d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -66,6 +66,7 @@
import android.os.RemoteException;
import android.view.DisplayInfo;
import android.view.DragEvent;
+import android.view.View;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -115,6 +116,7 @@
private DragAndDropPolicy mPolicy;
private ClipData mActivityClipData;
+ private PendingIntent mLaunchableIntentPendingIntent;
private ClipData mLaunchableIntentClipData;
private ClipData mNonResizeableActivityClipData;
private ClipData mTaskClipData;
@@ -151,7 +153,10 @@
mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
- mLaunchableIntentClipData = createIntentClipData();
+ mLaunchableIntentPendingIntent = mock(PendingIntent.class);
+ when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
+ .thenReturn(android.os.Process.myUserHandle());
+ mLaunchableIntentClipData = createIntentClipData(mLaunchableIntentPendingIntent);
mNonResizeableActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
mTaskClipData = createAppClipData(MIMETYPE_APPLICATION_TASK);
@@ -202,16 +207,13 @@
/**
* Creates an intent-based clip data that is by default resizeable.
*/
- private ClipData createIntentClipData() {
+ private ClipData createIntentClipData(PendingIntent intent) {
ClipDescription clipDescription = new ClipDescription("Intent",
new String[] { MIMETYPE_TEXT_INTENT });
- PendingIntent intent = mock(PendingIntent.class);
- when(intent.getCreatorUserHandle()).thenReturn(android.os.Process.myUserHandle());
ClipData.Item item = new ClipData.Item.Builder()
.setIntentSender(intent.getIntentSender())
.build();
ClipData data = new ClipData(clipDescription, item);
- when(DragUtils.getLaunchIntent((ClipData) any())).thenReturn(intent);
return data;
}
@@ -259,16 +261,22 @@
@Test
public void testDragIntentOverFullscreenHome_expectOnlyFullscreenTarget() {
+ when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+ mLaunchableIntentPendingIntent);
dragOverFullscreenHome_expectOnlyFullscreenTarget(mLaunchableIntentClipData);
}
@Test
public void testDragIntentOverFullscreenApp_expectSplitScreenTargets() {
+ when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+ mLaunchableIntentPendingIntent);
dragOverFullscreenApp_expectSplitScreenTargets(mLaunchableIntentClipData);
}
@Test
public void testDragIntentOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
+ when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+ mLaunchableIntentPendingIntent);
dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mLaunchableIntentClipData);
}
@@ -276,7 +284,7 @@
doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
setRunningTask(mHomeTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
- mLandscapeDisplayLayout, data);
+ mLandscapeDisplayLayout, data, 0 /* dragFlags */);
dragSession.update();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
@@ -291,7 +299,7 @@
doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
- mLandscapeDisplayLayout, data);
+ mLandscapeDisplayLayout, data, 0 /* dragFlags */);
dragSession.update();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
@@ -311,7 +319,7 @@
doReturn(false).when(mSplitScreenStarter).isLeftRightSplit();
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
- mPortraitDisplayLayout, data);
+ mPortraitDisplayLayout, data, 0 /* dragFlags */);
dragSession.update();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
@@ -331,7 +339,7 @@
public void testTargetHitRects() {
setRunningTask(mFullscreenAppTask);
DragSession dragSession = new DragSession(mActivityTaskManager,
- mLandscapeDisplayLayout, mActivityClipData);
+ mLandscapeDisplayLayout, mActivityClipData, 0 /* dragFlags */);
dragSession.update();
mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = mPolicy.getTargets(mInsets);
@@ -345,6 +353,11 @@
}
}
+ @Test
+ public void testDisallowLaunchIntentWithoutDelegationFlag() {
+ assertTrue(DragUtils.getLaunchIntent(mLaunchableIntentClipData, 0) == null);
+ }
+
private Target filterTargetByType(ArrayList<Target> targets, int type) {
for (Target t : targets) {
if (type == t.type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
index e731b06..d410151 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
@@ -74,7 +74,7 @@
@Test
fun onUnhandledDrop_noListener_expectNotifyUnhandled() {
// Simulate an unhandled drop
- val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, null, null, null,
+ val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, 0, null, null, null,
null, null, false)
val wmCallback = mock<IUnhandledDragCallback>()
mController.onUnhandledDrop(dropEvent, wmCallback)
@@ -98,7 +98,7 @@
// Simulate an unhandled drop
val dragSurface = mock<SurfaceControl>()
- val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, null, null, null,
+ val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, 0, null, null, null,
dragSurface, null, false)
val wmCallback = mock<IUnhandledDragCallback>()
mController.onUnhandledDrop(dropEvent, wmCallback)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipTransitionStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipTransitionStateTest.java
index bd8ac37..f3f3c37 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipTransitionStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipTransitionStateTest.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip2;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Parcelable;
import android.testing.AndroidTestingRunner;
@@ -29,6 +30,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
/**
* Unit test against {@link PhoneSizeSpecSource}.
@@ -42,9 +44,12 @@
private PipTransitionState.PipTransitionStateChangedListener mStateChangedListener;
private Parcelable mEmptyParcelable;
+ @Mock
+ private Handler mMainHandler;
+
@Before
public void setUp() {
- mPipTransitionState = new PipTransitionState();
+ mPipTransitionState = new PipTransitionState(mMainHandler);
mPipTransitionState.setState(PipTransitionState.UNDEFINED);
mEmptyParcelable = new Bundle();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index d7c3835..d18fec2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -16,10 +16,7 @@
package com.android.wm.shell.splitscreen;
-import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
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;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -31,8 +28,9 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
@@ -45,6 +43,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -54,7 +53,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.RemoteTransition;
-import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.annotation.UiThreadTest;
@@ -343,14 +341,14 @@
@Test
public void testAddActivityOptions_addsBackgroundActivitiesFlags() {
- Bundle options = mStageCoordinator.resolveStartStage(STAGE_TYPE_MAIN,
+ Bundle bundle = mStageCoordinator.resolveStartStage(STAGE_TYPE_MAIN,
SPLIT_POSITION_UNDEFINED, null /* options */, null /* wct */);
+ ActivityOptions options = ActivityOptions.fromBundle(bundle);
- assertEquals(options.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, WindowContainerToken.class),
- mMainStage.mRootTaskInfo.token);
- assertTrue(options.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED));
- assertTrue(options.getBoolean(
- KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION));
+ assertThat(options.getLaunchRootTask()).isEqualTo(mMainStage.mRootTaskInfo.token);
+ assertThat(options.getPendingIntentBackgroundActivityStartMode())
+ .isEqualTo(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission()).isTrue();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index aa2cee7..282495d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -121,6 +121,7 @@
@Mock private lateinit var mockShellController: ShellController
@Mock private lateinit var mockShellExecutor: ShellExecutor
@Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ @Mock private lateinit var mockResizeHandleSizeRepository: ResizeHandleSizeRepository
@Mock private lateinit var mockShellCommandHandler: ShellCommandHandler
@Mock private lateinit var mockWindowManager: IWindowManager
@@ -156,7 +157,8 @@
mockInputMonitorFactory,
transactionFactory,
mockRootTaskDisplayAreaOrganizer,
- windowDecorByTaskIdSpy
+ windowDecorByTaskIdSpy,
+ mockResizeHandleSizeRepository
)
whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
@@ -197,7 +199,8 @@
mockMainHandler,
mockMainChoreographer,
mockSyncQueue,
- mockRootTaskDisplayAreaOrganizer
+ mockRootTaskDisplayAreaOrganizer,
+ mockResizeHandleSizeRepository
)
verify(decoration).close()
}
@@ -221,7 +224,8 @@
mockMainHandler,
mockMainChoreographer,
mockSyncQueue,
- mockRootTaskDisplayAreaOrganizer
+ mockRootTaskDisplayAreaOrganizer,
+ mockResizeHandleSizeRepository
)
task.setWindowingMode(WINDOWING_MODE_FREEFORM)
@@ -236,7 +240,8 @@
mockMainHandler,
mockMainChoreographer,
mockSyncQueue,
- mockRootTaskDisplayAreaOrganizer
+ mockRootTaskDisplayAreaOrganizer,
+ mockResizeHandleSizeRepository
)
}
@@ -296,7 +301,7 @@
onTaskChanging(task)
verify(mockDesktopModeWindowDecorFactory, never())
- .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
}
@Test
@@ -309,7 +314,7 @@
onTaskOpening(task)
verify(mockDesktopModeWindowDecorFactory, never())
- .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
}
@Test
@@ -406,7 +411,7 @@
onTaskOpening(task)
verify(mockDesktopModeWindowDecorFactory, never())
- .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
} finally {
mockitoSession.finishMocking()
}
@@ -430,7 +435,7 @@
onTaskOpening(task)
verify(mockDesktopModeWindowDecorFactory)
- .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
} finally {
mockitoSession.finishMocking()
}
@@ -453,7 +458,7 @@
onTaskOpening(task)
verify(mockDesktopModeWindowDecorFactory)
- .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
} finally {
mockitoSession.finishMocking()
}
@@ -497,7 +502,7 @@
val decoration = mock(DesktopModeWindowDecoration::class.java)
whenever(
mockDesktopModeWindowDecorFactory.create(
- any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+ any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
).thenReturn(decoration)
decoration.mTaskInfo = task
whenever(decoration.isFocused).thenReturn(task.isFocused)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 608f74b..e737861 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
import static com.google.common.truth.Truth.assertThat;
@@ -39,6 +40,9 @@
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.SystemProperties;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.view.Choreographer;
@@ -51,6 +55,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
@@ -61,6 +66,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -83,6 +89,8 @@
private static final String USE_ROUNDED_CORNERS_SYSPROP_KEY =
"persist.wm.debug.desktop_use_rounded_corners";
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
@Mock
private DisplayController mMockDisplayController;
@Mock
@@ -107,6 +115,8 @@
private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
@Mock
private TypedArray mMockRoundedCornersRadiusArray;
+ @Mock
+ private ResizeHandleSizeRepository mMockResizeHandleSizeRepository;
private final Configuration mConfiguration = new Configuration();
@@ -175,6 +185,48 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
+ public void updateRelayoutParams_appHeader_usesTaskDensity() {
+ final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
+ .getConfiguration().densityDpi;
+ final int customTaskDensity = systemDensity + 300;
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ taskInfo.configuration.densityDpi = customTaskDensity;
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(customTaskDensity);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
+ public void updateRelayoutParams_appHeader_usesSystemDensity() {
+ final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
+ .getConfiguration().densityDpi;
+ final int customTaskDensity = systemDensity + 300;
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ taskInfo.configuration.densityDpi = customTaskDensity;
+ final RelayoutParams relayoutParams = new RelayoutParams();
+
+ DesktopModeWindowDecoration.updateRelayoutParams(
+ relayoutParams,
+ mTestableContext,
+ taskInfo,
+ /* applyStartTransactionOnDraw= */ true,
+ /* shouldSetTaskPositionAndCrop */ false);
+
+ assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(systemDensity);
+ }
+
+ @Test
public void updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -294,10 +346,10 @@
private DesktopModeWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo) {
return new DesktopModeWindowDecoration(mContext, mMockDisplayController,
- mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mConfiguration,
+ mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl,
mMockHandler, mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer,
- SurfaceControl.Builder::new, mMockTransactionSupplier,
- WindowContainerTransaction::new, SurfaceControl::new,
+ mMockResizeHandleSizeRepository, SurfaceControl.Builder::new,
+ mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
mMockSurfaceControlViewHostFactory);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index 5464508..62fb1c4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -27,10 +27,7 @@
import android.annotation.NonNull;
import android.graphics.Point;
import android.graphics.Region;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.util.Size;
@@ -74,7 +71,7 @@
TASK_SIZE.getHeight() + EDGE_RESIZE_THICKNESS / 2);
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
/**
* Check that both groups of objects satisfy equals/hashcode within each group, and that each
@@ -147,8 +144,8 @@
* capture all eligible input regardless of source (touch or cursor).
*/
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
Region region = new Region();
GEOMETRY.union(region);
// Make sure we're choosing a point outside of any debug region buffer.
@@ -164,8 +161,8 @@
* size.
*/
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
Region region = new Region();
GEOMETRY.union(region);
final int cornerRadius = DragResizeWindowGeometry.DEBUG
@@ -176,16 +173,16 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testCalculateControlType_edgeDragResizeEnabled_edges() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
// The input source (touch or cursor) shouldn't impact the edge resize size.
validateCtrlTypeForEdges(/* isTouch= */ false);
validateCtrlTypeForEdges(/* isTouch= */ true);
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testCalculateControlType_edgeDragResizeDisabled_edges() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
// Edge resizing is not supported when the flag is disabled.
validateCtrlTypeForEdges(/* isTouch= */ false);
validateCtrlTypeForEdges(/* isTouch= */ false);
@@ -203,8 +200,8 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testCalculateControlType_edgeDragResizeEnabled_corners() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);
@@ -226,8 +223,8 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testCalculateControlType_edgeDragResizeDisabled_corners() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt
new file mode 100644
index 0000000..a9fddc6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.windowdecor
+
+import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import java.util.function.Consumer
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameter
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for {@link ResizeHandleSizeRepository}.
+ *
+ * Build/Install/Run: atest WMShellUnitTests:ResizeHandleSizeRepositoryParameterizedTests
+ */
+@SmallTest
+@RunWith(Parameterized::class)
+class ResizeHandleSizeRepositoryParameterizedTests {
+ private val resources = ApplicationProvider.getApplicationContext<Context>().resources
+ private val resizeHandleSizeRepository = ResizeHandleSizeRepository()
+ @Mock private lateinit var mockSizeChangeFunctionOne: Consumer<ResizeHandleSizeRepository>
+ @Mock private lateinit var mockSizeChangeFunctionTwo: Consumer<ResizeHandleSizeRepository>
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ @Parameter(0) lateinit var name: String
+ // The current ResizeHandleSizeRepository API under test.
+
+ @Parameter(1) lateinit var operation: (ResizeHandleSizeRepository) -> Unit
+
+ @Before
+ fun setOverrideBeforeResetResizeHandle() {
+ MockitoAnnotations.initMocks(this)
+ if (name != "reset") return
+ val originalEdgeHandle =
+ resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+ resizeHandleSizeRepository.setResizeEdgeHandlePixels(originalEdgeHandle + 2)
+ }
+
+ companion object {
+ @Parameters(name = "{index}: {0}")
+ @JvmStatic
+ fun data(): Iterable<Array<Any>> {
+ return listOf(
+ arrayOf(
+ "reset",
+ { sizeRepository: ResizeHandleSizeRepository ->
+ sizeRepository.resetResizeEdgeHandlePixels()
+ }
+ ),
+ arrayOf(
+ "set",
+ { sizeRepository: ResizeHandleSizeRepository ->
+ sizeRepository.setResizeEdgeHandlePixels(99)
+ }
+ )
+ )
+ }
+ }
+
+ // =================
+ // Validate that listeners are notified correctly for reset resize handle API.
+ // =================
+
+ @Test
+ fun testUpdateResizeHandleSize_flagDisabled() {
+ setFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ registerSizeChangeFunctions()
+ operation.invoke(resizeHandleSizeRepository)
+ // Nothing is notified since flag is disabled.
+ verify(mockSizeChangeFunctionOne, never()).accept(any())
+ verify(mockSizeChangeFunctionTwo, never()).accept(any())
+ }
+
+ @Test
+ fun testUpdateResizeHandleSize_flagEnabled_noListeners() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ operation.invoke(resizeHandleSizeRepository)
+ // Nothing is notified since nothing was registered.
+ verify(mockSizeChangeFunctionOne, never()).accept(any())
+ verify(mockSizeChangeFunctionTwo, never()).accept(any())
+ }
+
+ @Test
+ fun testUpdateResizeHandleSize_flagEnabled_listenersNotified() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ registerSizeChangeFunctions()
+ operation.invoke(resizeHandleSizeRepository)
+ // Functions notified when reset.
+ verify(mockSizeChangeFunctionOne).accept(any())
+ verify(mockSizeChangeFunctionTwo).accept(any())
+ }
+
+ @Test
+ fun testUpdateResizeHandleSize_flagEnabled_listenerFails() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ registerSizeChangeFunctions()
+ operation.invoke(resizeHandleSizeRepository)
+ // Functions notified when reset.
+ verify(mockSizeChangeFunctionOne).accept(any())
+ verify(mockSizeChangeFunctionTwo).accept(any())
+ }
+
+ @Test
+ fun testUpdateResizeHandleSize_flagEnabled_ignoreSecondListener() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ registerSizeChangeFunctions()
+ val extraConsumerMock = mock(Consumer::class.java) as Consumer<ResizeHandleSizeRepository>
+ resizeHandleSizeRepository.registerSizeChangeFunction(extraConsumerMock)
+ // First listener succeeds, second one that fails is ignored.
+ operation.invoke(resizeHandleSizeRepository)
+ // Functions notified when reset.
+ verify(mockSizeChangeFunctionOne).accept(any())
+ verify(mockSizeChangeFunctionTwo).accept(any())
+ verify(extraConsumerMock).accept(any())
+ }
+
+ private fun registerSizeChangeFunctions() {
+ resizeHandleSizeRepository.registerSizeChangeFunction(mockSizeChangeFunctionOne)
+ resizeHandleSizeRepository.registerSizeChangeFunction(mockSizeChangeFunctionTwo)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt
new file mode 100644
index 0000000..59bbc72
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.windowdecor
+
+import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for {@link ResizeHandleSizeRepository}. Validate that get/reset/set work correctly.
+ *
+ * Build/Install/Run: atest WMShellUnitTests:ResizeHandleSizeRepositoryTests
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ResizeHandleSizeRepositoryTests {
+ private val resources = ApplicationProvider.getApplicationContext<Context>().resources
+ private val resizeHandleSizeRepository = ResizeHandleSizeRepository()
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ @Test
+ fun testOverrideResizeEdgeHandlePixels_flagEnabled_resetSucceeds() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ // Reset does nothing when no override is set.
+ val originalEdgeHandle =
+ resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+ resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+ assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+ .isEqualTo(originalEdgeHandle)
+
+ // Now try to set the value; reset should succeed.
+ resizeHandleSizeRepository.setResizeEdgeHandlePixels(originalEdgeHandle + 2)
+ resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+ assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+ .isEqualTo(originalEdgeHandle)
+ }
+
+ @Test
+ fun testOverrideResizeEdgeHandlePixels_flagDisabled_resetFails() {
+ setFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+ // Reset does nothing when no override is set.
+ val originalEdgeHandle =
+ resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+ resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+ assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+ .isEqualTo(originalEdgeHandle)
+
+ // Now try to set the value; reset should do nothing.
+ val newEdgeHandle = originalEdgeHandle + 2
+ resizeHandleSizeRepository.setResizeEdgeHandlePixels(newEdgeHandle)
+ resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+ assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+ .isEqualTo(originalEdgeHandle)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 8b8cd11..4831081 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -49,7 +49,6 @@
import android.app.ActivityManager;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
@@ -134,7 +133,6 @@
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
- private Configuration mWindowConfiguration = new Configuration();
private int mCaptionMenuWidthId;
@Before
@@ -303,7 +301,6 @@
taskInfo.isFocused = true;
// Density is 2. Shadow radius is 10px. Caption height is 64px.
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mWindowConfiguration.densityDpi = taskInfo.configuration.densityDpi;
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
@@ -314,14 +311,16 @@
verify(mMockWindowContainerTransaction, never())
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
+ final SurfaceControl.Transaction t2 = mock(SurfaceControl.Transaction.class);
+ mMockSurfaceControlTransactions.add(t2);
taskInfo.isVisible = false;
windowDecor.relayout(taskInfo);
- final InOrder releaseOrder = inOrder(t, mMockSurfaceControlViewHost);
+ final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost);
releaseOrder.verify(mMockSurfaceControlViewHost).release();
- releaseOrder.verify(t).remove(captionContainerSurface);
- releaseOrder.verify(t).remove(decorContainerSurface);
- releaseOrder.verify(t).apply();
+ releaseOrder.verify(t2).remove(captionContainerSurface);
+ releaseOrder.verify(t2).remove(decorContainerSurface);
+ releaseOrder.verify(t2).apply();
// Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
verify(mMockWindowContainerTransaction, Mockito.times(2))
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
@@ -836,7 +835,7 @@
private TestWindowDecoration createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo) {
return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
- taskInfo, mMockTaskSurface, mWindowConfiguration,
+ taskInfo, mMockTaskSurface,
new MockObjectSupplier<>(mMockSurfaceControlBuilders,
() -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
new MockObjectSupplier<>(mMockSurfaceControlTransactions,
@@ -877,16 +876,15 @@
TestWindowDecoration(Context context, DisplayController displayController,
ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
- Configuration windowConfiguration,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
super(context, displayController, taskOrganizer, taskInfo, taskSurface,
- windowConfiguration, surfaceControlBuilderSupplier,
- surfaceControlTransactionSupplier, windowContainerTransactionSupplier,
- surfaceControlSupplier, surfaceControlViewHostFactory);
+ surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
+ windowContainerTransactionSupplier, surfaceControlSupplier,
+ surfaceControlViewHostFactory);
}
@Override
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 3d0a534..785aef3 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -688,8 +688,8 @@
static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
jobject padding, jobject bitmapFactoryOptions, jlong inBitmapHandle, jlong colorSpaceHandle) {
-#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
- return nullObjectReturn("Not supported on Windows");
+#ifdef _WIN32 // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
+ return nullObjectReturn("Not supported on Windows");
#else
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index e2dddad..85bc8ef 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -36,6 +36,5 @@
* Call MediaRouterService#requestCreateSessionWithRouter2 to pass the result.
*/
void requestCreateSessionByManager(long uniqueRequestId, in RoutingSessionInfo oldSession,
- in MediaRoute2Info route, in UserHandle transferInitiatorUserHandle,
- in String transferInitiatorPackageName);
+ in MediaRoute2Info route);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 63cb945..efbf8da 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -64,8 +64,7 @@
void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, long managerRequestId,
in RoutingSessionInfo oldSession, in MediaRoute2Info route,
- in @nullable Bundle sessionHints, in UserHandle transferInitiatorUserHandle,
- in String transferInitiatorPackageName);
+ in @nullable Bundle sessionHints);
void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
diff --git a/media/java/android/media/LoudnessCodecDispatcher.java b/media/java/android/media/LoudnessCodecDispatcher.java
index fa08658..bdd3c73 100644
--- a/media/java/android/media/LoudnessCodecDispatcher.java
+++ b/media/java/android/media/LoudnessCodecDispatcher.java
@@ -16,6 +16,9 @@
package android.media;
+import static android.media.MediaFormat.KEY_AAC_DRC_ALBUM_MODE;
+import static android.media.MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR;
+import static android.media.MediaFormat.KEY_AAC_DRC_BOOST_FACTOR;
import static android.media.MediaFormat.KEY_AAC_DRC_EFFECT_TYPE;
import static android.media.MediaFormat.KEY_AAC_DRC_HEAVY_COMPRESSION;
import static android.media.MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL;
@@ -142,6 +145,18 @@
filteredBundle.putInt(KEY_AAC_DRC_EFFECT_TYPE,
bundle.getInt(KEY_AAC_DRC_EFFECT_TYPE));
}
+ if (bundle.containsKey(KEY_AAC_DRC_BOOST_FACTOR)) {
+ filteredBundle.putInt(KEY_AAC_DRC_BOOST_FACTOR,
+ bundle.getInt(KEY_AAC_DRC_BOOST_FACTOR));
+ }
+ if (bundle.containsKey(KEY_AAC_DRC_ATTENUATION_FACTOR)) {
+ filteredBundle.putInt(KEY_AAC_DRC_ATTENUATION_FACTOR,
+ bundle.getInt(KEY_AAC_DRC_ATTENUATION_FACTOR));
+ }
+ if (bundle.containsKey(KEY_AAC_DRC_ALBUM_MODE)) {
+ filteredBundle.putInt(KEY_AAC_DRC_ALBUM_MODE,
+ bundle.getInt(KEY_AAC_DRC_ALBUM_MODE));
+ }
return filteredBundle;
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 7ddf11e..679e8a1 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -991,9 +991,7 @@
void requestCreateController(
@NonNull RoutingController controller,
@NonNull MediaRoute2Info route,
- long managerRequestId,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
+ long managerRequestId) {
final int requestId = mNextRequestId.getAndIncrement();
@@ -1022,9 +1020,7 @@
managerRequestId,
controller.getRoutingSessionInfo(),
route,
- controllerHints,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ controllerHints);
} catch (RemoteException ex) {
Log.e(TAG, "createControllerForTransfer: "
+ "Failed to request for creating a controller.", ex);
@@ -1366,11 +1362,7 @@
}
void onRequestCreateControllerByManagerOnHandler(
- RoutingSessionInfo oldSession,
- MediaRoute2Info route,
- long managerRequestId,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName) {
+ RoutingSessionInfo oldSession, MediaRoute2Info route, long managerRequestId) {
Log.i(
TAG,
TextUtils.formatSimple(
@@ -1387,8 +1379,7 @@
if (controller == null) {
return;
}
- requestCreateController(controller, route, managerRequestId, transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ requestCreateController(controller, route, managerRequestId);
}
private List<MediaRoute2Info> getSortedRoutes(
@@ -2423,20 +2414,14 @@
@Override
public void requestCreateSessionByManager(
- long managerRequestId,
- RoutingSessionInfo oldSession,
- MediaRoute2Info route,
- UserHandle transferInitiatorUserHandle,
- String transferInitiatorPackageName) {
+ long managerRequestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
mHandler.sendMessage(
obtainMessage(
MediaRouter2::onRequestCreateControllerByManagerOnHandler,
MediaRouter2.this,
oldSession,
route,
- managerRequestId,
- transferInitiatorUserHandle,
- transferInitiatorPackageName));
+ managerRequestId));
}
}
@@ -3581,12 +3566,7 @@
RoutingController controller = getCurrentController();
if (!controller.tryTransferWithinProvider(route)) {
- requestCreateController(
- controller,
- route,
- MANAGER_REQUEST_ID_NONE,
- Process.myUserHandle(),
- mContext.getPackageName());
+ requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE);
}
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 223b432c..4059291 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -109,7 +109,7 @@
try {
final Callback c = Objects.requireNonNull(callback);
if (handler == null) {
- handler = new Handler();
+ handler = new Handler(mContext.getMainLooper());
}
mCallbacks.put(c, new CallbackRecord(c, handler));
} catch (NullPointerException e) {
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index a488756..70462ef 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -614,12 +614,11 @@
}
/**
- * Override to handle changes to the audio info.
+ * Signals a change in the session's {@link PlaybackInfo PlaybackInfo}.
*
- * @param info The current audio info for this session.
+ * @param playbackInfo The latest known state of the session's playback info.
*/
- public void onAudioInfoChanged(PlaybackInfo info) {
- }
+ public void onAudioInfoChanged(@NonNull PlaybackInfo playbackInfo) {}
}
/**
@@ -1182,7 +1181,7 @@
}
@Override
- public void onVolumeInfoChanged(PlaybackInfo info) {
+ public void onVolumeInfoChanged(@NonNull PlaybackInfo info) {
MediaController controller = mController.get();
if (controller != null) {
controller.postMessage(MSG_UPDATE_VOLUME, info, null);
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 83056b2..02d72ad 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -60,7 +60,7 @@
APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
int64_t initialTargetWorkDurationNanos,
- hal::SessionTag tag = hal::SessionTag::OTHER);
+ hal::SessionTag tag = hal::SessionTag::APP);
int64_t getPreferredRateNanos() const;
private:
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 7cd7e7ab..7150b54 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -91,7 +91,7 @@
boolean enableReaderOption(boolean enable);
boolean isObserveModeSupported();
boolean isObserveModeEnabled();
- boolean setObserveMode(boolean enabled);
+ boolean setObserveMode(boolean enabled, String pkg);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
boolean setWlcEnabled(boolean enable);
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 06098de..698df28 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -1268,8 +1268,12 @@
@FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
public boolean setObserveModeEnabled(boolean enabled) {
+ if (mContext == null) {
+ throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ + " observe mode APIs");
+ }
try {
- return sService.setObserveMode(enabled);
+ return sService.setObserveMode(enabled, mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
return false;
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index d2df0e4..e3dd4cb 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -70,7 +70,7 @@
<string name="permission_contacts_summary" msgid="2840800622763086808">"الوصول إلى جهات اتصالك"</string>
<string name="permission_calendar_summary" msgid="8430353935747336165">"الوصول إلى تقويمك"</string>
<string name="permission_microphone_summary" msgid="4862628553869973259">"تسجيل الصوت"</string>
- <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"يمكن العثور على الموضع النسبي للأجهزة المجاورة والربط بها وتحديدها."</string>
+ <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"يمكن العثور على الأجهزة المجاورة والربط بها وتحديد موقعها النسبي."</string>
<string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string>
<string name="permission_notifications_summary" msgid="2272810466047367030">"• قراءة كل الإشعارات بما فيها المعلومات، مثل جهات الاتصال والرسائل والصور<br/>• إرسال الإشعارات<br/><br/>يمكنك إدارة الإذن الممنوح لهذا التطبيق بقراءة الإشعارات وإرسالها في أي وقت من خلال الإعدادات > الإشعارات."</string>
<string name="permission_app_streaming_summary" msgid="606923325679670624">"بث تطبيقات هاتفك"</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
index bf81d3f..f98908c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
@@ -211,7 +211,10 @@
// Start discovery services if needed.
if (!mRequest.isSelfManaged()) {
- CompanionDeviceDiscoveryService.startForRequest(this, mRequest);
+ boolean started = CompanionDeviceDiscoveryService.startForRequest(this, mRequest);
+ if (!started) {
+ return;
+ }
// TODO(b/217749191): Create the ViewModel for the LiveData
CompanionDeviceDiscoveryService.getDiscoveryState().observe(
/* LifeCycleOwner */ this, this::onDiscoveryStateChanged);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index a5bb34f..e809433 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -60,6 +60,8 @@
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -88,6 +90,9 @@
new MutableLiveData<>(Collections.emptyList());
private static MutableLiveData<DiscoveryState> sStateLiveData =
new MutableLiveData<>(DiscoveryState.NOT_STARTED);
+ private static final Object LOCK = new Object();
+ @GuardedBy("LOCK")
+ private static boolean sDiscoveryStarted = false;
private BluetoothManager mBtManager;
private BluetoothAdapter mBtAdapter;
@@ -98,8 +103,6 @@
private BluetoothBroadcastReceiver mBtReceiver;
private WifiBroadcastReceiver mWifiReceiver;
- private boolean mDiscoveryStarted = false;
- private boolean mDiscoveryStopped = false;
private final List<DeviceFilterPair<?>> mDevicesFound = new ArrayList<>();
private final Runnable mTimeoutRunnable = this::timeout;
@@ -111,22 +114,27 @@
*/
enum DiscoveryState {
NOT_STARTED,
- STARTING,
- DISCOVERY_IN_PROGRESS,
+ IN_PROGRESS,
FINISHED_STOPPED,
FINISHED_TIMEOUT
}
- static void startForRequest(
+ static boolean startForRequest(
@NonNull Context context, @NonNull AssociationRequest associationRequest) {
+ synchronized (LOCK) {
+ if (sDiscoveryStarted) {
+ Slog.e(TAG, "Discovery is already started. Ignoring this request...");
+ return false;
+ }
+ }
requireNonNull(associationRequest);
final Intent intent = new Intent(context, CompanionDeviceDiscoveryService.class);
intent.setAction(ACTION_START_DISCOVERY);
intent.putExtra(EXTRA_ASSOCIATION_REQUEST, associationRequest);
- sStateLiveData.setValue(DiscoveryState.STARTING);
- sScanResultsLiveData.setValue(Collections.emptyList());
context.startService(intent);
+
+ return true;
}
static void stop(@NonNull Context context) {
@@ -176,10 +184,16 @@
Slog.d(TAG, "startDiscovery() request=" + request);
requireNonNull(request);
- if (mDiscoveryStarted) throw new RuntimeException("Discovery in progress.");
+ synchronized (LOCK) {
+ if (sDiscoveryStarted) {
+ Slog.e(TAG, "Discovery is already started. Returning...");
+ return;
+ }
+ sDiscoveryStarted = true;
+ }
mStopAfterFirstMatch = request.isSingleDevice();
- mDiscoveryStarted = true;
- sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
+ sScanResultsLiveData.setValue(Collections.emptyList());
+ sStateLiveData.setValue(DiscoveryState.IN_PROGRESS);
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
final List<BluetoothDeviceFilter> btFilters =
@@ -211,14 +225,13 @@
private void stopDiscoveryAndFinish(boolean timeout) {
Slog.d(TAG, "stopDiscoveryAndFinish(" + timeout + ")");
- if (!mDiscoveryStarted) {
- stopSelf();
- return;
+ synchronized (LOCK) {
+ if (!sDiscoveryStarted) {
+ stopSelf();
+ return;
+ }
}
- if (mDiscoveryStopped) return;
- mDiscoveryStopped = true;
-
// Stop BT discovery.
if (mBtReceiver != null) {
// Cancel discovery.
@@ -249,6 +262,10 @@
sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
}
+ synchronized (LOCK) {
+ sDiscoveryStarted = false;
+ }
+
// "Finish".
stopSelf();
}
@@ -340,7 +357,9 @@
private void onDeviceFound(@NonNull DeviceFilterPair<?> device) {
runOnMainThread(() -> {
- if (mDiscoveryStopped) return;
+ synchronized (LOCK) {
+ if (!sDiscoveryStarted) return;
+ }
if (mDevicesFound.contains(device)) {
// TODO: update the device instead of ignoring (new found device may contain
// additional/updated info, eg. name of the device).
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index 7b8093e..d9715ee 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -48,7 +48,7 @@
<string name="passwords" msgid="5419394230391253816">"mots de passe"</string>
<string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
<string name="sign_in_info" msgid="2627704710674232328">"renseignements de connexion"</string>
- <string name="save_credential_to_title" msgid="3172811692275634301">"Enregistrer la <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> dans"</string>
+ <string name="save_credential_to_title" msgid="3172811692275634301">"Enregistrer le <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> dans"</string>
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Créer une clé d\'accès sur un autre appareil?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Enregistrer le mot de passe sur un autre appareil?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Enregistrer l\'authentifiant de connexion sur un autre appareil?"</string>
@@ -57,9 +57,9 @@
<string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
<string name="settings" msgid="6536394145760913145">"Paramètres"</string>
<string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
- <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> clés d\'accès"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mot(s) de passe • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clé(s) d\'accès"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mot(s) de passe"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> clé(s) d\'accès"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g> authentifiants"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Clé d\'accès"</string>
<string name="another_device" msgid="5147276802037801217">"Un autre appareil"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index 3ec7da3..630a08a 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -24,15 +24,15 @@
<string name="string_learn_more" msgid="4541600451688392447">"Իմանալ ավելին"</string>
<string name="content_description_show_password" msgid="3283502010388521607">"Ցուցադրել գաղտնաբառը"</string>
<string name="content_description_hide_password" msgid="6841375971631767996">"Թաքցնել գաղտնաբառը"</string>
- <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Անցաբառերի հետ ավելի ապահով է"</string>
- <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Անցաբառերի շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string>
- <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Անցաբառերը գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string>
+ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Մուտքի բանալիների հետ ավելի ապահով է"</string>
+ <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Մուտքի բանալիների շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string>
+ <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Մուտքի բանալիները գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ մուտքի բանալիները պահվում են գաղտնաբառերի կառավարիչում"</string>
<string name="more_about_passkeys_title" msgid="7797903098728837795">"Ավելին՝ մուտքի բանալիների մասին"</string>
<string name="passwordless_technology_title" msgid="2497513482056606668">"Գաղտնաբառեր չպահանջող տեխնոլոգիա"</string>
<string name="passwordless_technology_detail" msgid="6853928846532955882">"Մուտքի բանալիները ձեզ թույլ են տալիս մուտք գործել առանց գաղտնաբառերի։ Ձեզ պարզապես հարկավոր է օգտագործել ձեր մատնահետքը, դիմաճանաչումը, PIN կոդը կամ նախշը՝ ձեր ինքնությունը հաստատելու և մուտքի բանալի ստեղծելու համար։"</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Բաց բանալու կրիպտոգրաֆիա"</string>
- <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Ըստ FIDO դաշինքի (որը ներառում է Google-ը, Apple-ը, Microsoft-ը և այլ ընկերություններ) և W3C ստանդարտների՝ անցաբառերն օգտագործում են կրիպտոգրաֆիկ բանալիների զույգ։ Օգտանվան և գաղտնաբառի փոխարեն հավելվածի կամ կայքի համար մենք ստեղծում ենք բաց-փակ բանալիների զույգ։ Փակ բանալին ապահով պահվում է ձեր սարքում կամ գաղտնաբառերի կառավարիչում և հաստատում է ձեր ինքնությունը։ Բաց բանալին փոխանցվում է հավելվածի կամ կայքի սերվերին։ Համապատասխան բանալիների միջոցով կարող եք ակնթարթորեն գրանցվել և մուտք գործել։"</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Ըստ FIDO դաշինքի (որը ներառում է Google-ը, Apple-ը, Microsoft-ը և այլ ընկերություններ) և W3C ստանդարտների՝ մուտքի բանալիներն օգտագործում են կրիպտոգրաֆիկ բանալիների զույգ։ Օգտանվան և գաղտնաբառի փոխարեն հավելվածի կամ կայքի համար մենք ստեղծում ենք բաց-փակ բանալիների զույգ։ Փակ բանալին ապահով պահվում է ձեր սարքում կամ գաղտնաբառերի կառավարիչում և հաստատում է ձեր ինքնությունը։ Բաց բանալին փոխանցվում է հավելվածի կամ կայքի սերվերին։ Համապատասխան բանալիների միջոցով կարող եք ակնթարթորեն գրանցվել և մուտք գործել։"</string>
<string name="improved_account_security_title" msgid="1069841917893513424">"Հաշվի բարելավված անվտանգություն"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"Յուրաքանչյուր բանալի բացառապես կապված է հավելվածի կամ կայքի հետ, որի համար այն ստեղծվել է, ուստի դուք երբեք չեք կարող սխալմամբ մուտք գործել կեղծ հավելված կամ կայք։ Բացի այդ՝ սերվերներում պահվում են միայն բաց բանալիներ, ինչը զգալիորեն դժվարացնում է կոտրումը։"</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Սահուն անցում"</string>
@@ -61,7 +61,7 @@
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> մուտքի բանալի"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"Մուտքի տվյալներ (<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g>)"</string>
- <string name="passkey_before_subtitle" msgid="2448119456208647444">"Անցաբառ"</string>
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Մուտքի բանալի"</string>
<string name="another_device" msgid="5147276802037801217">"Այլ սարք"</string>
<string name="other_password_manager" msgid="565790221427004141">"Գաղտնաբառերի այլ կառավարիչներ"</string>
<string name="close_sheet" msgid="1393792015338908262">"Փակել թերթը"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index 4224da6..452565c 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -74,7 +74,7 @@
<string name="get_dialog_description_single_tap" msgid="2797059565126030879">"გამოიყენეთ თქვენი ეკრანის დაბლოკვის ფუნქცია <xliff:g id="APP_NAME">%1$s</xliff:g>-ში <xliff:g id="USERNAME">%2$s</xliff:g>-ით შესასვლელად"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7096423827682163270">"შესვლის ვარიანტების განბლოკვა <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>
- <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"აირჩიეთ შენახული პაროლი <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
+ <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"აირჩიეთ შენახული პაროლი <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის"</string>
<string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"აირჩიეთ სისტემაში შესვლის ინფორმაცია <xliff:g id="APP_NAME">%1$s</xliff:g>-სთვის"</string>
<string name="get_dialog_title_choose_sign_in_for" msgid="645728947702442421">"აირჩიეთ ანგარიში <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის"</string>
<string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"გსურთ აირჩიოთ ვარიანტი <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის?"</string>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index 2fd31ee..c3bfc4f 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -90,7 +90,7 @@
<string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Кіру ақпараты жоқ."</string>
<string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> аккаунтында кіру туралы ешқандай ақпарат жоқ."</string>
<string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіру әрекеттерін басқару"</string>
- <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string>
+ <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сұрауды тоқтатты."</string>
<string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Кіру опциялары"</string>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 07775e0..7ac1d1a 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -91,7 +91,7 @@
<string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> मा साइन इन गर्नेसम्बन्धी कुनै पनि जानकारी छैन"</string>
<string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इनसम्बन्धी विकल्पहरू व्यवस्थापन गर्नुहोस्"</string>
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string>
- <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string>
+ <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गर्नुहोस्"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अनुरोध रद्द गरेको छ"</string>
<string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"साइन इनसम्बन्धी विकल्पहरू"</string>
<string name="more_options_content_description" msgid="1323427365788198808">"थप"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index a3476d9..9186c59 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -91,7 +91,7 @@
<string name="no_sign_in_info_in" msgid="2641118151920288356">"Sem informações de início de sessão em <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Faça a gestão dos inícios de sessão"</string>
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
- <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use um dispositivo diferente"</string>
+ <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use outro diferente"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Pedido cancelado pela app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Opções de início de sessão"</string>
<string name="more_options_content_description" msgid="1323427365788198808">"Mais"</string>
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
index 0417533..473094c 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
@@ -22,6 +22,7 @@
import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry.PerUserNameEntries
import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.CredentialEntryInfo
+import java.time.Instant
fun Request.Get.toGet(isPrimary: Boolean): CredentialSelectorUiState.Get {
val accounts = providerInfos
@@ -67,4 +68,4 @@
val comparator = compareBy<CredentialEntryInfo> { entryInfo ->
// Passkey type always go first
entryInfo.credentialType.let { if (it == CredentialType.PASSKEY) 0 else 1 }
-}.thenByDescending { it.lastUsedTimeMillis ?: 0 }
+}.thenByDescending { it.lastUsedTimeMillis ?: Instant.EPOCH }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm b/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm
index 03b5c19..723c187 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_french_ca.kcm
@@ -348,13 +348,13 @@
label: ','
base: ','
shift: '\''
- ralt: '_'
+ ralt: '\u00af'
}
key PERIOD {
label: '.'
base: '.'
- ralt: '-'
+ ralt: '\u00ad'
}
key SLASH {
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index 21651ba1..4fa9855 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -63,7 +63,7 @@
<string name="archive_application_text_all_users" msgid="3151229641681672580">"Diese App für alle Nutzer archivieren? Deine personenbezogenen Daten werden gespeichert."</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Diese in deinem Arbeitsprofil befindliche App archivieren? Deine personenbezogenen Daten werden gespeichert."</string>
<string name="archive_application_text_user" msgid="2586558895535581451">"Diese App für <xliff:g id="USERNAME">%1$s</xliff:g> archivieren? Deine personenbezogenen Daten werden gespeichert."</string>
- <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Möchtest du diese in deinem privaten Bereich befindliche App archivieren? Deine personenbezogenen Daten werden gespeichert."</string>
+ <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Möchtest du diese in deinem vertraulichen Profil befindliche App archivieren? Deine personenbezogenen Daten werden gespeichert."</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Möchtest du diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Möchtest du diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Möchtest du diese App aus deinem Arbeitsprofil deinstallieren?"</string>
@@ -72,7 +72,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> an App-Daten behalten."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Möchtest du diese App löschen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Möchtest du diese App deinstallieren? Der <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-Klon wird ebenfalls gelöscht."</string>
- <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Möchtest du diese App deinstallieren und damit aus deinem vertraulichen Bereich entfernen?"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Möchtest du diese App deinstallieren und damit aus deinem vertraulichen Profil entfernen?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Laufende Deinstallationen"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Fehlgeschlagene Deinstallationen"</string>
<string name="uninstalling" msgid="8709566347688966845">"Wird deinstalliert..."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 6f7a433..acacc7f 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -63,7 +63,7 @@
<string name="archive_application_text_all_users" msgid="3151229641681672580">"Αρχειοθέτηση αυτής της εφαρμογής για όλους τους χρήστες; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Αρχειοθέτηση αυτής της εφαρμογής στο προφίλ εργασίας σας; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string>
<string name="archive_application_text_user" msgid="2586558895535581451">"Αρχειοθέτηση αυτής της εφαρμογής για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string>
- <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Θέλετε να αρχειοθετήσετε αυτή την εφαρμογή από τον απόρρητο χώρο σας; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string>
+ <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Θέλετε να αρχειοθετήσετε αυτή την εφαρμογή από τον ιδιωτικό χώρο σας; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για "<b>"όλους"</b>" τους χρήστες; Η εφαρμογή και τα δεδομένα της θα καταργηθούν από "<b>"όλους"</b>" τους χρήστες στη συσκευή."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>;"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Θέλετε να καταργήσετε την εγκατάσταση αυτής της εφαρμογής από το προφίλ εργασίας σας;"</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index 436d6ce..8595ae2 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -46,7 +46,7 @@
<string name="ok" msgid="7871959885003339302">"OK"</string>
<string name="archive" msgid="4447791830199354721">"Archiválás"</string>
<string name="update_anyway" msgid="8792432341346261969">"Frissítés"</string>
- <string name="manage_applications" msgid="5400164782453975580">"Alkalmazáskezelés"</string>
+ <string name="manage_applications" msgid="5400164782453975580">"Appok kezelése"</string>
<string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nincs elég hely"</string>
<string name="out_of_space_dlg_text" msgid="8727714096031856231">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazást nem lehet telepíteni. Szabadítson fel egy kis helyet, és próbálkozzon újra."</string>
<string name="app_not_found_dlg_title" msgid="5107924008597470285">"Az alkalmazás nem található"</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index 69d954d..c4702dd 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="7488448184431507488">"Namest. program za paket"</string>
+ <string name="app_name" msgid="7488448184431507488">"Namestitvena aplikacija za paket"</string>
<string name="install" msgid="711829760615509273">"Namesti"</string>
<string name="update" msgid="3932142540719227615">"Posodobi"</string>
<string name="done" msgid="6632441120016885253">"Končano"</string>
diff --git a/packages/SettingsLib/Color/res/values/colors.xml b/packages/SettingsLib/Color/res/values/colors.xml
index b0b9b10..ef0dd1b 100644
--- a/packages/SettingsLib/Color/res/values/colors.xml
+++ b/packages/SettingsLib/Color/res/values/colors.xml
@@ -17,6 +17,7 @@
<resources>
<!-- Dynamic colors-->
+ <color name="settingslib_color_blue700">#0B57D0</color>
<color name="settingslib_color_blue600">#1a73e8</color>
<color name="settingslib_color_blue400">#669df6</color>
<color name="settingslib_color_blue300">#8ab4f8</color>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
index 0447ef8..bc3488fc 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
@@ -56,6 +56,9 @@
".black",
android.R.color.white);
map.put(
+ ".blue200",
+ R.color.settingslib_color_blue700);
+ map.put(
".blue400",
R.color.settingslib_color_blue600);
map.put(
diff --git a/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
index bef0caa..b7e857c 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-ar/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settingslib_category_personal" msgid="1142302328104700620">"شخصي"</string>
+ <string name="settingslib_category_personal" msgid="1142302328104700620">"المساحة الشخصية"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"للعمل"</string>
<string name="settingslib_category_private" msgid="5039276873477591386">"خاص"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
index e55f48e..853700b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml
@@ -19,5 +19,5 @@
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>
- <string name="settingslib_category_private" msgid="5039276873477591386">"निजी"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"प्राइवेट"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
index a36078c..aa5687b 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml
@@ -19,5 +19,5 @@
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>
- <string name="settingslib_category_private" msgid="5039276873477591386">"Անձնական"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Մասնավոր"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
index 2e199c4..a5fc031 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml
@@ -19,5 +19,5 @@
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>
- <string name="settingslib_category_private" msgid="5039276873477591386">"ສ່ວນຕົວ"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"ສ່ວນບຸກຄົນ"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
index ac1f07b..204ac69 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobiste"</string>
+ <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobisty"</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-sk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
index da02fb9..49f3d80 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobné"</string>
+ <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobný"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Pracovné"</string>
<string name="settingslib_category_private" msgid="5039276873477591386">"Súkromné"</string>
</resources>
diff --git a/packages/SystemUI/monet/AndroidManifest.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
similarity index 66%
rename from packages/SystemUI/monet/AndroidManifest.xml
rename to packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
index 1fab528..eda7daa 100644
--- a/packages/SystemUI/monet/AndroidManifest.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2021 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.
@@ -14,7 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.monet">
-</manifest>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:layout_marginTop="16dp">
+</LinearLayout>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
index cdd5c25..6052be3 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml
@@ -20,7 +20,7 @@
<item name="android:colorAccent">@color/settingslib_materialColorPrimary</item>
<item name="android:colorBackground">@color/settingslib_materialColorSurfaceContainer</item>
<item name="android:textColorPrimary">@color/settingslib_materialColorOnSurface</item>
- <item name="android:textColorSecondary">@color/settingslib_materialColorOnSurfaceVariant</item>
+ <item name="android:textColorSecondary">@color/settingslib_text_color_secondary</item>
<item name="android:textColorTertiary">@color/settingslib_materialColorOutline</item>
</style>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 6e9bde4..8276e18 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -29,36 +29,46 @@
import kotlinx.coroutines.flow.map
interface IAppOpsController {
- val mode: Flow<Int>
+ val modeFlow: Flow<Int>
val isAllowed: Flow<Boolean>
- get() = mode.map { it == MODE_ALLOWED }
+ get() = modeFlow.map { it == MODE_ALLOWED }
fun setAllowed(allowed: Boolean)
@Mode fun getMode(): Int
}
+data class AppOps(
+ val op: Int,
+ val modeForNotAllowed: Int = MODE_ERRORED,
+
+ /**
+ * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
+ *
+ * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
+ */
+ val setModeByUid: Boolean = false,
+)
+
class AppOpsController(
context: Context,
private val app: ApplicationInfo,
- private val op: Int,
- private val modeForNotAllowed: Int = MODE_ERRORED,
- private val setModeByUid: Boolean = false,
+ private val appOps: AppOps,
) : IAppOpsController {
private val appOpsManager = context.appOpsManager
private val packageManager = context.packageManager
- override val mode = appOpsManager.opModeFlow(op, app)
+ override val modeFlow = appOpsManager.opModeFlow(appOps.op, app)
override fun setAllowed(allowed: Boolean) {
- val mode = if (allowed) MODE_ALLOWED else modeForNotAllowed
+ val mode = if (allowed) MODE_ALLOWED else appOps.modeForNotAllowed
- if (setModeByUid) {
- appOpsManager.setUidMode(op, app.uid, mode)
+ if (appOps.setModeByUid) {
+ appOpsManager.setUidMode(appOps.op, app.uid, mode)
} else {
- appOpsManager.setMode(op, app.uid, app.packageName, mode)
+ appOpsManager.setMode(appOps.op, app.uid, app.packageName, mode)
}
- val permission = AppOpsManager.opToPermission(op)
+ val permission = AppOpsManager.opToPermission(appOps.op)
if (permission != null) {
packageManager.updatePermissionFlags(permission, app.packageName,
PackageManager.FLAG_PERMISSION_USER_SET,
@@ -67,5 +77,6 @@
}
}
- @Mode override fun getMode(): Int = appOpsManager.getOpMode(op, app)
+ @Mode
+ override fun getMode(): Int = appOpsManager.getOpMode(appOps.op, app)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionController.kt
new file mode 100644
index 0000000..9350f98
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionController.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.settingslib.spaprivileged.model.app
+
+import android.app.AppOpsManager
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.util.Log
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+
+interface IAppOpsPermissionController {
+ val isAllowedFlow: Flow<Boolean>
+ fun setAllowed(allowed: Boolean)
+}
+
+class AppOpsPermissionController(
+ context: Context,
+ private val app: ApplicationInfo,
+ appOps: AppOps,
+ private val permission: String,
+ private val packageManagers: IPackageManagers = PackageManagers,
+ private val appOpsController: IAppOpsController = AppOpsController(context, app, appOps),
+) : IAppOpsPermissionController {
+ override val isAllowedFlow: Flow<Boolean> = appOpsController.modeFlow.map { mode ->
+ when (mode) {
+ AppOpsManager.MODE_ALLOWED -> true
+
+ AppOpsManager.MODE_DEFAULT -> {
+ with(packageManagers) { app.hasGrantPermission(permission) }
+ }
+
+ else -> false
+ }
+ }.conflate().onEach { Log.d(TAG, "isAllowed: $it") }.flowOn(Dispatchers.Default)
+
+ override fun setAllowed(allowed: Boolean) {
+ appOpsController.setAllowed(allowed)
+ }
+
+ private companion object {
+ private const val TAG = "AppOpsPermissionControl"
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index 5db5eae..120b75e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -20,12 +20,14 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settingslib.spa.framework.util.asyncMapItem
import com.android.settingslib.spa.framework.util.filterItem
-import com.android.settingslib.spaprivileged.model.app.AppOpsController
+import com.android.settingslib.spaprivileged.model.app.AppOps
+import com.android.settingslib.spaprivileged.model.app.AppOpsPermissionController
import com.android.settingslib.spaprivileged.model.app.AppRecord
-import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.IAppOpsPermissionController
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers
import kotlinx.coroutines.flow.Flow
@@ -36,7 +38,7 @@
override val app: ApplicationInfo,
val hasRequestBroaderPermission: Boolean,
val hasRequestPermission: Boolean,
- var appOpsController: IAppOpsController,
+ var appOpsPermissionController: IAppOpsPermissionController,
) : AppRecord
abstract class AppOpPermissionListModel(
@@ -44,11 +46,11 @@
private val packageManagers: IPackageManagers = PackageManagers,
) : TogglePermissionAppListModel<AppOpPermissionRecord> {
- abstract val appOp: Int
+ abstract val appOps: AppOps
abstract val permission: String
override val enhancedConfirmationKey: String?
- get() = AppOpsManager.opToPublicName(appOp)
+ get() = AppOpsManager.opToPublicName(appOps.op)
/**
* When set, specifies the broader permission who trumps the [permission].
@@ -65,27 +67,12 @@
*/
open val permissionHasAppOpFlag: Boolean = true
- open val modeForNotAllowed: Int = AppOpsManager.MODE_ERRORED
-
- /**
- * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
- *
- * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
- */
- open val setModeByUid = false
-
/** These not changeable packages will also be hidden from app list. */
private val notChangeablePackages =
setOf("android", "com.android.systemui", context.packageName)
- private fun createAppOpsController(app: ApplicationInfo) =
- AppOpsController(
- context = context,
- app = app,
- op = appOp,
- setModeByUid = setModeByUid,
- modeForNotAllowed = modeForNotAllowed,
- )
+ private fun createAppOpsPermissionController(app: ApplicationInfo) =
+ AppOpsPermissionController(context, app, appOps, permission)
private fun createRecord(
app: ApplicationInfo,
@@ -98,7 +85,7 @@
app.hasRequestPermission(it)
} ?: false,
hasRequestPermission = hasRequestPermission,
- appOpsController = createAppOpsController(app),
+ appOpsPermissionController = createAppOpsPermissionController(app),
)
}
@@ -131,14 +118,20 @@
override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<AppOpPermissionRecord>>) =
recordListFlow.filterItem(::isChangeable)
+ /**
+ * Defining the default behavior as permissible as long as the package requested this permission
+ * (This means pre-M gets approval during install time; M apps gets approval during runtime).
+ */
@Composable
- override fun isAllowed(record: AppOpPermissionRecord): () -> Boolean? =
- isAllowed(
- record = record,
- appOpsController = record.appOpsController,
- permission = permission,
- packageManagers = packageManagers,
- )
+ override fun isAllowed(record: AppOpPermissionRecord): () -> Boolean? {
+ if (record.hasRequestBroaderPermission) {
+ // Broader permission trumps the specific permission.
+ return { true }
+ }
+ val isAllowed by record.appOpsPermissionController.isAllowedFlow
+ .collectAsStateWithLifecycle(initialValue = null)
+ return { isAllowed }
+ }
override fun isChangeable(record: AppOpPermissionRecord) =
record.hasRequestPermission &&
@@ -146,36 +139,6 @@
record.app.packageName !in notChangeablePackages
override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
- record.appOpsController.setAllowed(newAllowed)
- }
-}
-
-/**
- * Defining the default behavior as permissible as long as the package requested this permission
- * (This means pre-M gets approval during install time; M apps gets approval during runtime).
- */
-@Composable
-internal fun isAllowed(
- record: AppOpPermissionRecord,
- appOpsController: IAppOpsController,
- permission: String,
- packageManagers: IPackageManagers = PackageManagers,
-): () -> Boolean? {
- if (record.hasRequestBroaderPermission) {
- // Broader permission trumps the specific permission.
- return { true }
- }
-
- val mode = appOpsController.mode.collectAsStateWithLifecycle(initialValue = null)
- return {
- when (mode.value) {
- null -> null
- AppOpsManager.MODE_ALLOWED -> true
- AppOpsManager.MODE_DEFAULT -> {
- with(packageManagers) { record.app.hasGrantPermission(permission) }
- }
-
- else -> false
- }
+ record.appOpsPermissionController.setAllowed(newAllowed)
}
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
index 91bbd9f..74a7c14 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
@@ -27,16 +27,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spaprivileged.framework.common.appOpsManager
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.any
-import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -44,28 +42,18 @@
class AppOpsControllerTest {
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
- @Spy private val context: Context = ApplicationProvider.getApplicationContext()
+ private val appOpsManager = mock<AppOpsManager>()
- @Mock private lateinit var appOpsManager: AppOpsManager
+ private val packageManager = mock<PackageManager>()
- @Mock private lateinit var packageManager: PackageManager
-
- @Before
- fun setUp() {
- whenever(context.appOpsManager).thenReturn(appOpsManager)
- whenever(context.packageManager).thenReturn(packageManager)
- doNothing().whenever(packageManager)
- .updatePermissionFlags(any(), any(), any(), any(), any())
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { appOpsManager } doReturn appOpsManager
+ on { packageManager } doReturn packageManager
}
@Test
fun setAllowed_setToTrue() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
controller.setAllowed(true)
@@ -74,12 +62,7 @@
@Test
fun setAllowed_setToFalse() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
controller.setAllowed(false)
@@ -88,13 +71,11 @@
@Test
fun setAllowed_setToFalseWithModeForNotAllowed() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- modeForNotAllowed = MODE_IGNORED,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, modeForNotAllowed = MODE_IGNORED),
+ )
controller.setAllowed(false)
@@ -103,13 +84,11 @@
@Test
fun setAllowed_setToTrueByUid() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- setModeByUid = true,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = true),
+ )
controller.setAllowed(true)
@@ -118,13 +97,11 @@
@Test
fun setAllowed_setToFalseByUid() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- setModeByUid = true,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = true),
+ )
controller.setAllowed(false)
@@ -135,12 +112,7 @@
fun getMode() {
whenever(appOpsManager.checkOpNoThrow(OP, APP.uid, APP.packageName))
.thenReturn(MODE_ALLOWED)
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
val mode = controller.getMode()
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
new file mode 100644
index 0000000..9f80b92
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
@@ -0,0 +1,167 @@
+/*
+ * 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.spaprivileged.model.app
+
+import android.app.AppOpsManager
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spaprivileged.framework.common.appOpsManager
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class AppOpsPermissionControllerTest {
+
+ private val appOpsManager = mock<AppOpsManager>()
+ private val packageManager = mock<PackageManager>()
+ private val packageManagers = mock<IPackageManagers>()
+ private val appOpsController = mock<IAppOpsController>()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { appOpsManager } doReturn appOpsManager
+ on { packageManager } doReturn packageManager
+ }
+
+ @Test
+ fun isAllowedFlow_appOpsAllowed_returnTrue() = runBlocking {
+ appOpsController.stub {
+ on { modeFlow } doReturn flowOf(AppOpsManager.MODE_ALLOWED)
+ }
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP),
+ permission = PERMISSION,
+ appOpsController = appOpsController,
+ )
+
+ val isAllowed = controller.isAllowedFlow.firstWithTimeoutOrNull()
+
+ assertThat(isAllowed).isTrue()
+ }
+
+ @Test
+ fun isAllowedFlow_appOpsDefaultAndPermissionGranted_returnTrue() = runBlocking {
+ appOpsController.stub {
+ on { modeFlow } doReturn flowOf(AppOpsManager.MODE_DEFAULT)
+ }
+ packageManagers.stub {
+ on { APP.hasGrantPermission(PERMISSION) } doReturn true
+ }
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP),
+ permission = PERMISSION,
+ packageManagers = packageManagers,
+ appOpsController = appOpsController,
+ )
+
+ val isAllowed = controller.isAllowedFlow.firstWithTimeoutOrNull()
+
+ assertThat(isAllowed).isTrue()
+ }
+
+ @Test
+ fun isAllowedFlow_appOpsDefaultAndPermissionNotGranted_returnFalse() = runBlocking {
+ appOpsController.stub {
+ on { modeFlow } doReturn flowOf(AppOpsManager.MODE_DEFAULT)
+ }
+ packageManagers.stub {
+ on { APP.hasGrantPermission(PERMISSION) } doReturn false
+ }
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP),
+ permission = PERMISSION,
+ packageManagers = packageManagers,
+ appOpsController = appOpsController,
+ )
+
+ val isAllowed = controller.isAllowedFlow.firstWithTimeoutOrNull()
+
+ assertThat(isAllowed).isFalse()
+ }
+
+ @Test
+ fun isAllowedFlow_appOpsError_returnFalse() = runBlocking {
+ appOpsController.stub {
+ on { modeFlow } doReturn flowOf(AppOpsManager.MODE_ERRORED)
+ }
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP),
+ permission = PERMISSION,
+ appOpsController = appOpsController,
+ )
+
+ val isAllowed = controller.isAllowedFlow.firstWithTimeoutOrNull()
+
+ assertThat(isAllowed).isFalse()
+ }
+
+ @Test
+ fun setAllowed_notSetModeByUid() {
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = false),
+ permission = PERMISSION,
+ )
+
+ controller.setAllowed(true)
+
+ verify(appOpsManager).setMode(OP, APP.uid, APP.packageName, AppOpsManager.MODE_ALLOWED)
+ }
+
+ @Test
+ fun setAllowed_setModeByUid() {
+ val controller = AppOpsPermissionController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = true),
+ permission = PERMISSION,
+ )
+
+ controller.setAllowed(true)
+
+ verify(appOpsManager).setUidMode(OP, APP.uid, AppOpsManager.MODE_ALLOWED)
+ }
+
+ private companion object {
+ const val OP = 1
+ const val PERMISSION = "Permission"
+ val APP = ApplicationInfo().apply {
+ packageName = "package.name"
+ uid = 123
+ }
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
index bb25cf3..9d12fc7 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
@@ -25,7 +25,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.android.settingslib.spaprivileged.framework.common.appOpsManager
-import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.AppOps
+import com.android.settingslib.spaprivileged.model.app.IAppOpsPermissionController
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.test.R
import com.google.common.truth.Truth.assertThat
@@ -39,7 +40,6 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@@ -119,7 +119,7 @@
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = false,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val recordListFlow = listModel.filter(flowOf(USER_ID), flowOf(listOf(record)))
@@ -135,7 +135,7 @@
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ALLOWED),
+ appOpsPermissionController = FakeAppOpsPermissionController(true),
)
val isAllowed = getIsAllowed(record)
@@ -144,38 +144,6 @@
}
@Test
- fun isAllowed_defaultAndHasGrantPermission() {
- with(packageManagers) { whenever(APP.hasGrantPermission(PERMISSION)).thenReturn(true) }
- val record =
- AppOpPermissionRecord(
- app = APP,
- hasRequestBroaderPermission = false,
- hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
- )
-
- val isAllowed = getIsAllowed(record)
-
- assertThat(isAllowed).isTrue()
- }
-
- @Test
- fun isAllowed_defaultAndNotGrantPermission() {
- with(packageManagers) { whenever(APP.hasGrantPermission(PERMISSION)).thenReturn(false) }
- val record =
- AppOpPermissionRecord(
- app = APP,
- hasRequestBroaderPermission = false,
- hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
- )
-
- val isAllowed = getIsAllowed(record)
-
- assertThat(isAllowed).isFalse()
- }
-
- @Test
fun isAllowed_broaderPermissionTrumps() {
listModel.broaderPermission = BROADER_PERMISSION
with(packageManagers) {
@@ -187,7 +155,7 @@
app = APP,
hasRequestBroaderPermission = true,
hasRequestPermission = false,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ERRORED),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isAllowed = getIsAllowed(record)
@@ -202,7 +170,7 @@
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ERRORED),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isAllowed = getIsAllowed(record)
@@ -217,7 +185,7 @@
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = false,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isChangeable = listModel.isChangeable(record)
@@ -232,7 +200,7 @@
app = NOT_CHANGEABLE_APP,
hasRequestBroaderPermission = false,
hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isChangeable = listModel.isChangeable(record)
@@ -247,7 +215,7 @@
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isChangeable = listModel.isChangeable(record)
@@ -263,7 +231,7 @@
app = APP,
hasRequestBroaderPermission = true,
hasRequestPermission = true,
- appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ appOpsPermissionController = FakeAppOpsPermissionController(false),
)
val isChangeable = listModel.isChangeable(record)
@@ -273,28 +241,18 @@
@Test
fun setAllowed() {
- val appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+ val appOpsPermissionController = FakeAppOpsPermissionController(false)
val record =
AppOpPermissionRecord(
app = APP,
hasRequestBroaderPermission = false,
hasRequestPermission = true,
- appOpsController = appOpsController,
+ appOpsPermissionController = appOpsPermissionController,
)
listModel.setAllowed(record = record, newAllowed = true)
- assertThat(appOpsController.setAllowedCalledWith).isTrue()
- }
-
- @Test
- fun setAllowed_setModeByUid() {
- listModel.setModeByUid = true
- val record = listModel.transformItem(APP)
-
- listModel.setAllowed(record = record, newAllowed = true)
-
- verify(appOpsManager).setUidMode(listModel.appOp, APP.uid, AppOpsManager.MODE_ALLOWED)
+ assertThat(appOpsPermissionController.setAllowedCalledWith).isTrue()
}
private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
@@ -309,11 +267,9 @@
override val switchTitleResId = R.string.test_app_op_permission_switch_title
override val footerResId = R.string.test_app_op_permission_footer
- override val appOp = AppOpsManager.OP_MANAGE_MEDIA
+ override val appOps = AppOps(AppOpsManager.OP_MANAGE_MEDIA)
override val permission = PERMISSION
override var broaderPermission: String? = null
-
- override var setModeByUid = false
}
private companion object {
@@ -326,14 +282,12 @@
}
}
-private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
+private class FakeAppOpsPermissionController(allowed: Boolean) : IAppOpsPermissionController {
var setAllowedCalledWith: Boolean? = null
- override val mode = flowOf(fakeMode)
+ override val isAllowedFlow = flowOf(allowed)
override fun setAllowed(allowed: Boolean) {
setAllowedCalledWith = allowed
}
-
- override fun getMode() = fakeMode
}
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 9c0d29d..32557b9 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -69,3 +69,13 @@
description: "Allow all widgets on the lock screen by default."
bug: "328261690"
}
+
+flag {
+ name: "enable_determining_advanced_details_header_with_metadata"
+ namespace: "pixel_cross_device_control"
+ description: "Use metadata instead of device type to determine whether a bluetooth device should use advanced details header."
+ bug: "328556903"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
index 7aae1a6..6f614b3 100644
--- a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig
@@ -31,3 +31,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "use_playback_info_for_routing_controls"
+ namespace: "media_solutions"
+ description: "Use app-provided playback info when providing media routing information."
+ bug: "333564788"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index ad5337c..5e80604 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Regs: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktief"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Gestoor"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktief (net links)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fisieke sleutelbord"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Kies sleutelborduitleg"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Verstek"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Skakel skerm aan"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Skermaanskakelkontrole"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Laat toe dat die skerm aangeskakel word"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Laat ’n app toe om die skerm aan te skakel. As jy toestemming gee, kan die app die skerm enige tyd sonder jou uitdruklike bedoeling aanskakel."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index b65fdc0..eb1a365 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ግ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>፣ ቀ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ባትሪ።"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ግራ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ቀኝ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ንቁ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ተቀምጧል"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ገቢር (ግራ ብቻ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"አካላዊ ቁልፍ ሰሌዳ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"የቁልፍ ሰሌዳ አቀማመጥን ይምረጡ"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ነባሪ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ማያ ገጽን ያብሩ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"የማያ ገፅ ማብሪያ መቆጣጠሪያ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ማያ ገጹን ማብራት ይፍቀዱ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"አንድ መተግበሪያ ማያ ገጹን እንዲያበራ ይፍቀዱለት። ከተሰጠ፣ መተግበሪያው ያለእርስዎ ግልፅ ሐሳብ በማንኛውም ጊዜ ማያ ገጹን ሊያበራ ይችላል።"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ማሰራጨት ይቁም?"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index cfa5b14..3c034c2 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"مستوى الشحن في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، مستوى الشحن في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"مستوى الشحن في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"مستوى الشحن في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"مستوى شحن البطارية في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"مستوى شحن البطارية في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"نشط"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"محفوظ"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"سماعة الأذن الطبية نشطة (اليسرى فقط)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"لوحة المفاتيح الخارجية"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"اختيار تنسيق لوحة مفاتيح"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"التنسيق التلقائي"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"تشغيل الشاشة"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"التحكّم في تشغيل الشاشة"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"السماح بتشغيل الشاشة"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"يمكنك السماح لأحد التطبيقات بتشغيل الشاشة. في حال منحت هذا الإذن، قد يشغِّل التطبيق الشاشة في أي وقت بدون إذن صريح منك."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index debef2c..e64a742 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"বাওঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী।"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"বাকী আছে: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"বাওঁফালে <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"সোঁফালে <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"সক্ৰিয়"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ছেভ কৰা হৈছে"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"সক্ৰিয় হৈ আছে (কেৱল বাওঁফালৰটো)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"কায়িক কীব’ৰ্ড"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"কীব\'ৰ্ডৰ চানেকি বাছক"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ডিফ’ল্ট"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"স্ক্ৰীন অন কৰক"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"স্ক্ৰীন অন কৰাৰ নিয়ন্ত্ৰণ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"স্ক্ৰীনখন অন কৰিবলৈ অনুমতি দিয়ক"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"এপ্টোক স্ক্ৰীনখন অন কৰিবলৈ অনুমতি দিয়ক। যদি অনুমতি দিয়া হয়, এপ্টোৱে আপোনাৰ স্পষ্ট উদ্দেশ্য অবিহনেও যিকোনো সময়তে স্ক্ৰীনখন অন কৰিব পাৰে।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 9541a98..23bfcb5 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Yadda saxlandı"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiv (yalnız sol)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziki klaviatura"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura düzənini seçin"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Defolt"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekranı aktiv etmək"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekran yandırma nizamlayıcısı"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Ekranı aktiv etməyə icazə verin"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tətbiqin ekranı aktiv etməsinə icazə verin. İcazə verilərsə, tətbiq istənilən vaxt sizdən soruşmadan ekranı aktiv edə bilər."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index eda08fb0..71b7f6e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivan"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Sačuvano"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktivno (samo levo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Podrazumevano"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Uključivanje ekrana"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrola uključivanja ekrana"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Dozvoli uključivanje ekrana"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Dozvoljava aplikaciji da uključi ekran. Ako se omogući, aplikacija može da uključi ekran u bilo kom trenutku bez vaše eksplicitne namere."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Želite da zaustavite emitovanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 1c6705e..61ed0a1 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (левы навушнік), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (правы навушнік)."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (левы навушнік)"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (правы навушнік)"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Уключана"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Захавана"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Выкарыстоўваецца (толькі левы навушнік)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Фізічная клавіятура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Выбар раскладкі клавіятуры"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Стандартна"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Уключэнне экрана"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Налады ўключэння экрана"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Дазволіць уключэнне экрана"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Дазволіць праграме ўключаць экран. З гэтым дазволам праграма зможа ў любы час уключаць экран без вашага яўнага намеру."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 31d24c1..ce497f3 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -186,11 +186,11 @@
</string-array>
<string-array name="select_logd_size_summaries">
<item msgid="409235464399258501">"Изключено"</item>
- <item msgid="4195153527464162486">"Рег. буфер – 64 КБ"</item>
- <item msgid="7464037639415220106">"Рег. буфер – 256 КБ"</item>
+ <item msgid="4195153527464162486">"Рег. буфер – 64 хил."</item>
+ <item msgid="7464037639415220106">"Рег. буфер – 256 хил."</item>
<item msgid="8539423820514360724">"Рег. буфер – 1 млн."</item>
- <item msgid="1984761927103140651">"Рег. буфер – 4 МБ"</item>
- <item msgid="2983219471251787208">"Регистрационен буфер – 8 МБ"</item>
+ <item msgid="1984761927103140651">"Рег. буфер – 4 млн."</item>
+ <item msgid="2983219471251787208">"Регистрационен буфер – 8 млн."</item>
</string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"Изкл."</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d6794a2..0515ed9 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Л: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Д: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"За ляво ухо. Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"За дясно ухо. Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Запазено"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Активно (само лявото)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Физическа клавиатура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избор на клавиатурна подредба"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"По подразбиране"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Включване на екрана"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Контрола за включване на екрана"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Разрешаване на включването на екрана"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Разрешете на дадено приложение да включва екрана. Ако го направите, то може да включва екрана по всяко време без явното ви намерение."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 57bc401..fea8137 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি।"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"চালু আছে"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"সেভ করা আছে"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"চালু আছে (শুধু বাঁদিক)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ফিজিক্যাল কীবোর্ড"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"কীবোর্ড লেআউট বেছে নিন"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ডিফল্ট"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"স্ক্রিন চালু করা"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"স্ক্রিন চালু করার কন্ট্রোল"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"স্ক্রিন চালু করার অনুমতি দিন"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"অ্যাপকে স্ক্রিন চালু করার অনুমতি দিন। অনুমতি দেওয়া হলে, অ্যাপ আপনার এক্সপ্লিসিট ইনটেন্ট ছাড়াই যেকোনও সময় স্ক্রিন চালু করতে পারবে।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 9d914db..15a9618 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Lijevo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Lijeva <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Desna <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivan"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Sačuvano"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktivno (samo lijevo)"</string>
@@ -490,10 +492,10 @@
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je optimizirano"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje"</string>
- <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATUS">%2$s</xliff:g> – Napunjeno do <xliff:g id="TIME">%3$s</xliff:g>"</string>
+ <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATUS">%2$s</xliff:g> – Napunit će se do <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> – Potpuno napunjeno do <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Potpuno napunjeno do <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Napunjeno do <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Napunit će se do <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zadano"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Uključivanje ekrana"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrola za uključivanje ekrana"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Dozvoli uključivanje ekrana"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Dozvolite aplikaciji da uključuje ekran. Ako se odobri, aplikacija može uključiti ekran bilo kada bez vaše izričite namjere."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index eb7bd7b..7dce81a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Esquerre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Dret: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actiu"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Desat"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Actiu (només l\'esquerre)"</string>
@@ -208,11 +212,11 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"Instal·la dades de veu"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"Instal·la les dades de veu necessàries per a la síntesi de veu"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Pot ser que aquest motor de síntesi de parla pugui recopilar tot el text que s\'enunciarà, incloses les dades personals, com ara les contrasenyes i els números de les targetes de crèdit. Ve del motor <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Vols activar l\'ús d\'aquest motor de síntesi de parla?"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"Aquest idioma requereix una connexió a la xarxa activa per a la sortida de text a parla."</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"Aquest idioma requereix una connexió de xarxa activa per a la sortida de text a parla."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Això és un exemple de síntesi de veu"</string>
<string name="tts_status_title" msgid="8190784181389278640">"Estat de l\'idioma predeterminat"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> és totalment compatible"</string>
- <string name="tts_status_requires_network" msgid="8327617638884678896">"Es necessita una connexió a la xarxa per a <xliff:g id="LOCALE">%1$s</xliff:g>"</string>
+ <string name="tts_status_requires_network" msgid="8327617638884678896">"Es necessita una connexió de xarxa per a <xliff:g id="LOCALE">%1$s</xliff:g>"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> no és compatible"</string>
<string name="tts_status_checking" msgid="8026559918948285013">"S\'està comprovant…"</string>
<string name="tts_engine_settings_title" msgid="7849477533103566291">"Configuració de: <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclat físic"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tria una disposició de teclat"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminat"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activa la pantalla"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Control d\'activació de la pantalla"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permet que activi la pantalla"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permet que una aplicació activi la pantalla. Si concedeixes aquest permís, pot ser que l\'aplicació activi la pantalla en qualsevol moment sense la teva intenció explícita."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 6fa6e12..20ff455 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Baterie: L <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Levá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Pravá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Levá část: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Pravá část: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivní"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Uloženo"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktivní (pouze levé)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnice"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zvolte rozložení klávesnice"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Výchozí"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Zapínání obrazovky"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ovládání zapnutí obrazovky"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Povolit zapínání obrazovky"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Aplikaci můžete povolit zapínat obrazovku. Pokud bude mít toto oprávnění, může kdykoli zapnout obrazovku bez požadavku uživatele."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index fc2191c..9e47d6d 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -94,7 +94,7 @@
<string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon eller medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Aktiveret. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string>
+ <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Aktiv. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string>
<string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Aktiveret. V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string>
<string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Aktiveret. V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string>
<string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Aktiveret. H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string>
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Højre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Højre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Gemt"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiveret (kun venstre)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vælg tastaturlayout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Aktivér skærmen"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Indstillinger for aktivering af skærm"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Tillad aktivering af skærmen"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tillad, at en app aktiverer skærmen. Hvis du giver denne tilladelse, kan appen til enhver tid aktivere skærmen, uden at du eksplicit har bedt om det."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 793560d..cfa64c0 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Gespeichert"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiv (nur links)"</string>
@@ -493,7 +497,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATUS">%2$s</xliff:g> – Vollständig geladen in <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vollständig geladen in <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Vollständig geladen in <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Vollständig geladen in <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Vollständig geladen bis <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physische Tastatur"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastaturlayout wählen"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Display aktivieren"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Steuerelement zum Aktivieren des Displays"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Aktivieren des Displays erlauben"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Einer App erlauben, das Display zu aktivieren. Wenn du diese Erlaubnis erteilst, kann die App jederzeit das Display aktivieren – auch ohne deine explizite Absicht."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 6bcdc81..bd1b848 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Αριστερά: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Δεξιά: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ενεργό"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Αποθηκεύτηκε"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ενεργό (μόνο το αριστερό)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Φυσικό πληκτρολόγιο"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Επιλέξτε διάταξη πληκτρολογίου"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Προεπιλογή"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ενεργοποίηση οθόνης"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Στοιχείο ελέγχου ενεργοποίησης οθόνης"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Να επιτρέπεται η ενεργοποίηση της οθόνης"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Επιτρέψτε σε μια εφαρμογή να ενεργοποιεί την οθόνη. Αν παραχωρήσετε την άδεια, η εφαρμογή ενδέχεται να ενεργοποιεί την οθόνη ανά πάσα στιγμή, χωρίς να εκφράσετε σαφή πρόθεση."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Διακοπή μετάδοσης με την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 83c1bdc..c4d33e0 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saved"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Active (left only)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Choose keyboard layout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Turn screen on"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Screen turn-on control"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Allow turning the screen on"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 59fe8da..42f9b5f 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saved"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Active (left only)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Choose keyboard layout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Turn screen on"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Screen turn-on control"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Allow turning the screen on"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 83c1bdc..c4d33e0 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saved"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Active (left only)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Choose keyboard layout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Turn screen on"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Screen turn-on control"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Allow turning the screen on"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 83c1bdc..c4d33e0 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saved"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Active (left only)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Choose keyboard layout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Turn screen on"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Screen turn-on control"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Allow turning the screen on"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index e7f6d99..fd84077 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saved"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Active (left only)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Choose keyboard layout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Turn screen on"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Screen turn-on control"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Allow turning the screen on"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 1a0fec5d..0167ec1 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Guardado"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Activo (solo izquierdo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Elige el diseño de teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminada"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activar pantalla"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Control para activar la pantalla"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir activación de la pantalla"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permite que una app active la pantalla. Si se otorga permiso, la app podría activar la pantalla en cualquier momento sin que lo pidas de manera explícita."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 69c804e..0899d5a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Guardado"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Activo (solo izquierdo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Elige el diseño del teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminado"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Encender la pantalla"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Control de activación de pantalla"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir encender la pantalla"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permite que una aplicación encienda la pantalla. Si das este permiso, la aplicación puede encender la pantalla en cualquier momento sin que se lo pidas."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index fd5762b..42c20399 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -94,7 +94,7 @@
<string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Ühendatud (telefoni pole), aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Ühendatud (meediat pole), aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Ühendatud (telefoni ega meediat pole), aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Aktiivne. Aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Aktiivne. Aku: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
<string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Aktiivne. Aku: V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Aktiivne. Vasak: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> akutoidet."</string>
<string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Aktiivne. Parem: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> akutoidet."</string>
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Aku: V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Vasak: aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Parem: aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Vasakpoolne: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Parempoolne: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivne"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Salvestatud"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiivne (ainult vasak)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Füüsiline klaviatuur"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatuuri paigutuse valimine"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Vaikimisi"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekraani sisselülitamine"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekraani sisselülitamise juhtimine"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Luba ekraani sisselülitamine"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Rakendusel lubatakse ekraan sisse lülitada. Kui annate loa, võib rakendus ekraani igal ajal sisse lülitada ilma teie sõnaselge kavatsuseta."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index c330b76..6be5f6c 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. R aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Ezkerreko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Eskuineko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktibo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Gordeta"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktibo (ezkerrekoa soilik)"</string>
@@ -120,7 +124,7 @@
<string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktibo (multimedia-edukia soilik); ezkerreko aldea soilik"</string>
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktibo (multimedia-edukia soilik); eskuineko aldea soilik"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktibo (multimedia-edukia soilik); ezkerreko eta eskuineko aldeak"</string>
- <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Euskarriaren audioa"</string>
+ <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Multimedia-audioa"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefono-deiak"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fitxategi-transferentzia"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Sarrera-gailua"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teklatu fisikoa"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Aukeratu teklatuaren diseinua"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Lehenetsia"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Piztu pantaila"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Pantaila pizteko modua kontrolatzeko aukera"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Eman pantaila pizteko baimena"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Eman pantaila pizteko baimena aplikazioei. Baimena emanez gero, aplikazioek edonoiz piztu ahal izango dute pantaila, zuk halako asmorik izan ez arren."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1d331fb..a5fe65d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"فعال"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ذخیرهشده"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"فعال (فقط چپ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"صفحهکلید فیزیکی"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"انتخاب جانمایی صفحهکلید"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"پیشفرض"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"روشن کردن صفحهنمایش"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"کنترل روشن شدن صفحهنمایش"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"اجازه روشن کردن صفحهنمایش"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"به برنامه اجازه میدهد صفحهنمایش را روشن کند. اگر اجازه داده شود، ممکن است این برنامه در هر زمانی بدون هدف صریح شما صفحهنمایش را روشن کند."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"همهفرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index bdf4301..03a6d43 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, O: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> virtaa."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Vasen: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Oikea: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivinen"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Tallennettu"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiivinen (vain vasen)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fyysinen näppäimistö"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Valitse näppäimistöasettelu"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Oletus"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Näytön käynnistys"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Näytön päälle laittamisen asetukset"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Salli näytön käynnistäminen"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Salli sovelluksen käynnistää näyttö. Jos sovellus saa luvan, se voi käynnistää näytön itsenäisesti milloin tahansa."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 090c3b9..1d9d5c8 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"G. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Gauche : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Droite : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Écouteur gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Écouteur droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Enregistré"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Actif (gauche seulement)"</string>
@@ -125,7 +127,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfert de fichier"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Périphérique d\'entrée"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Accès Internet"</string>
- <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Autoriser accès : contacts et hist. d\'app."</string>
+ <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Autoriser accès : contacts et hist. d\'appels"</string>
<string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Ces infos seront utilisées pour les annonces d\'appels et plus"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Partage de connexion Internet"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Messages texte"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Clavier physique"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Sélectionner disposition du clavier"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Par défaut"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activer l\'écran"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Commande d\'activation de l\'écran"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Autoriser l\'activation de l\'écran"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Autorisez une application à activer l\'écran. Lorsque vous accordez cette autorisation, l\'application peut activer l\'écran à tout moment sans que vous lui demandiez."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index be3b058..7d2bea0 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batterie, droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batterie."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Enregistré"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Actif (gauche uniquement)"</string>
@@ -490,10 +494,10 @@
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge optimisée"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - En charge"</string>
- <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Complètement chargé dans <xliff:g id="TIME">%3$s</xliff:g>"</string>
+ <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Complètement chargé d\'ici <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Complètement chargé dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Complètement chargé dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Complètement chargé dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Complètement chargé d\'ici <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Clavier physique"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Sélectionner disposition du clavier"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Par défaut"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activer l\'écran"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Commande d\'activation de l\'écran"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Autoriser l\'activation de l\'écran"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Autoriser une appli à activer l\'écran. Si elle y est autorisée, l\'appli pourra activer l\'écran à tout moment sans que vous le lui demandiez."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 21d0bcd..cc03004 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Gardado"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Activo (só o esquerdo)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Seleccionar deseño do teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminado"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activar a pantalla"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Control de activación da pantalla"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir activación da pantalla"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permite que unha aplicación active a pantalla. Se lle dás permiso, a aplicación poderá activar a pantalla en calquera momento sen que llo pidas."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 35f48e0..a5bf093 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"સક્રિય"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"સાચવેલું"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ચાલુ છે (માત્ર ડાબી બાજુ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ભૌતિક કીબોર્ડ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"કીબોર્ડ લેઆઉટ પસંદ કરો"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ડિફૉલ્ટ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"સ્ક્રીન ચાલુ કરો"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"સ્ક્રીન ચાલુ કરવાનું નિયંત્રણ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"સ્ક્રીન ચાલુ કરવાની મંજૂરી આપો"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ઍપને સ્ક્રીન ચાલુ કરવાની મંજૂરી આપો. જો મંજૂરી આપી હોય, તો ઍપ તમારા સ્પષ્ટ હેતુ વિના કોઈપણ સમયે સ્ક્રીન ચાલુ કરી શકે છે."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> બ્રોડકાસ્ટ કરવાનું રોકીએ?"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index cfb6546..2aee1bc 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायां हेडसेट:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"बाएं ईयरबड में <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी बची है"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"दाएं ईयरबड में <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी बची है"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"चालू"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"सेव किया गया"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"सिर्फ़ बाईं तरफ़ वाला चालू है"</string>
@@ -493,7 +495,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - बैटरी <xliff:g id="TIME">%3$s</xliff:g> में पूरी चार्ज हो जाएगी"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - बैटरी <xliff:g id="TIME">%2$s</xliff:g> में पूरी चार्ज हो जाएगी"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"बैटरी <xliff:g id="TIME">%1$s</xliff:g> में पूरी चार्ज हो जाएगी"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"बैटरी <xliff:g id="TIME">%1$s</xliff:g> में पूरी चार्ज हो जाएगी"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"बैटरी <xliff:g id="TIME">%1$s</xliff:g> तक पूरी चार्ज हो जाएगी"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"फ़िज़िकल कीबोर्ड"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"कीबोर्ड का लेआउट चुनें"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफ़ॉल्ट"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"स्क्रीन चालू करने की अनुमति"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"इन ऐप के पास स्क्रीन को चालू करने का कंट्रोल है"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रीन चालू करने की अनुमति दें"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ऐप्लिकेशन को स्क्रीन चालू करने की अनुमति दें. ऐसा करने पर, ऐप्लिकेशन आपकी अनुमति लिए बिना भी, जब चाहे स्क्रीन चालू कर सकता है."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 0aba7cd..0271b09 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Lijeva strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Desna strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivan"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Spremljeno"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktivno (samo lijevo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tipkovnica"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tipkovnice"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zadano"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Uključivanje zaslona"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrola za uključivanje zaslona"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Dopusti uključivanje zaslona"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Dopustite aplikaciji da uključuje zaslon. Ako date to dopuštenje, aplikacija može uključiti zaslon u bilo kojem trenutku bez vaše izričite namjere."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index e01c20a..5c06624 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Akkumulátorok töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (bal) és <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (jobb)."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (bal)."</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (jobb)."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktív"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Mentve"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktív (csak bal)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizikai billentyűzet"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Billentyűzetkiosztás kiválasztása"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Alapértelmezett"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Képernyő bekapcsolása"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Képernyő-bekapcsolási vezérlő"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"A képernyő bekapcsolásának engedélyezése"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"A képernyő bekapcsolásának engedélyezése az adott alkalmazás számára. Ha megadja az engedélyt, az alkalmazás az Ön kifejezett szándéka nélkül, bármikor bekapcsolhatja a képernyőt."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 5e3d779..805284e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Ձախ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, աջ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>։"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Ձախ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Աջ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ակտիվ է"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Պահված է"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ակտիվ է (միայն ձախ)"</string>
@@ -159,7 +163,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Չեղարկել"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Զուգակցում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ՝ սխալ PIN-ի կամ անցաբառի պատճառով:"</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ՝ սխալ PIN-ի կամ մուտքի բանալու պատճառով:"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Հնարավոր չէ կապ հաստատել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Զուգավորումը մերժվեց <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի կողմից:"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Համակարգիչ"</string>
@@ -258,7 +262,7 @@
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Զուգակցեք նոր սարքեր՝ օգտագործելով վեցանիշ կոդը"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Զուգակցված սարքեր"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Միացված է"</string>
- <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Սարքի տվյալները"</string>
+ <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Սարքի տվյալներ"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Հեռացնել"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Սարքի մատնահետք՝ <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Չհաջողվեց միացնել"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Ֆիզիկական ստեղնաշար"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Ընտրեք ստեղնաշարի դասավորությունը"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Կանխադրված"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Էկրանի միացում"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Էկրանի միացման կառավարում"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Թույլատրել հավելվածին միացնել էկրանը"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Եթե թույլ տաք, հավելվածը ցանկացած ժամանակ կկարողանա միացնել էկրանը՝ առանց ձեր բացահայտ համաձայնության։"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 79fb4da..6b03ae5 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Baterai L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Kiri: Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Kanan: Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Disimpan"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktif (hanya kiri)"</string>
@@ -490,10 +494,10 @@
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sampai penuh"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dioptimalkan"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Mengisi daya"</string>
- <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Penuh dalam <xliff:g id="TIME">%3$s</xliff:g>"</string>
+ <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Penuh pukul <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Baterai terisi penuh dalam <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Baterai terisi penuh dalam <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Penuh dalam <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Penuh pukul <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Keyboard fisik"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih tata letak keyboard"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Pengaktifan layar"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrol pengaktifan layar"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Izinkan pengaktifan layar"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Mengizinkan aplikasi mengaktifkan layar. Jika diizinkan, aplikasi dapat mengaktifkan layar kapan saja tanpa izin Anda."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index dfb780d..d89da77 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlöðuhleðsla."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Vinstri: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Hægri: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Virkt"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Vistað"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Kveikt (eingöngu vinstra)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Vélbúnaðarlyklaborð"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Veldu lyklaskipan"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Sjálfgefið"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Kveikja á skjánum"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Stýring til að kveikja á skjá"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Leyfa að kveikt sé á skjánum"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Leyfa forriti að kveikja á skjánum. Ef þetta er leyft getur forritið kveikt á skjánum hvenær sem er án þess að þú samþykkir það sérstaklega."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 26b9c64..92f9554 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"S: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> di batteria. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> di batteria."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Sinistro: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Destro: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Attivo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Dispositivo salvato"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Attivo (solo sinistro)"</string>
@@ -493,7 +497,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Ricarica completa entro <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batteria completamente carica entro <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Batteria completamente carica entro <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Ricarica completa entro <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Ricarica completa entro le ore <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fisica"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Scegli layout tastiera"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinito"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Attiva lo schermo"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Controllo di attivazione dello schermo"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Consenti l\'attivazione dello schermo"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Consenti a un\'app di attivare lo schermo. Se la autorizzi, l\'app può attivare lo schermo in qualsiasi momento senza la tua autorizzazione esplicita."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c232396..5eb9170 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"סוללה בצד שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, סוללה בצד ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"סוללה בצד שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"סוללה בצד ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"פעיל"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"בוצעה שמירה"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"פעיל (שמאל בלבד)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"מקלדת פיזית"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"בחירה של פריסת המקלדת"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ברירת מחדל"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"הפעלת המסך"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"שליטה בהפעלת המסך"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"הרשאה להפעלת המסך"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"הרשאה לאפליקציה להפעיל את המסך. אם מעניקים את ההרשאה, האפליקציה יכולה להפעיל את המסך בכל זמן, גם בלי שמתכוונים לכך במפורש."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 4d2f8fc..acdad9c 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> から退出しました"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"右 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"有効"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"保存済み"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"アクティブ(左のみ)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"物理キーボード"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"キーボード レイアウトの選択"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"デフォルト"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"画面をオンにする"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"画面をオンにする設定"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"画面をオンにすることを許可する"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"画面をオンにすることをアプリに許可します。許可すると、ユーザーからの明示的インテントを必要とせずに、アプリがいつでも画面をオンにできるようになります。"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> のブロードキャストを停止しますか?"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 4ade50f..4efebc5 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -105,6 +105,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"მარცხენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, მარჯვენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ბატარეა."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"მარცხენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ბატარეა"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"მარჯვენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ბატარეა"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"მარცხენა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"მარჯვენა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"აქტიური"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"შენახული"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"აქტიური (მხოლოდ მარცხენა)"</string>
@@ -573,7 +575,7 @@
<string name="zen_mode_forever" msgid="3339224497605461291">"გამორთვამდე"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ეს ტელეფონი"</string>
- <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ეს ტაბლეტი"</string>
+ <string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ამ ტაბლეტზე"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"სამაგრის დინამიკი"</string>
@@ -710,7 +712,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ფიზიკური კლავიატურა"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"აირჩიე კლავიატურის განლაგება"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ნაგულისხმევი"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ჩართეთ ეკრანი"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ეკრანის ჩართვის მართვის საშუალებები"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ეკრანის ჩართვის დაშვება"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"დართეთ ნება აპს, ჩართოს ეკრანი. თუ ამ ნებართვას მიანიჭებთ, აპმა შეიძლება ნებისმიერ დროს ჩართოს ეკრანი თქვენი ცალსახა განზრახვის გარეშე."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"გსურთ <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ტრანსლაციის შეჩერება?"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 4e034b4..0efe609 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Сол жақ: батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Оң жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Сол жақ: батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Оң жақ: батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Қосулы"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Сақталған"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Істеп тұр (тек сол жағы)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Пернетақта"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Пернетақтаның орналасу ретін таңдау"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Әдепкі"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Экранды қосу"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Экранның қосылуын басқару"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Экранды қосуға рұқсат беру"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Қолданбаға экранды қосуға рұқсат береді. Рұқсат берілсе, қолданба кез келген уақытта экранды өздігінен қосуы мүмкін."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 60f88ea..0882327 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>។"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"សកម្ម"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"បានរក្សាទុក"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"សកម្ម (ខាងឆ្វេងប៉ុណ្ណោះ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ក្ដារចុចរូបវន្ត"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ជ្រើសរើសប្លង់ក្ដារចុច"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"លំនាំដើម"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"បើកអេក្រង់"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ការគ្រប់គ្រងការបើកអេក្រង់"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"អនុញ្ញាតឱ្យបើកអេក្រង់"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"អនុញ្ញាតឱ្យកម្មវិធីបើកអេក្រង់។ ប្រសិនបើអនុញ្ញាត កម្មវិធីអាចបើកអេក្រង់បានគ្រប់ពេល ទោះបីជាអ្នកគ្មានបំណងធ្វើអន្តរកម្មក៏ដោយ។"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 6594b5e..d47c76b 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ಎಡ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ಬಲ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ಎಡ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ಬಲ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ಸಕ್ರಿಯ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ಸಕ್ರಿಯವಾಗಿದೆ (ಎಡಕಿವಿಯ ಸಾಧನ ಮಾತ್ರ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆರಿಸಿ"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ಡೀಫಾಲ್ಟ್"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ಸ್ಕ್ರೀನ್-ಆನ್ ನಿಯಂತ್ರಣ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್ ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್ ಮಾಡಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಿ. ಅನುಮತಿಸಿದರೆ, ನಿಮಗೆ ಅಗತ್ಯವಿಲ್ಲದಿದ್ದಾಗಲೂ ಆ್ಯಪ್ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್ ಮಾಡಬಹುದು."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಬೇಕೆ?"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index d93af73..51c8475 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"배터리는 왼쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>입니다."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"왼쪽 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"오른쪽 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"활성"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"저장됨"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"활성(왼쪽만)"</string>
@@ -493,7 +497,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - <xliff:g id="TIME">%3$s</xliff:g>에 완전히 충전됨"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>에 완전히 충전됨"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"<xliff:g id="TIME">%1$s</xliff:g>에 완전히 충전됨"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g>에 완전히 충전됨"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g>까지 완전히 충전됨"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"물리적 키보드"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"키보드 레이아웃 선택"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"기본"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"화면 켜기"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"화면 사용 설정 제어"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"화면 켜기 허용"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"앱에서 화면을 켜도록 허용합니다. 권한이 부여된 경우 앱에서 명시적 인텐트 없이 언제든지 화면을 켤 수 있습니다."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 4a76d550..0560a81 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Батарея: L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Сол кулак – батареянын деңгээли: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Оң кулак – батареянын деңгээли: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Жигердүү"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Сакталган"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Иштеп жатат (сол тарап гана)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Аппараттык баскычтоп"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Тергичтин жайылмасын тандоо"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Демейки"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Экранды күйгүзүү"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Экранды күйгүзүүнү башкаруу"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Экранды күйгүзүүгө уруксат берүү"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Колдонмого экранды күйгүзүүгө уруксат бересиз. Колдонмо экранды каалаган убакта сизден уруксат сурабастан күйгүзө берет."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index a6040ef..f6a2681 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ຊ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ຂ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ຊ້າຍ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ຂວາ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"ຊ້າຍ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"ຂວາ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ອອນລາຍ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ບັນທຶກແລ້ວ"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ນຳໃຊ້ຢູ່ (ຊ້າຍເທົ່ານັ້ນ)"</string>
@@ -120,7 +122,7 @@
<string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍເທົ່ານັ້ນ"</string>
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຂວາເທົ່ານັ້ນ"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍ ແລະ ຂວາ"</string>
- <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ສຽງ"</string>
+ <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ສຽງມີເດຍ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ການໂທ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ການໂອນຍ້າຍໄຟລ໌"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ອຸປະກອນປ້ອນຂໍ້ມູນ"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ແປ້ນພິມພາຍນອກ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ຄ່າເລີ່ມຕົ້ນ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ເປີດໜ້າຈໍ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ການຄວບຄຸມການເປີດໜ້າຈໍ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ອະນຸຍາດໃຫ້ເປີດໜ້າຈໍ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ອະນຸຍາດໃຫ້ແອັບເປີດໜ້າຈໍໄດ້. ຫາກອະນຸມັດ, ແອັບຈະສາມາດເປີດໜ້າຈໍຕອນໃດກໍໄດ້ໂດຍທີ່ທ່ານບໍ່ຕ້ອງມີເຈດຕະນາຢ່າງຈະແຈ້ງ."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b84cefb..4abde8f 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Akumuliatoriaus lygis kairėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dešinėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Akumuliatoriaus lygis kairėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Akumuliatoriaus lygis dešinėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Kairė: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Dešinė: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktyvus"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Išsaugota"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktyvus (tik kairiojoje pusėje)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizinė klaviatūra"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatūros išdėstymo pasirinkimas"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Numatytasis"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekrano įjungimas"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekrano įjungimo valdiklis"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Leisti įjungti ekraną"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Leiskite programai įjungti ekraną. Jei suteiksite leidimą, programa galės įjungti ekraną bet kuriuo metu be nurodyto tikslo."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c07fae3..201c7a0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Akumulatora uzlādes līmenis labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktīvs"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saglabāta"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ierīce aktīva (tikai kreisā auss)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziskā tastatūra"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastatūras izkārtojuma izvēle"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Noklusējums"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekrāna ieslēgšana"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekrāna ieslēgšanas vadīkla"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Atļaut ieslēgt ekrānu"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Atļaujiet lietotnei ieslēgt ekrānu. Ja to atļausiet, lietotne varēs jebkurā laikā ieslēgt ekrānu bez tiešas jūsu piekrišanas."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index be8d039..a72a72e 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активен"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Зачувано"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Активно (само лево)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избери распоред на тастатура"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Стандардно"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Вклучување на екранот"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Контрола за вклучување на екранот"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Дозволи вклучување на екранот"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Дозволете одредена апликација да го вклучува екранот. Ако е дозволено, апликацијата ќе може да го вклучува екранот во секое време без ваша намера."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Да се прекине емитувањето на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 5f21c34..9cf6268 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, വലതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"വലത് വശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"ഇടത് വശത്ത് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"വലത് വശത്ത് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"സജീവം"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"സംരക്ഷിച്ചു"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"സജീവമാണ് (ഇടതുഭാഗത്ത് മാത്രം)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ഫിസിക്കൽ കീബോർഡ്"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ഡിഫോൾട്ട്"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"സ്ക്രീൻ ഓണാക്കുക"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"സ്ക്രീൻ ഓണാക്കാനുള്ള നിയന്ത്രണം"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"സ്ക്രീൻ ഓണാക്കാൻ അനുവദിക്കുക"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"സ്ക്രീൻ ഓണാക്കാൻ ആപ്പിനെ അനുവദിക്കുക. അനുവദിക്കുകയാണെങ്കിൽ, നിങ്ങളുടെ താൽപ്പര്യം കൂടാതെ ഏതുസമയത്തും സ്ക്രീൻ ഓണാക്കാൻ ആപ്പിന് കഴിയും."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 66efe8b..41afe435 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Зүүн: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Баруун: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Идэвхтэй"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Хадгалсан"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Идэвхтэй (зөвхөн зүүн тал)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Биет гар"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Гарын бүдүүвчийг сонгох"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Өгөгдмөл"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Дэлгэцийг асаах"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Дэлгэц асаах тохиргоо"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Дэлгэцийг асаахыг зөвшөөрөх"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Аппад дэлгэцийг асаахыг зөвшөөрнө үү. Зөвшөөрсөн тохиолдолд тухайн апп таны тодорхой оролцоогүйгээр ямар ч үед дэлгэцийг асааж болно."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index fecb91f..b68fc71 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"डावीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, उजवीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"डावीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"उजवीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"डावीकडे <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"उजवीकडे <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"अॅक्टिव्ह"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"सेव्ह केली आहेत"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"अॅक्टिव्ह आहे (फक्त डावे)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"वास्तविक कीबोर्ड"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट निवडा"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"डीफॉल्ट"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"स्क्रीन सुरू करा"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"स्क्रीन सुरू करण्यासंबंधित नियंत्रण"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रीन सुरू करण्यासाठी अनुमती द्या"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"स्क्रीन सुरू करण्यासाठी ॲपला अनुमती द्या. अनुमती दिल्यास, ॲप तुमच्या स्पष्ट हेतूशिवाय कधीही स्क्रीन सुरू करू शकते."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index e8e9e7eb..50f0c2e 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Kiri: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Kanan: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Kiri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Kanan <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Disimpan"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktif (kiri sahaja)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Papan kekunci fizikal"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih susun atur papan kekunci"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Lalai"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Hidupkan skrin"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kawalan untuk menghidupkan skrin"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Benarkan apl menghidupkan skrin"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Benarkan apl menghidupkan skrin. Jika dibenarkan, apl boleh menghidupkan skrin pada bila-bila masa tanpa niat eksplisit anda."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index b3317e4..aa21f3c 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ဘက်ထရီ L- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>၊ R- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>။"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ဘယ်- ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ညာ- ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"ဘယ် <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"ညာ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ဖွင့်ထားသည်"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"သိမ်းထားသည်များ"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"သုံးနေသည် (ဘယ်ဘက်သီးသန့်)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ပကတိ ကီးဘုတ်"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"လက်ကွက်အပြင်အဆင်ရွေးချယ်ခြင်း"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"မူရင်း"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ဖန်သားပြင် ဖွင့်ခြင်း"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ဖန်သားပြင်ဖွင့်ခြင်း စီမံရန်"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ဖန်သားပြင် ဖွင့်ခွင့်ပြုရန်"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"အက်ပ်ကို ဖန်သားပြင် ဖွင့်ခွင့်ပြုနိုင်သည်။ ခွင့်ပြုထားပါက သင်က တစ်စုံတစ်ခု လုပ်ဆောင်ရန် မရည်ရွယ်သော်လည်း အက်ပ်သည် ဖန်သားပြင်ကို အချိန်မရွေး ဖွင့်နိုင်မည်။"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f1ea63b..bd1659c 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Høyre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Lagret"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiv (bare venstre)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Velg et tastaturoppsett"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Slå på skjermen"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontroller når skjermen slås på"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Tillat å slå på skjermen"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tillat at en app slår på skjermen. Hvis tillatelsen gis, kan appen slå på skjermen når som helst uten din eksplisitte intensjon."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 8bafef3..5032e35 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ब्याट्री।"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"बायाँ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"दायाँ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"सक्रिय"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"सेभ गरिएको"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"सक्रिय छ (बायाँ मात्र)"</string>
@@ -526,7 +528,7 @@
<string name="screen_zoom_summary_large" msgid="4706951482598978984">"ठुलो"</string>
<string name="screen_zoom_summary_very_large" msgid="7317423942896999029">"अझ ठुलो"</string>
<string name="screen_zoom_summary_extremely_large" msgid="1438045624562358554">"सबैभन्दा ठुलो"</string>
- <string name="screen_zoom_summary_custom" msgid="3468154096832912210">"आफू अनुकूल (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
+ <string name="screen_zoom_summary_custom" msgid="3468154096832912210">" कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="content_description_menu_button" msgid="6254844309171779931">"मेनु"</string>
<string name="retail_demo_reset_message" msgid="5392824901108195463">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्टि गर्नुहोस्"</string>
<string name="retail_demo_reset_next" msgid="3688129033843885362">"अर्को"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"भौतिक किबोर्ड"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट छान्नुहोस्"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफल्ट"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"स्क्रिन अन गर्नुहोस्"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"स्क्रिन अन गर्नेसम्बन्धी कन्ट्रोल"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रिन अन गर्ने अनुमति दिनुहोस्"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"कुनै एपलाई स्क्रिन अन गर्ने अनुमति दिनुहोस्। यो अनुमति दिइएका खण्डमा तपाईंले अन गर्न नखोजेका बेलामा पनि एपले जुनसुकै बेला स्क्रिन अन गर्न सक्छ।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 00c3acb..226f592 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Links: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Rechts: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Links <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Rechts <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actief"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Opgeslagen"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Actief (alleen links)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiek toetsenbord"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Toetsenbordindeling kiezen"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standaard"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Scherm aanzetten"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Bedieningselement voor aanzetten van scherm"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Scherm aanzetten toestaan"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Sta toe dat een app het scherm aanzet. Indien toegestaan, kan de app het scherm op elk moment aanzetten zonder jouw expliciete intentie."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index 28a8db6..37e5071 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -186,11 +186,11 @@
</string-array>
<string-array name="select_logd_size_summaries">
<item msgid="409235464399258501">"ବନ୍ଦ"</item>
- <item msgid="4195153527464162486">"64K ପିଛା ଲଗ୍ ବଫର୍"</item>
- <item msgid="7464037639415220106">"256K ଲଗ୍ ପ୍ରତି ବଫର୍"</item>
- <item msgid="8539423820514360724">"ପ୍ରତି ଲଗ ବଫର ପାଇଁ 1M"</item>
- <item msgid="1984761927103140651">"ଲଗ୍ ବଫର୍ ପ୍ରତି 4M"</item>
- <item msgid="2983219471251787208">"ଲଗ୍ ବଫର୍ ପ୍ରତି 8M"</item>
+ <item msgid="4195153527464162486">"ପ୍ରତି ଲଗ ବଫର 64K"</item>
+ <item msgid="7464037639415220106">"ପ୍ରତି ଲଗ ବଫର 256K"</item>
+ <item msgid="8539423820514360724">"ପ୍ରତି ଲଗ ବଫର 1M"</item>
+ <item msgid="1984761927103140651">"ପ୍ରତି ଲଗ ବଫର 4M"</item>
+ <item msgid="2983219471251787208">"ପ୍ରତି ଲଗ ବଫର 8M"</item>
</string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"ବନ୍ଦ"</item>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ab150c2..8fc58d1 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -94,7 +94,7 @@
<string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"ସଂଯୁକ୍ତ ନାହିଁ (ଫୋନ୍ ନୁହେଁ), ବ୍ୟାଟେରୀ<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"ସଂଯୁକ୍ତ ହେଲା (ମିଡିଆ ନୁହେଁ), ବ୍ୟାଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"ସଂଯୁକ୍ତ ହେଲା (ଫୋନ୍ କିମ୍ବା ମେଡିଆ ନୁହେଁ), ବ୍ୟାଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"ସକ୍ରିୟ ଅଛନ୍ତି। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string>
+ <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"ସକ୍ରିୟ ଅଛି। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"ସକ୍ରିୟ ଅଛନ୍ତି। ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ।"</string>
<string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"ସକ୍ରିୟ ଅଛି। ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string>
<string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"ସକ୍ରିୟ ଅଛି। ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string>
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ।"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ସକ୍ରିୟ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ସେଭ କରାଯାଇଛି"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ସକ୍ରିୟ (କେବଳ ବାମ)"</string>
@@ -121,7 +125,7 @@
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), କେବଳ ଡାହାଣ"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), ବାମ ଏବଂ ଡାହାଣ"</string>
<string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ମିଡିଆ ଅଡିଓ"</string>
- <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ଫୋନ୍ କଲ୍ଗୁଡ଼ିକ"</string>
+ <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ଫୋନ କଲ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ଇନ୍ପୁଟ୍ ଡିଭାଇସ୍"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ଇଣ୍ଟରନେଟ ଆକ୍ସେସ"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ଫିଜିକାଲ କୀବୋର୍ଡ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"କୀବୋର୍ଡ ଲେଆଉଟ ବାଛନ୍ତୁ"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ଡିଫଲ୍ଟ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ସ୍କ୍ରିନକୁ ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ସ୍କ୍ରିନ ଚାଲୁ କରିବା ପାଇଁ ନିୟନ୍ତ୍ରଣ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ସ୍କ୍ରିନକୁ ଚାଲୁ କରିବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ସ୍କ୍ରିନକୁ ଚାଲୁ କରିବା ପାଇଁ ଏକ ଆପକୁ ଅନୁମତି ଦିଅନ୍ତୁ। ଯଦି ଅନୁମତି ଦିଆଯାଏ, ତେବେ ଆପଟି ଆପଣଙ୍କ ଏକ୍ସପ୍ଲିସିଟ ଇଣ୍ଟେଣ୍ଟ ବିନା ଯେ କୌଣସି ସମୟରେ ସ୍କ୍ରିନକୁ ଚାଲୁ କରିପାରେ।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 0e77a04..36a52b2 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ਖੱਬੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ਸੱਜੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ।"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ਖੱਬੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ਸੱਜੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ਕਿਰਿਆਸ਼ੀਲ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਖੱਬਾ)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ਕੀ-ਬੋਰਡ ਖਾਕਾ ਚੁਣੋ"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"ਸਕ੍ਰੀਨ ਨੂੰ ਚਾਲੂ ਕਰਨ ਵਾਲੀ ਸੈਟਿੰਗ ਸੰਬੰਧੀ ਕੰਟਰੋਲ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰਨ ਦਿਓ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ਐਪ ਨੂੰ ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰਨ ਦਿਓ। ਇਜਾਜ਼ਤ ਦਿੱਤੇ ਜਾਣ \'ਤੇ, ਇਹ ਐਪ ਤੁਹਾਡੇ ਇਰਾਦੇ ਦੇ ਬਿਨਾਂ ਕਿਸੇ ਵੇਲੇ ਵੀ ਸਕ੍ਰੀਨ ਨੂੰ ਚਾਲੂ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 0906d4b..da68889 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> naładowania baterii."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Po lewej <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Po prawej <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Urządzenie aktywne"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Zapisano"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktywne (tylko lewa strona)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Klawiatura fizyczna"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Wybierz układ klawiatury"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Domyślny"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Włączanie ekranu"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Opcja włączenia ekranu"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Zezwalaj na włączanie ekranu"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Zezwalaj na włączanie ekranu przez aplikację. Gdy przyznasz te uprawnienia, aplikacja będzie mogła w dowolnym momencie włączyć ekran bez Twojego wyraźnego pozwolenia."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d054d9b..2676ff6 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ativo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Salvo"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ativo (apenas o esquerdo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ligar tela"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Controle de ativação da tela"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir que a tela seja ligada"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permitir que um app ative a tela. Com sua autorização, o app vai poder ligar a tela a qualquer momento, sem você pedir."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 0bcca15..a40b95f 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ativo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Guardado"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ativo (apenas esquerdo)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha um esquema de teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinição"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ativação do ecrã"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Controlo de ativação do ecrã"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir a ativação do ecrã"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permita que uma app ative o ecrã. Se a autorização for concedida, a app pode ativar o ecrã em qualquer altura sem a sua intenção explícita."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d054d9b..2676ff6 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ativo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Salvo"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Ativo (apenas o esquerdo)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ligar tela"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Controle de ativação da tela"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir que a tela seja ligada"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permitir que um app ative a tela. Com sua autorização, o app vai poder ligar a tela a qualquer momento, sem você pedir."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index ea97c37..4c97658 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Nivelul bateriei din dreapta:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activ"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Salvat"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Activ (numai stânga)"</string>
@@ -493,7 +497,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Timp rămas <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Complet încărcat în <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Complet încărcat în <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Timp rămas <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Încărcare completă la <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tastatură fizică"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Alege aspectul tastaturii"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Prestabilit"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Activează ecranul"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Comandă pentru activarea ecranului"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Permite activarea ecranului"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permite unei aplicații să activeze ecranul. Dacă acorzi permisiunea, aplicația poate să activeze oricând ecranul, fără intenția ta explicită."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Oprești difuzarea <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index aaf648e..505a1ec 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (Л)"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (П)"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Сохранено"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Используется (только левый)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Физическая клавиатура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Выберите раскладку клавиатуры"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"По умолчанию"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Включение экрана"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Управление включением экрана"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Разрешить приложению включать экран"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Приложение сможет в любое время включать экран без явного согласия с вашей стороны"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Остановить трансляцию \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index ab423b5..6e4b5f9 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"බැටරිය ව: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ද: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"වම: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"දකුණ: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ක්රියාකාරී"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"සුරැකිණි"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"සක්රිය (වම පමණි)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"භෞතික යතුරු පුවරුව"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"යතුරු පුවරු පිරිසැලසුම තෝරන්න"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"පෙරනිමි"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"තිරය ක්රියාත්මක කරන්න"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"තිරය ක්රියාත්මක කිරීමේ පාලනය"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"තිරය ක්රියාත්මක කිරීමට ඉඩ දෙන්න"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"යෙදුමකට තිරය ක්රියාත්මක කිරීමට ඉඩ දෙන්න. ඉඩ දුනහොත්, යෙදුම ඔබගේ පැහැදිලි අභිප්රායෙන් තොරව ඕනෑම වේලාවක තිරය ක්රියාත්මක කළ හැකිය."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 7922b70..64c1113 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Ľavá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Pravá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktívne"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Uložené"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktívne (iba ľavé)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnica"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vyberte rozloženie klávesnice"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predvolené"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Zapínanie obrazovky"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ovládanie zapínania obrazovky"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Povoliť zapínanie obrazovky"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Povoľte aplikácii zapínať obrazovku. Ak to urobíte, aplikácia bude môcť kedykoľvek zapínať obrazovku, a to aj vtedy, keď to nebudete mať v úmysle."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Chcete zastaviť vysielanie aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 301e377..bd35c82 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -190,7 +190,7 @@
<item msgid="7464037639415220106">"256 K/medpomnilnik dnevnika"</item>
<item msgid="8539423820514360724">"1 M/medpomnilnik dnevnika"</item>
<item msgid="1984761927103140651">"4 M/medpomnilnik dnevnika"</item>
- <item msgid="2983219471251787208">"8M/medpomnilnik dnevnika"</item>
+ <item msgid="2983219471251787208">"8 M/medpomnilnik dnevnika"</item>
</string-array>
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"Izklopljeno"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index d412f57..5460c3b 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Baterija – L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Levo – baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Desno – baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Leva: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Desna: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Shranjeno"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktivno (samo levo)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizična tipkovnica"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Izbira razporeditve tipkovnice"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Privzeto"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Vklop zaslona"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Upravljanje vklopa zaslona"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Dovoli vklop zaslona"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Dovolite aplikaciji, da vklopi zaslon. Če ji to odobrite, lahko aplikacija kadar koli brez vašega eksplicitnega namena vklopi zaslon."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 944d992..0288ec2 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Majtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateri, djathtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateri."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Majtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Djathtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Të ruajtura"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktive (vetëm majtas)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fizike"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zgjidh strukturën e tastierës"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Parazgjedhja"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ndiz ekranin"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrolli i aktivizimit të ekranit"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Lejo ndezjen e ekranit"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Lejo një aplikacion që të ndezë ekranin. Nëse lejohet, aplikacioni mund ta ndezë ekranin në çdo kohë pa synimin tënd të shprehur."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Të ndalohet transmetimi i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 1bb801d..927b8e4 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активан"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Сачувано"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Активно (само лево)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Одаберите распоред тастатуре"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Подразумевано"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Укључивање екрана"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Контрола укључивања екрана"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Дозволи укључивање екрана"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Дозвољава апликацији да укључи екран. Ако се омогући, апликација може да укључи екран у било ком тренутку без ваше експлицитне намере."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Желите да зауставите емитовање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index cc32432..7c6a832 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Vänster: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Höger: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Sparad"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktiv (endast vänster)"</string>
@@ -294,7 +298,7 @@
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Begränsning av wifi-sökning"</string>
<string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Slumpgenerering av icke-beständig MAC för wifi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata alltid aktiverad"</string>
- <string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvaruacceleration för internetdelning"</string>
+ <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hårdvaruacceleration för internetdelning"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inaktivera Absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivera Gabeldorsche"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiskt tangentbord"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Välj en tangentbordslayout"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Aktivera skärmen"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Inställningar för att sätta på skärmen"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Tillåt att skärmen aktiveras"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tillåt att en app aktiverar skärmen. Om du ger tillåtelse kan appen aktivera skärmen när som helst utan din uttryckliga avsikt."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 0eac15c..00f4349 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Kushoto <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Kulia <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Kimeunganishwa"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Imeokoa"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Inatumika (kushoto pekee)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Kibodi halisi"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chagua mpangilio wa kibodi"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Chaguomsingi"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Washa skrini"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kudhibiti mipangilio ya kuwasha skrini"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Ruhusu kuwasha skrini"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Ruhusu programu iwashe skrini. Ikiwa imepewa idhini, programu inaweza kuwasha skrini wakati wowote bila utaratibu wako dhahiri wa kuratibu."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Ungependa kusimamisha utangazaji kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7c87eb7..4b67011 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"இடது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, வலது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"இடது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"வலது: - <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"செயலில் உள்ளது"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"சேமிக்கப்பட்டது"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"செயலில் உள்ளது (இடதுபுறம் மட்டும்)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"கீபோர்டு"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"கீபோர்டு தளவமைப்பைத் தேர்வுசெய்தல்"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"இயல்பு"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"திரையை ஆன் செய்தல்"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"திரையை இயக்குவதற்கான கட்டுப்பாடு"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"திரையை ஆன் செய்வதை அனுமதி"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"திரையை ஆன் செய்ய ஓர் ஆப்ஸை அனுமதிக்கவும். அனுமதித்தால், உங்கள் தலையீடு இல்லாமலே ஆப்ஸ் எப்போது வேண்டுமானாலும் திரையை ஆன் செய்யக்கூடும்."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 689ea6f1..b7446c2 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"కుడి వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"ఎడమ వైపు <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"కుడి వైపు <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"యాక్టివ్గా ఉంది"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"సేవ్ చేయబడింది"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"యాక్టివ్గా ఉంది (ఎడమ వైపు మాత్రమే)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"భౌతిక కీబోర్డ్"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"కీబోర్డ్ లేఅవుట్ను ఎంచుకోండి"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ఆటోమేటిక్ సెట్టింగ్"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"స్క్రీన్ను ఆన్ చేయండి"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"స్క్రీన్ను ఆన్ చేయడానికి సంబంధించిన కంట్రోల్"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"స్క్రీన్ను ఆన్ చేయడానికి అనుమతించండి"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"స్క్రీన్ను ఆన్ చేయడానికి యాప్ను అనుమతించండి. మంజూరు చేయబడితే, మీ స్పష్టమైన ఉద్దేశం లేకుండా యాప్ ఎప్పుడైనా స్క్రీన్ను ఆన్ చేయవచ్చు."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 1899914..afda7cb 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"ซ้าย: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"ขวา: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"ฝั่งซ้าย <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"ฝั่งขวา <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ใช้งานอยู่"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"บันทึกแล้ว"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ใช้งานอยู่ (เฉพาะข้างซ้าย)"</string>
@@ -126,7 +128,7 @@
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"อุปกรณ์อินพุต"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"การเข้าถึงอินเทอร์เน็ต"</string>
<string name="bluetooth_profile_pbap" msgid="2103406516858653017">"ให้เข้าถึงรายชื่อติดต่อและประวัติการโทร"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"จะมีการใช้ข้อมูลเพื่อประกาศการโทรและอื่นๆ"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"ข้อมูลนี้จะถูกใช้เพื่อแจ้งการโทรและอื่นๆ"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"การแชร์การเชื่อมต่ออินเทอร์เน็ต"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"ข้อความ"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"การเข้าถึงซิม"</string>
@@ -371,7 +373,7 @@
<string name="media_category" msgid="8122076702526144053">"สื่อ"</string>
<string name="debug_monitoring_category" msgid="1597387133765424994">"การตรวจสอบ"</string>
<string name="strict_mode" msgid="889864762140862437">"เปิดใช้งานโหมดเข้มงวด"</string>
- <string name="strict_mode_summary" msgid="1838248687233554654">"กะพริบหน้าจอเมื่อแอปทำงานในชุดข้อความหลักนาน"</string>
+ <string name="strict_mode_summary" msgid="1838248687233554654">"กะพริบหน้าจอเมื่อแอปทำงานในเทรดหลักนาน"</string>
<string name="pointer_location" msgid="7516929526199520173">"ตำแหน่งของตัวชี้"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"การวางซ้อนหน้าจอที่แสดงข้อมูลการแตะในปัจจุบัน"</string>
<string name="show_touches" msgid="8437666942161289025">"แสดงการแตะ"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"แป้นพิมพ์จริง"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"เลือกรูปแบบแป้นพิมพ์"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ค่าเริ่มต้น"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"เปิดหน้าจอ"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"การควบคุมการเปิดหน้าจอ"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"อนุญาตให้เปิดหน้าจอ"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"อนุญาตให้แอปเปิดหน้าจอ หากอนุญาต แอปอาจเปิดหน้าจอได้ทุกเมื่อแม้คุณไม่ได้ระบุเจตนาที่ชัดแจ้ง"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 64f5190..936f521 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Kaliwa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Kanan: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Kaliwa <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Kanan <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktibo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Na-save"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktibo (kaliwa lang)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Pisikal na keyboard"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pumili ng layout ng keyboard"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"I-on ang screen"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kontrol ng pag-on sa screen"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Payagan ang pag-on sa screen"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Nagpapahintulot sa app na i-on ang screen. Kung papayagan, puwedeng i-on ng app ang screen anumang oras nang wala ng iyong malinaw na intent."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 144c20b..97d20bf 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil seviyesi."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Etkin"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Kaydedildi"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Etkin (yalnızca sol taraf)"</string>
@@ -493,7 +497,7 @@
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - <xliff:g id="TIME">%3$s</xliff:g> içinde tamamen dolacak"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> içinde tamamen şarj olacak"</string>
<string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"<xliff:g id="TIME">%1$s</xliff:g> içinde tamamen şarj olacak"</string>
- <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g> içinde tamamen dolacak"</string>
+ <string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g> itibarıyla tamamen dolacak"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziksel klavye"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klavye düzenini seçin"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Varsayılan"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekranı açma"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekran açma kontrolü"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Ekranı açmaya izin ver"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Bir uygulamanın ekranı açmasına izin verin. İzin verildiğinde, uygulama sizin belirgin niyetiniz olmadan istediği zaman ekranı açabilir."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index ecfa2c9..ab1e7f6 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> заряду акумулятора."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активовано"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Збережено"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Активовано (лише лівий)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Фізична клавіатура"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Вибрати розкладку клавіатури"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"За умовчанням"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Увімкнення екрана"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Керування ввімкненням екрана"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Дозволити ввімкнення екрана"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Дозвольте додатку вмикати екран. Якщо ви надасте цей дозвіл, додаток зможе будь-коли вмикати екран пристрою навіть без вашого явного наміру."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index ed0b1df..3ac4d95 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری۔"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"بائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"دائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"بائیں <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"دائیں <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"فعال"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"محفوظ ہے"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"فعال ہے (صرف بایاں)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"فزیکل کی بورڈ"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"کی بورڈ لے آؤٹ منتخب کریں"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ڈیفالٹ"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"اسکرین آن کریں"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"اسکرین آن کرنے کیلئے کنٹرول"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"اسکرین آن کرنے کی اجازت دیں"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"ایپ کو اسکرین آن کرنے کی اجازت دیں۔ اگر اجازت دی گئی تو ایپ آپ کے واضح مقصد کے بغیر کسی بھی وقت اسکرین کو آن کر سکتی ہے۔"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> براڈکاسٹنگ روکیں؟"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 104f27b..f0a89b3 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (L), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (R)."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (chap)"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (oʻng)."</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Faol"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Saqlangan"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Faol (faqat chap)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tashqi klaviatura"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura sxemasini tanlang"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Asosiy"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekranni yoqish"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ekranni yoqish boshqaruvi"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Ekranni yoqishga ruxsat"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Ilovaga ekranni yoqishga ruxsat berish. Ruxsat berilsa, ilova istalgan vaqt ruxsatingizsiz ekranni yoqishi mumkin."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga translatsiya toʻxtatilsinmi?"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2ed847c..d85449e 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pin. Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pin."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"Bên trái <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Bên phải <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Đang hoạt động"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Đã lưu"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Đang hoạt động (chỉ tai trái)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Bàn phím thực"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chọn bố cục bàn phím"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Mặc định"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Bật màn hình"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Kiểm soát chế độ bật màn hình"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Cho phép bật màn hình"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Cho phép ứng dụng bật màn hình. Nếu được phép, ứng dụng có thể bật màn hình bất kỳ lúc nào kể cả khi bạn không có ý định như vậy."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 25ca0c2..20fd651 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"已保存的设备"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"使用中(仅左耳助听器)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"实体键盘"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"选择键盘布局"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"默认"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"唤醒屏幕"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"屏幕开启控件"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"允许开启屏幕"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"允许应用唤醒屏幕。如获授权,该应用便可在您未明确表达意愿的情况下随时唤醒屏幕。"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 60c71e0..556c0af 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量。"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"左耳機:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"右耳機:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"已儲存"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"使用中 (僅左側)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"開啟螢幕"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"螢幕開啟控制項"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"允許開啟螢幕"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"允許應用程式開啟螢幕。應用程式獲授權後,可在你未有明確表明意圖的情況下隨時開啟螢幕。"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 6159736..3f35957 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -103,6 +103,8 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"左側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"右側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"左耳機:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"右耳機:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"已儲存"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"使用中 (僅左側)"</string>
@@ -706,7 +708,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"開啟螢幕"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"螢幕開啟控制選項"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"允許開啟螢幕"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"允許應用程式開啟螢幕。如果授予這項權限,即使你未明確指示,應用程式也隨時可能會開啟螢幕。"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 0200c01..063d148 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -103,6 +103,10 @@
<string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri."</string>
<string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"Kwesobunxele: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri"</string>
<string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Kwesokudla: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_left (337629670583744410) -->
+ <skip />
+ <!-- no translation found for tv_bluetooth_battery_level_untethered_right (8610019317279155595) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Iyasebenza"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Ilondoloziwe"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Iyasebenza (ngakwesokunxele kuphela)"</string>
@@ -706,7 +710,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"Ikhibhodi ephathekayo"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Khetha isendlalelo sekhibhodi"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zenzekela"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"Vula isikrini"</string>
+ <string name="turn_screen_on_title" msgid="2662312432042116026">"Ukulawula ukuvula isikrini"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Vumela ukuvula isikrini"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Vumela i-app ivule isikrini. Uma kuvunyiwe, i-app ingavula isikrini noma nini ngaphandle kwenhloso yakho esobala."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 8917412..721e7b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -276,6 +276,14 @@
if (isUntetheredHeadset(bluetoothDevice)) {
return true;
}
+ if (Flags.enableDeterminingAdvancedDetailsHeaderWithMetadata()) {
+ // A FastPair device that use advanced details header must have METADATA_MAIN_ICON
+ if (getUriMetaData(bluetoothDevice, BluetoothDevice.METADATA_MAIN_ICON) != null) {
+ Log.d(TAG, "isAdvancedDetailsHeader is true with main icon uri");
+ return true;
+ }
+ return false;
+ }
// The metadata is for Android S
String deviceType =
getStringMetaData(bluetoothDevice, BluetoothDevice.METADATA_DEVICE_TYPE);
@@ -302,12 +310,15 @@
if (isUntetheredHeadset(bluetoothDevice)) {
return true;
}
- // The metadata is for Android S
- String deviceType =
- getStringMetaData(bluetoothDevice, BluetoothDevice.METADATA_DEVICE_TYPE);
- if (TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)) {
- Log.d(TAG, "isAdvancedUntetheredDevice: is untethered device ");
- return true;
+ if (!Flags.enableDeterminingAdvancedDetailsHeaderWithMetadata()) {
+ // The METADATA_IS_UNTETHERED_HEADSET of an untethered FastPair headset is always true,
+ // so there's no need to check the device type.
+ String deviceType =
+ getStringMetaData(bluetoothDevice, BluetoothDevice.METADATA_DEVICE_TYPE);
+ if (TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)) {
+ Log.d(TAG, "isAdvancedUntetheredDevice: is untethered device");
+ return true;
+ }
}
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index eae58ad..b7758de 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -40,6 +40,7 @@
import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static android.media.session.MediaController.PlaybackInfo;
import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
@@ -51,6 +52,8 @@
import android.media.MediaRoute2Info;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -135,19 +138,28 @@
@NonNull protected final UserHandle mUserHandle;
private final Collection<MediaDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
private MediaDevice mCurrentConnectedDevice;
+ private MediaController mMediaController;
+ private PlaybackInfo mLastKnownPlaybackInfo;
private final LocalBluetoothManager mBluetoothManager;
private final Map<String, RouteListingPreference.Item> mPreferenceItemMap =
new ConcurrentHashMap<>();
+ private final MediaController.Callback mMediaControllerCallback = new MediaControllerCallback();
+
/* package */ InfoMediaManager(
@NonNull Context context,
@NonNull String packageName,
@NonNull UserHandle userHandle,
- @NonNull LocalBluetoothManager localBluetoothManager) {
+ @NonNull LocalBluetoothManager localBluetoothManager,
+ @Nullable MediaController mediaController) {
mContext = context;
mBluetoothManager = localBluetoothManager;
mPackageName = packageName;
mUserHandle = userHandle;
+ mMediaController = mediaController;
+ if (mediaController != null) {
+ mLastKnownPlaybackInfo = mediaController.getPlaybackInfo();
+ }
}
/**
@@ -159,12 +171,19 @@
* speakers, as opposed to app-specific routing (for example, casting to another device).
* @param userHandle The {@link UserHandle} of the user on which the app to control is running,
* or null if the caller does not need app-specific routing (see {@code packageName}).
+ * @param token The token of the associated {@link MediaSession} for which to do media routing.
*/
public static InfoMediaManager createInstance(
Context context,
@Nullable String packageName,
@Nullable UserHandle userHandle,
- LocalBluetoothManager localBluetoothManager) {
+ LocalBluetoothManager localBluetoothManager,
+ @Nullable MediaSession.Token token) {
+ MediaController mediaController = null;
+
+ if (Flags.usePlaybackInfoForRoutingControls() && token != null) {
+ mediaController = new MediaController(context, token);
+ }
// The caller is only interested in system routes (headsets, built-in speakers, etc), and is
// not interested in a specific app's routing. The media routing APIs still require a
@@ -180,16 +199,16 @@
if (Flags.useMediaRouter2ForInfoMediaManager()) {
try {
return new RouterInfoMediaManager(
- context, packageName, userHandle, localBluetoothManager);
+ context, packageName, userHandle, localBluetoothManager, mediaController);
} catch (PackageNotAvailableException ex) {
// TODO: b/293578081 - Propagate this exception to callers for proper handling.
Log.w(TAG, "Returning a no-op InfoMediaManager for package " + packageName);
return new NoOpInfoMediaManager(
- context, packageName, userHandle, localBluetoothManager);
+ context, packageName, userHandle, localBluetoothManager, mediaController);
}
} else {
return new ManagerInfoMediaManager(
- context, packageName, userHandle, localBluetoothManager);
+ context, packageName, userHandle, localBluetoothManager, mediaController);
}
}
@@ -310,6 +329,9 @@
if (wasEmpty) {
mMediaDevices.clear();
registerRouter();
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ }
updateRouteListingPreference();
refreshDevices();
}
@@ -323,6 +345,9 @@
*/
public final void unregisterCallback(@NonNull MediaDeviceCallback callback) {
if (mCallbacks.remove(callback) && mCallbacks.isEmpty()) {
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
unregisterRouter();
}
}
@@ -389,7 +414,34 @@
private RoutingSessionInfo getActiveRoutingSession() {
// List is never empty.
final List<RoutingSessionInfo> sessions = getRoutingSessionsForPackage();
- return sessions.get(sessions.size() - 1);
+ RoutingSessionInfo activeSession = sessions.get(sessions.size() - 1);
+
+ // Logic from MediaRouter2Manager#getRoutingSessionForMediaController
+ if (!Flags.usePlaybackInfoForRoutingControls() || mMediaController == null) {
+ return activeSession;
+ }
+
+ PlaybackInfo playbackInfo = mMediaController.getPlaybackInfo();
+ if (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ // Return system session.
+ return sessions.get(0);
+ }
+
+ // For PLAYBACK_TYPE_REMOTE.
+ String volumeControlId = playbackInfo.getVolumeControlId();
+ for (RoutingSessionInfo session : sessions) {
+ if (TextUtils.equals(volumeControlId, session.getId())) {
+ return session;
+ }
+ // Workaround for provider not being able to know the unique session ID.
+ if (TextUtils.equals(volumeControlId, session.getOriginalId())
+ && TextUtils.equals(
+ mMediaController.getPackageName(), session.getOwnerPackageName())) {
+ return session;
+ }
+ }
+
+ return activeSession;
}
boolean isRoutingSessionAvailableForVolumeControl() {
@@ -808,4 +860,23 @@
}
}
}
+
+ private final class MediaControllerCallback extends MediaController.Callback {
+ @Override
+ public void onSessionDestroyed() {
+ mMediaController = null;
+ refreshDevices();
+ }
+
+ @Override
+ public void onAudioInfoChanged(@NonNull PlaybackInfo info) {
+ if (info.getPlaybackType() != mLastKnownPlaybackInfo.getPlaybackType()
+ || !TextUtils.equals(
+ info.getVolumeControlId(),
+ mLastKnownPlaybackInfo.getVolumeControlId())) {
+ refreshDevices();
+ }
+ mLastKnownPlaybackInfo = info;
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 473c627..cfa825b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -149,7 +149,11 @@
// TODO: b/321969740 - Take the userHandle as a parameter and pass it through. The
// package name is not sufficient to unambiguously identify an app.
InfoMediaManager.createInstance(
- context, packageName, /* userHandle */ null, mLocalBluetoothManager);
+ context,
+ packageName,
+ /* userHandle */ null,
+ mLocalBluetoothManager,
+ /* token */ null);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
index d621751..82b1976 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
@@ -21,6 +21,7 @@
import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
+import android.media.session.MediaController;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -55,8 +56,9 @@
Context context,
@NonNull String packageName,
@NonNull UserHandle userHandle,
- LocalBluetoothManager localBluetoothManager) {
- super(context, packageName, userHandle, localBluetoothManager);
+ LocalBluetoothManager localBluetoothManager,
+ @Nullable MediaController mediaController) {
+ super(context, packageName, userHandle, localBluetoothManager, mediaController);
mRouterManager = MediaRouter2Manager.getInstance(context);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/NoOpInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/NoOpInfoMediaManager.java
index d2b018c..2c7ec93 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/NoOpInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/NoOpInfoMediaManager.java
@@ -20,6 +20,7 @@
import android.media.MediaRoute2Info;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
+import android.media.session.MediaController;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -60,8 +61,9 @@
Context context,
@NonNull String packageName,
@NonNull UserHandle userHandle,
- LocalBluetoothManager localBluetoothManager) {
- super(context, packageName, userHandle, localBluetoothManager);
+ LocalBluetoothManager localBluetoothManager,
+ @Nullable MediaController mediaController) {
+ super(context, packageName, userHandle, localBluetoothManager, mediaController);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
index 045c60d..6571dd7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
@@ -25,6 +25,7 @@
import android.media.RouteDiscoveryPreference;
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
+import android.media.session.MediaController;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -71,9 +72,10 @@
Context context,
@NonNull String packageName,
@NonNull UserHandle userHandle,
- LocalBluetoothManager localBluetoothManager)
+ LocalBluetoothManager localBluetoothManager,
+ @Nullable MediaController mediaController)
throws PackageNotAvailableException {
- super(context, packageName, userHandle, localBluetoothManager);
+ super(context, packageName, userHandle, localBluetoothManager, mediaController);
MediaRouter2 router = null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
index 23b2cc2..89f3cf5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
@@ -278,7 +278,7 @@
}
@Override
- public void onAudioInfoChanged(PlaybackInfo info) {
+ public void onAudioInfoChanged(@NonNull PlaybackInfo info) {
if (D.BUG) {
Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info)
+ " sentRemote=" + sentRemote);
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 36e396fb..3b84333 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
@@ -79,8 +79,6 @@
suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean
suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode)
-
- suspend fun isAffectedByMute(audioStream: AudioStream): Boolean
}
class AudioRepositoryImpl(
@@ -152,8 +150,9 @@
minVolume = getMinVolume(audioStream),
maxVolume = audioManager.getStreamMaxVolume(audioStream.value),
volume = audioManager.getStreamVolume(audioStream.value),
+ isAffectedByMute = audioManager.isStreamAffectedByMute(audioStream.value),
isAffectedByRingerMode = audioManager.isStreamAffectedByRingerMode(audioStream.value),
- isMuted = audioManager.isStreamMute(audioStream.value)
+ isMuted = audioManager.isStreamMute(audioStream.value),
)
}
@@ -187,12 +186,6 @@
withContext(backgroundCoroutineContext) { audioManager.ringerMode = mode.value }
}
- override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean {
- return withContext(backgroundCoroutineContext) {
- audioManager.isStreamAffectedByMute(audioStream.value)
- }
- }
-
private fun getMinVolume(stream: AudioStream): Int =
try {
audioManager.getStreamMinVolume(stream.value)
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 0e5ebda..202ff40 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
@@ -50,11 +50,13 @@
suspend fun setVolume(audioStream: AudioStream, volume: Int) {
val streamModel = getAudioStream(audioStream).first()
val oldVolume = streamModel.volume
- audioRepository.setVolume(audioStream, volume)
- when {
- volume == streamModel.minVolume -> setMuted(audioStream, true)
- oldVolume == streamModel.minVolume && volume > streamModel.minVolume ->
- setMuted(audioStream, false)
+ if (volume != oldVolume) {
+ audioRepository.setVolume(audioStream, volume)
+ when {
+ volume == streamModel.minVolume -> setMuted(audioStream, true)
+ oldVolume == streamModel.minVolume && volume > streamModel.minVolume ->
+ setMuted(audioStream, false)
+ }
}
}
@@ -90,9 +92,6 @@
}
}
- suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
- audioRepository.isAffectedByMute(audioStream)
-
private suspend fun processVolume(
audioStreamModel: AudioStreamModel,
ringerMode: RingerMode,
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
index c1be1ee..2c26af1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
@@ -22,6 +22,7 @@
val volume: Int,
val minVolume: Int,
val maxVolume: Int,
+ val isAffectedByMute: Boolean,
val isAffectedByRingerMode: Boolean,
val isMuted: Boolean,
)
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/InfoMediaManagerIntegTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/InfoMediaManagerIntegTest.java
index 3bd37a2..a2ee2ec 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/InfoMediaManagerIntegTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/InfoMediaManagerIntegTest.java
@@ -65,7 +65,7 @@
public void createInstance_withMR2FlagOn_returnsRouterInfoMediaManager() {
InfoMediaManager manager =
InfoMediaManager.createInstance(
- mContext, mContext.getPackageName(), mContext.getUser(), null);
+ mContext, mContext.getPackageName(), mContext.getUser(), null, null);
assertThat(manager).isInstanceOf(RouterInfoMediaManager.class);
}
@@ -73,14 +73,15 @@
@RequiresFlagsEnabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
public void createInstance_withMR2FlagOn_withFakePackage_returnsNoOpInfoMediaManager() {
InfoMediaManager manager =
- InfoMediaManager.createInstance(mContext, FAKE_PACKAGE, null, null);
+ InfoMediaManager.createInstance(mContext, FAKE_PACKAGE, null, null, null);
assertThat(manager).isInstanceOf(NoOpInfoMediaManager.class);
}
@Test
@RequiresFlagsEnabled(FLAG_USE_MEDIA_ROUTER2_FOR_INFO_MEDIA_MANAGER)
public void createInstance_withMR2FlagOn_withNullPackage_returnsRouterInfoMediaManager() {
- InfoMediaManager manager = InfoMediaManager.createInstance(mContext, null, null, null);
+ InfoMediaManager manager =
+ InfoMediaManager.createInstance(mContext, null, null, null, null);
assertThat(manager).isInstanceOf(RouterInfoMediaManager.class);
}
@@ -89,7 +90,7 @@
public void createInstance_withMR2FlagOff_returnsManagerInfoMediaManager() {
InfoMediaManager manager =
InfoMediaManager.createInstance(
- mContext, mContext.getPackageName(), mContext.getUser(), null);
+ mContext, mContext.getPackageName(), mContext.getUser(), null, null);
assertThat(manager).isInstanceOf(ManagerInfoMediaManager.class);
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
index 9860cd8..8700680 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
@@ -173,6 +173,7 @@
volume = 50,
minVolume = MIN_VOLUME,
maxVolume = MAX_VOLUME,
+ isAffectedByMute = false,
isAffectedByRingerMode = false,
isMuted = false,
)
@@ -201,6 +202,7 @@
volume = 0,
minVolume = MIN_VOLUME,
maxVolume = MAX_VOLUME,
+ isAffectedByMute = false,
isAffectedByRingerMode = false,
isMuted = true,
)
@@ -230,6 +232,7 @@
volume = 0,
minVolume = MIN_VOLUME,
maxVolume = MAX_VOLUME,
+ isAffectedByMute = false,
isAffectedByRingerMode = false,
isMuted = false,
)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 7a2818d..a638df5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.flags.Flags.FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -33,11 +35,13 @@
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Pair;
import com.android.settingslib.widget.AdaptiveIcon;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -83,11 +87,15 @@
private static final String TEST_EXCLUSIVE_MANAGER_PACKAGE = "com.test.manager";
private static final String TEST_EXCLUSIVE_MANAGER_COMPONENT = "com.test.manager/.component";
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mSetFlagsRule.disableFlags(FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
@@ -253,6 +261,25 @@
}
@Test
+ public void isAdvancedDetailsHeader_noMainIcon_returnFalse() {
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA);
+
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON)).thenReturn(null);
+
+ assertThat(BluetoothUtils.isAdvancedDetailsHeader(mBluetoothDevice)).isFalse();
+ }
+
+ @Test
+ public void isAdvancedDetailsHeader_hasMainIcon_returnTrue() {
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA);
+
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
+ .thenReturn(STRING_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.isAdvancedDetailsHeader(mBluetoothDevice)).isTrue();
+ }
+
+ @Test
public void isAdvancedUntetheredDevice_untetheredHeadset_returnTrue() {
when(mBluetoothDevice.getMetadata(
BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
@@ -294,6 +321,18 @@
}
@Test
+ public void isAdvancedUntetheredDevice_untetheredHeadsetMetadataIsFalse_returnFalse() {
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_DETERMINING_ADVANCED_DETAILS_HEADER_WITH_METADATA);
+
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn("false".getBytes());
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE))
+ .thenReturn(BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET.getBytes());
+
+ assertThat(BluetoothUtils.isAdvancedUntetheredDevice(mBluetoothDevice)).isFalse();
+ }
+
+ @Test
public void isAvailableMediaBluetoothDevice_isConnectedLeAudioDevice_returnTrue() {
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 69faddf..ce07fe9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -146,7 +146,11 @@
Context.MEDIA_SESSION_SERVICE);
mInfoMediaManager =
new ManagerInfoMediaManager(
- mContext, TEST_PACKAGE_NAME, mContext.getUser(), mLocalBluetoothManager);
+ mContext,
+ TEST_PACKAGE_NAME,
+ mContext.getUser(),
+ mLocalBluetoothManager,
+ /* mediaController */ null);
mShadowRouter2Manager = ShadowRouter2Manager.getShadow();
mInfoMediaManager.mRouterManager = MediaRouter2Manager.getInstance(mContext);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index ddb5419..12541bb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -117,9 +117,16 @@
when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
// Need to call constructor to initialize final fields.
- mInfoMediaManager = mock(
- InfoMediaManager.class,
- withSettings().useConstructor(mContext, TEST_PACKAGE_NAME, mLocalBluetoothManager));
+ mInfoMediaManager =
+ mock(
+ InfoMediaManager.class,
+ withSettings()
+ .useConstructor(
+ mContext,
+ TEST_PACKAGE_NAME,
+ android.os.Process.myUserHandle(),
+ mLocalBluetoothManager,
+ /* mediaController */ null));
doReturn(
List.of(
new RoutingSessionInfo.Builder(TEST_SESSION_ID, TEST_PACKAGE_NAME)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/NoOpInfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/NoOpInfoMediaManagerTest.java
index 908f50d..c566741 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/NoOpInfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/NoOpInfoMediaManagerTest.java
@@ -47,7 +47,8 @@
mContext,
/* packageName */ "FAKE_PACKAGE_NAME",
mContext.getUser(),
- /* localBluetoothManager */ null);
+ /* localBluetoothManager */ null,
+ /* mediaController */ null);
}
@Test
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index e9c2672..75f8384 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -32,6 +32,8 @@
"unsupportedappusage",
],
static_libs: [
+ "aconfig_new_storage_flags_lib",
+ "aconfigd_java_utils",
"aconfig_demo_flags_java_lib",
"device_config_service_flags_java",
"libaconfig_java_proto_lite",
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 8f8445d..1706a6f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -38,6 +38,8 @@
* NOTE: All settings which are backed up should have a corresponding validator.
*/
public static final String[] SETTINGS_TO_BACKUP = {
+ Settings.Global.CONNECTED_APPS_ALLOWED_PACKAGES,
+ Settings.Global.CONNECTED_APPS_DISALLOWED_PACKAGES,
Settings.Global.APPLY_RAMPING_RINGER,
Settings.Global.BUGREPORT_IN_POWER_MENU, // moved to secure
Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
@@ -120,5 +122,8 @@
Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_ENABLED,
Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_TYPE,
Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_SPEED,
+ Settings.Global.ADD_USERS_WHEN_LOCKED,
+ Settings.Global.REMOVE_GUEST_ON_EXIT,
+ Settings.Global.USER_SWITCHER_ENABLED,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index c274534..f83928d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -51,6 +51,9 @@
public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
static {
+ VALIDATORS.put(Global.CONNECTED_APPS_ALLOWED_PACKAGES, new PackageNameListValidator((",")));
+ VALIDATORS.put(Global.CONNECTED_APPS_DISALLOWED_PACKAGES,
+ new PackageNameListValidator((",")));
VALIDATORS.put(Global.APPLY_RAMPING_RINGER, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.BUGREPORT_IN_POWER_MENU, BOOLEAN_VALIDATOR);
VALIDATORS.put(
@@ -450,5 +453,8 @@
Global.Wearable.CONSISTENT_NOTIFICATION_BLOCKING_ENABLED, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.AUTO_BEDTIME_MODE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.FORCE_ENABLE_PSS_PROFILING, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.ADD_USERS_WHEN_LOCKED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.REMOVE_GUEST_ON_EXIT, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.USER_SWITCHER_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 2e9075c..7be15af 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -88,7 +88,7 @@
private static final ArraySet<String> sBroadcastOnRestore;
private static final ArraySet<String> sBroadcastOnRestoreSystemUI;
static {
- sBroadcastOnRestore = new ArraySet<String>(9);
+ sBroadcastOnRestore = new ArraySet<String>(12);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -99,6 +99,7 @@
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
+ sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
sBroadcastOnRestore.add(Settings.Secure.SCREEN_RESOLUTION_MODE);
sBroadcastOnRestoreSystemUI = new ArraySet<String>(2);
sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES);
@@ -240,6 +241,11 @@
// Don't write it to setting. Let the broadcast receiver in
// AccessibilityManagerService handle restore/merging logic.
return;
+ } else if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()
+ && Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.equals(name)) {
+ // Don't write it to setting. Let the broadcast receiver in
+ // AccessibilityManagerService handle restore/merging logic.
+ return;
}
// Default case: write the restored value to settings
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 68bc96d..04922d6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -82,6 +82,18 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+// FOR ACONFIGD TEST MISSION AND ROLLOUT
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
+import android.util.proto.ProtoInputStream;
+import android.aconfigd.Aconfigd.StorageRequestMessage;
+import android.aconfigd.Aconfigd.StorageRequestMessages;
+import android.aconfigd.Aconfigd.StorageReturnMessage;
+import android.aconfigd.Aconfigd.StorageReturnMessages;
+import android.aconfigd.AconfigdJavaUtils;
+import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon;
/**
* This class contains the state for one type of settings. It is responsible
* for saving the state asynchronously to an XML file after a mutation and
@@ -346,6 +358,7 @@
mNamespaceDefaults = new HashMap<>();
+ ProtoOutputStream requests = null;
synchronized (mLock) {
readStateSyncLocked();
@@ -361,7 +374,146 @@
loadAconfigDefaultValuesLocked(apexProtoPaths);
}
}
+
+ if (isConfigSettingsKey(mKey)) {
+ requests = handleBulkSyncToNewStorage();
+ }
}
+
+ if (requests != null) {
+ LocalSocket client = new LocalSocket();
+ try{
+ client.connect(new LocalSocketAddress(
+ "aconfigd", LocalSocketAddress.Namespace.RESERVED));
+ Slog.d(LOG_TAG, "connected to aconfigd socket");
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "failed to connect to aconfigd socket", ioe);
+ return;
+ }
+ AconfigdJavaUtils.sendAconfigdRequests(client, requests);
+ }
+ }
+
+ // TODO(b/341764371): migrate aconfig flag push to GMS core
+ public static class FlagOverrideToSync {
+ public String packageName;
+ public String flagName;
+ public String flagValue;
+ public boolean isLocal;
+ }
+
+ // TODO(b/341764371): migrate aconfig flag push to GMS core
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ public FlagOverrideToSync getFlagOverrideToSync(String name, String value) {
+ int slashIdx = name.indexOf("/");
+ if (slashIdx <= 0 || slashIdx >= name.length()-1) {
+ Slog.e(LOG_TAG, "invalid flag name " + name);
+ return null;
+ }
+
+ String namespace = name.substring(0, slashIdx);
+ String fullFlagName = name.substring(slashIdx + 1);
+ boolean isLocal = false;
+
+ // get actual fully qualified flag name <package>.<flag>, note this is done
+ // after staged flag is applied, so no need to check staged flags
+ if (namespace.equals("device_config_overrides")) {
+ int colonIdx = fullFlagName.indexOf(":");
+ if (colonIdx == -1) {
+ Slog.e(LOG_TAG, "invalid local override flag name " + name);
+ return null;
+ }
+ namespace = fullFlagName.substring(0, colonIdx);
+ fullFlagName = fullFlagName.substring(colonIdx + 1);
+ isLocal = true;
+ }
+
+ String aconfigName = namespace + "/" + fullFlagName;
+ boolean isAconfig = mNamespaceDefaults.containsKey(namespace)
+ && mNamespaceDefaults.get(namespace).containsKey(aconfigName);
+ if (!isAconfig) {
+ return null;
+ }
+
+ // get package name and flag name
+ int dotIdx = fullFlagName.lastIndexOf(".");
+ if (dotIdx == -1) {
+ Slog.e(LOG_TAG, "invalid override flag name " + name);
+ return null;
+ }
+
+ FlagOverrideToSync flag = new FlagOverrideToSync();
+ flag.packageName = fullFlagName.substring(0, dotIdx);
+ flag.flagName = fullFlagName.substring(dotIdx + 1);
+ flag.isLocal = isLocal;
+ flag.flagValue = value;
+ return flag;
+ }
+
+
+ // TODO(b/341764371): migrate aconfig flag push to GMS core
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ public ProtoOutputStream handleBulkSyncToNewStorage() {
+ // get marker or add marker if it does not exist
+ final String bulkSyncMarkerName = new String("aconfigd_marker/bulk_synced");
+ Setting markerSetting = mSettings.get(bulkSyncMarkerName);
+ if (markerSetting == null) {
+ markerSetting = new Setting(
+ bulkSyncMarkerName, "false", false, "aconfig", "aconfig");
+ mSettings.put(bulkSyncMarkerName, markerSetting);
+ }
+
+ if (enableAconfigStorageDaemon()) {
+ if (markerSetting.value.equals("true")) {
+ // CASE 1, flag is on, bulk sync marker true, nothing to do
+ return null;
+ } else {
+ // CASE 2, flag is on, bulk sync marker false. Do following two tasks
+ // (1) Do bulk sync here.
+ // (2) After bulk sync, set marker to true.
+
+ // first add storage reset request
+ ProtoOutputStream requests = new ProtoOutputStream();
+ AconfigdJavaUtils.writeResetStorageRequest(requests);
+
+ // loop over all settings and add flag override requests
+ final int numSettings = mSettings.size();
+ int num_requests = 0;
+ for (int i = 0; i < numSettings; i++) {
+ String name = mSettings.keyAt(i);
+ Setting setting = mSettings.valueAt(i);
+ FlagOverrideToSync flag =
+ getFlagOverrideToSync(name, setting.getValue());
+ if (flag == null) {
+ continue;
+ }
+ ++num_requests;
+ AconfigdJavaUtils.writeFlagOverrideRequest(
+ requests, flag.packageName, flag.flagName, flag.flagValue,
+ flag.isLocal);
+ }
+
+ Slog.i(LOG_TAG, num_requests + " flag override requests created");
+
+ // mark sync has been done
+ markerSetting.value = "true";
+ scheduleWriteIfNeededLocked();
+ return requests;
+ }
+ } else {
+ if (markerSetting.value.equals("true")) {
+ // CASE 3, flag is off, bulk sync marker true, clear the marker
+ markerSetting.value = "false";
+ scheduleWriteIfNeededLocked();
+ return null;
+ } else {
+ // CASE 4, flag is off, bulk sync marker false, nothing to do
+ return null;
+ }
+ }
+
}
@GuardedBy("mLock")
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index ab9a30b..f05f6b5 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -63,7 +63,6 @@
Settings.Global.ADB_ENABLED,
Settings.Global.ADB_WIFI_ENABLED,
Settings.Global.ADB_DISCONNECT_SESSIONS_ON_REVOKE,
- Settings.Global.ADD_USERS_WHEN_LOCKED,
Settings.Global.AIRPLANE_MODE_ON,
Settings.Global.AIRPLANE_MODE_RADIOS,
Settings.Global.ALLOW_WORK_PROFILE_TELEPHONY_FOR_NON_DPM_ROLE_HOLDERS,
@@ -381,7 +380,6 @@
Settings.Global.RADIO_WIFI,
Settings.Global.RADIO_WIMAX,
Settings.Global.RADIO_UWB,
- Settings.Global.REMOVE_GUEST_ON_EXIT,
Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
Settings.Global.RESTRICTED_NETWORKING_MODE,
@@ -485,7 +483,6 @@
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
- Settings.Global.USER_SWITCHER_ENABLED,
Settings.Global.WARNING_TEMPERATURE,
Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
Settings.Global.WEBVIEW_MULTIPROCESS,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
index 2f8cf4b..f64f72a 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -26,6 +26,8 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.SettingsStringUtil;
@@ -35,6 +37,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -48,6 +51,10 @@
*/
@RunWith(AndroidJUnit4.class)
public class SettingsHelperRestoreTest {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final float FLOAT_TOLERANCE = 0.01f;
private Context mContext;
@@ -202,4 +209,32 @@
Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, /* defaultValue= */ 0))
.isEqualTo(Build.VERSION.SDK_INT);
}
+
+ @Test
+ @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
+ public void restoreAccessibilityShortcutTargetService_broadcastSent()
+ throws ExecutionException, InterruptedException {
+ BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
+ mContext);
+ final String settingName = Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+ final String restoredValue = "com.android.a11y/Service";
+ BroadcastInterceptingContext.FutureIntent futureIntent =
+ interceptingContext.nextBroadcastIntent(Intent.ACTION_SETTING_RESTORED);
+
+ mSettingsHelper.restoreValue(
+ interceptingContext,
+ mContentResolver,
+ new ContentValues(2),
+ Settings.Secure.getUriFor(settingName),
+ settingName,
+ restoredValue,
+ Build.VERSION.SDK_INT);
+
+ Intent intentReceived = futureIntent.get();
+ assertThat(intentReceived.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE))
+ .isEqualTo(restoredValue);
+ assertThat(intentReceived.getIntExtra(
+ Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, /* defaultValue= */ 0))
+ .isEqualTo(Build.VERSION.SDK_INT);
+ }
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 5db97c6..244c8c4 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -29,12 +29,18 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
+import com.android.providers.settings.SettingsState.FlagOverrideToSync;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.TypedXmlSerializer;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
import com.google.common.base.Strings;
import java.io.ByteArrayOutputStream;
@@ -947,4 +953,115 @@
+ testValue1.length() /* size for default */) * Character.BYTES;
assertEquals(expectedMemUsageForPackage2, settingsState.getMemoryUsage(package2));
}
+
+ @Test
+ public void testGetFlagOverrideToSync() {
+ int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+ Object lock = new Object();
+ SettingsState settingsState = new SettingsState(
+ InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+ parsed_flags flags = parsed_flags
+ .newBuilder()
+ .addParsedFlag(parsed_flag
+ .newBuilder()
+ .setPackage("com.android.flags")
+ .setName("flag1")
+ .setNamespace("test_namespace")
+ .setDescription("test flag")
+ .addBug("12345678")
+ .setState(Aconfig.flag_state.DISABLED)
+ .setPermission(Aconfig.flag_permission.READ_WRITE))
+ .build();
+
+ synchronized (lock) {
+ Map<String, Map<String, String>> defaults = new HashMap<>();
+ settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults);
+ Map<String, String> namespaceDefaults = defaults.get("test_namespace");
+ assertEquals(1, namespaceDefaults.keySet().size());
+ settingsState.addAconfigDefaultValuesFromMap(defaults);
+ }
+
+ // invalid flag name
+ assertTrue(settingsState.getFlagOverrideToSync(
+ "invalid_flag", "false") == null);
+
+ // non aconfig flag
+ assertTrue(settingsState.getFlagOverrideToSync(
+ "some_namespace/some_flag", "false") == null);
+
+ // server override
+ FlagOverrideToSync flag = settingsState.getFlagOverrideToSync(
+ "test_namespace/com.android.flags.flag1", "false");
+ assertTrue(flag != null);
+ assertEquals(flag.packageName, "com.android.flags");
+ assertEquals(flag.flagName, "flag1");
+ assertEquals(flag.flagValue, "false");
+ assertEquals(flag.isLocal, false);
+
+ // local override
+ flag = settingsState.getFlagOverrideToSync(
+ "device_config_overrides/test_namespace:com.android.flags.flag1", "false");
+ assertTrue(flag != null);
+ assertEquals(flag.packageName, "com.android.flags");
+ assertEquals(flag.flagName, "flag1");
+ assertEquals(flag.flagValue, "false");
+ assertEquals(flag.isLocal, true);
+ }
+
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Test
+ @EnableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON)
+ public void testHandleBulkSyncWithAconfigdEnabled() {
+ int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+ Object lock = new Object();
+ SettingsState settingsState = new SettingsState(
+ InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+ synchronized (lock) {
+ settingsState.insertSettingLocked("aconfigd_marker/bulk_synced",
+ "false", null, false, "aconfig");
+
+ // first bulk sync
+ ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage();
+ assertTrue(requests != null);
+ String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("true", value);
+
+ // send time should no longer bulk sync
+ requests = settingsState.handleBulkSyncToNewStorage();
+ assertTrue(requests == null);
+ value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("true", value);
+ }
+ }
+
+ @Test
+ @DisableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON)
+ public void testHandleBulkSyncWithAconfigdDisabled() {
+ int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+ Object lock = new Object();
+ SettingsState settingsState = new SettingsState(
+ InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+ synchronized (lock) {
+ settingsState.insertSettingLocked("aconfigd_marker/bulk_synced",
+ "true", null, false, "aconfig");
+
+ // when aconfigd is off, should change the marker to false
+ ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage();
+ assertTrue(requests == null);
+ String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("false", value);
+
+ // marker started with false value, after call, it should remain false
+ requests = settingsState.handleBulkSyncToNewStorage();
+ assertTrue(requests == null);
+ value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue();
+ assertEquals("false", value);
+ }
+ }
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 4579168..050a370 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -200,7 +200,7 @@
mBugreportFd = ParcelFileDescriptor.dup(invocation.getArgument(2));
return null;
}).when(mMockIDumpstate).startBugreport(anyInt(), any(), any(), any(), anyInt(), anyInt(),
- any(), anyBoolean());
+ any(), anyBoolean(), anyBoolean());
setWarningState(mContext, STATE_HIDE);
@@ -543,7 +543,7 @@
getInstrumentation().waitForIdleSync();
verify(mMockIDumpstate, times(1)).startBugreport(anyInt(), any(), any(), any(),
- anyInt(), anyInt(), any(), anyBoolean());
+ anyInt(), anyInt(), any(), anyBoolean(), anyBoolean());
sendBugreportFinished();
}
@@ -608,7 +608,7 @@
ArgumentCaptor<IDumpstateListener> listenerCap = ArgumentCaptor.forClass(
IDumpstateListener.class);
verify(mMockIDumpstate, timeout(TIMEOUT)).startBugreport(anyInt(), any(), any(), any(),
- anyInt(), anyInt(), listenerCap.capture(), anyBoolean());
+ anyInt(), anyInt(), listenerCap.capture(), anyBoolean(), anyBoolean());
mIDumpstateListener = listenerCap.getValue();
assertNotNull("Dumpstate listener should not be null", mIDumpstateListener);
mIDumpstateListener.onProgress(0);
diff --git a/packages/SoundPicker/res/values-ne/strings.xml b/packages/SoundPicker/res/values-ne/strings.xml
index 0a2bceb..79725fd 100644
--- a/packages/SoundPicker/res/values-ne/strings.xml
+++ b/packages/SoundPicker/res/values-ne/strings.xml
@@ -23,7 +23,7 @@
<string name="add_alarm_text" msgid="3545497316166999225">"अलार्म थप्नुहोस्"</string>
<string name="add_notification_text" msgid="4431129543300614788">"सूचना थप्नुहोस्"</string>
<string name="delete_ringtone_text" msgid="201443984070732499">"मेट्नुहोस्"</string>
- <string name="unable_to_add_ringtone" msgid="4583511263449467326">"आफू अनुकूल रिङटोन थप्न सकिएन"</string>
- <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"आफू अनुकूल रिङटोनलाई मेट्न सकिएन"</string>
+ <string name="unable_to_add_ringtone" msgid="4583511263449467326">" कस्टम रिङटोन थप्न सकिएन"</string>
+ <string name="unable_to_delete_ringtone" msgid="6792301380142859496">" कस्टम रिङटोनलाई मेट्न सकिएन"</string>
<string name="app_label" msgid="3091611356093417332">"ध्वनिहरू"</string>
</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 8b60ed0..ac680a9 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -193,6 +193,9 @@
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
+ // TODO(b/322324387): Fails to start due to missing ScreenshotActivity
+ "tests/src/**/systemui/bouncer/ui/composable/BouncerContentTest.kt",
+ "tests/src/**/systemui/bouncer/ui/composable/PatternBouncerTest.kt",
"tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
"tests/src/**/systemui/charging/WiredChargingRippleControllerTest.kt",
"tests/src/**/systemui/clipboardoverlay/ClipboardModelTest.kt",
@@ -533,6 +536,8 @@
"SystemUI-res",
"WifiTrackerLib",
"PlatformAnimationLib",
+ "PlatformMotionTestingCompose",
+ "ScreenshotComposeUtilsLib",
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUICustomizationLib",
@@ -766,6 +771,7 @@
],
static_libs: [
"RoboTestLibraries",
+ "mockito-kotlin2",
],
libs: [
"android.test.runner",
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
index d868d5c..ba84287 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
@@ -9,3 +9,13 @@
description: "Hides the AccessibilityMenuService UI before taking action instead of after."
bug: "292020123"
}
+
+flag {
+ name: "a11y_menu_snackbar_live_region"
+ namespace: "accessibility"
+ description: "configures live region on snackbar so its contents are announced when it appears."
+ bug: "338351484"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
index 3f72d95..7535c2b 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="accessibility_menu_service_name" msgid="730136711554740131">"Toegankelijkheidsmenu"</string>
+ <string name="accessibility_menu_service_name" msgid="730136711554740131">"toegankelijkheidsmenu"</string>
<string name="accessibility_menu_intro" msgid="3164193281544042394">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid aanpassen en screenshots maken."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistent"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index 1be04f8..7b43b72 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static java.lang.Math.max;
@@ -321,7 +322,14 @@
AccessibilityManager.FLAG_CONTENT_TEXT);
final TextView snackbar = mLayout.findViewById(R.id.snackbar);
+ if (snackbar == null) {
+ return;
+ }
snackbar.setText(text);
+ if (com.android.systemui.accessibility.accessibilitymenu
+ .Flags.a11yMenuSnackbarLiveRegion()) {
+ snackbar.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
+ }
// Remove any existing fade-out animation before starting any new animations.
mHandler.removeCallbacksAndMessages(null);
diff --git a/packages/SystemUI/aconfig/cross_device_control.aconfig b/packages/SystemUI/aconfig/cross_device_control.aconfig
deleted file mode 100644
index 5f9a4f4..0000000
--- a/packages/SystemUI/aconfig/cross_device_control.aconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-package: "com.android.systemui"
-container: "system"
-
-flag {
- name: "legacy_le_audio_sharing"
- namespace: "pixel_cross_device_control"
- description: "Gates the legacy le audio sharing UI."
- bug: "322295262"
-}
-
-flag {
- name: "enable_personal_le_audio_sharing"
- namespace: "pixel_cross_device_control"
- description: "Gates the personal le audio sharing UI in UMO."
- bug: "322295480"
-}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f9e955b..7e20804 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -43,7 +43,7 @@
}
flag {
- name: "notification_view_flipper_pausing"
+ name: "notification_view_flipper_pausing_v2"
namespace: "systemui"
description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed."
bug: "309146176"
@@ -414,6 +414,13 @@
}
flag {
+ name: "confine_notification_touch_to_view_width"
+ namespace: "systemui"
+ description: "Use notification view width when detecting gestures."
+ bug: "335828150"
+}
+
+flag {
name: "fix_image_wallpaper_crash_surface_already_released"
namespace: "systemui"
description: "Make sure ImageWallpaper doesn't return from OnSurfaceDestroyed until any drawing is finished"
@@ -516,6 +523,16 @@
}
flag {
+ name: "screenshot_private_profile_accessibility_announcement_fix"
+ namespace: "systemui"
+ description: "Modified a11y announcement for private space screenshots"
+ bug: "326941376"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "screenshot_private_profile_behavior_fix"
namespace: "systemui"
description: "Private profile support for screenshots"
@@ -968,3 +985,20 @@
description: "Shows a vertical bar at the right edge to indicate the user can swipe to open the glanceable hub"
bug: "339667383"
}
+
+flag {
+ name: "new_touchpad_gestures_tutorial"
+ namespace: "systemui"
+ description: "Enables new interactive tutorial for learning touchpad gestures"
+ bug: "309928033"
+}
+
+flag {
+ name: "register_wallpaper_notifier_background"
+ namespace: "systemui"
+ description: "Decide whether to register wallpaper change broadcast receiver on background executor."
+ bug: "327315860"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/compose/core/Android.bp b/packages/SystemUI/compose/core/Android.bp
index 49ae821..c63c2b4 100644
--- a/packages/SystemUI/compose/core/Android.bp
+++ b/packages/SystemUI/compose/core/Android.bp
@@ -32,6 +32,7 @@
static_libs: [
"PlatformAnimationLib",
+ "PlatformMotionTestingComposeValues",
"androidx.compose.runtime_runtime",
"androidx.compose.material3_material3",
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
index f5dc154..bd5b795a 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -19,11 +19,14 @@
import android.view.View
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.qualifiers.KeyguardRootView
import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.keyguard.ui.composable.LockscreenScene
import com.android.systemui.keyguard.ui.composable.LockscreenSceneBlueprintModule
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.scene.shared.model.Scene
import dagger.Binds
import dagger.Module
@@ -60,5 +63,14 @@
): Set<LockscreenSceneBlueprint> {
return blueprints
}
+
+ @Provides
+ fun providesLockscreenContent(
+ viewModel: LockscreenContentViewModel,
+ blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
+ clockInteractor: KeyguardClockInteractor,
+ ): LockscreenContent {
+ return LockscreenContent(viewModel, blueprints, clockInteractor)
+ }
}
}
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 fa01a4b..c19c08e 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
@@ -20,6 +20,7 @@
import android.app.AlertDialog
import android.content.DialogInterface
+import androidx.annotation.VisibleForTesting
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.animateFloatAsState
@@ -69,6 +70,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
@@ -104,6 +106,9 @@
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.pow
+import platform.test.motion.compose.values.MotionTestValueKey
+import platform.test.motion.compose.values.MotionTestValues
+import platform.test.motion.compose.values.motionTestValues
@Composable
fun BouncerContent(
@@ -114,6 +119,17 @@
val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsStateWithLifecycle()
val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported)
+ BouncerContent(layout, viewModel, dialogFactory, modifier)
+}
+
+@Composable
+@VisibleForTesting
+fun BouncerContent(
+ layout: BouncerSceneLayout,
+ viewModel: BouncerViewModel,
+ dialogFactory: BouncerDialogFactory,
+ modifier: Modifier
+) {
Box(
// Allows the content within each of the layouts to react to the appearance and
// disappearance of the IME, which is also known as the software keyboard.
@@ -318,6 +334,8 @@
LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded
val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
+ var swapAnimationEnd by remember { mutableStateOf(false) }
+
Row(
modifier =
modifier
@@ -331,11 +349,16 @@
}
)
}
+ .testTag("BesideUserSwitcherLayout")
+ .motionTestValues {
+ swapAnimationEnd exportAs BouncerMotionTestKeys.swapAnimationEnd
+ }
.padding(
top = if (isHeightExpanded) 128.dp else 96.dp,
bottom = if (isHeightExpanded) 128.dp else 48.dp,
),
) {
+ LaunchedEffect(isSwapped) { swapAnimationEnd = false }
val animatedOffset by
animateFloatAsState(
targetValue =
@@ -354,31 +377,35 @@
-1f
},
label = "offset",
- )
+ ) {
+ swapAnimationEnd = true
+ }
fun Modifier.swappable(inversed: Boolean = false): Modifier {
return graphicsLayer {
- translationX =
- size.width *
- animatedOffset *
- if (inversed) {
- // A negative sign is used to make sure this is offset in the direction
- // that's opposite to the direction that the user switcher is pushed in.
- -1
- } else {
- 1
- }
- alpha = animatedAlpha(animatedOffset)
- }
+ translationX =
+ size.width *
+ animatedOffset *
+ if (inversed) {
+ // A negative sign is used to make sure this is offset in the
+ // direction that's opposite to the direction that the user
+ // switcher is pushed in.
+ -1
+ } else {
+ 1
+ }
+ alpha = animatedAlpha(animatedOffset)
+ }
+ .motionTestValues { animatedAlpha(animatedOffset) exportAs MotionTestValues.alpha }
}
UserSwitcher(
viewModel = viewModel,
- modifier = Modifier.weight(1f).swappable(),
+ modifier = Modifier.weight(1f).swappable().testTag("UserSwitcher"),
)
FoldAware(
- modifier = Modifier.weight(1f).swappable(inversed = true),
+ modifier = Modifier.weight(1f).swappable(inversed = true).testTag("FoldAware"),
viewModel = viewModel,
aboveFold = {
Column(
@@ -389,7 +416,10 @@
viewModel = viewModel.message,
)
- OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
+ OutputArea(
+ viewModel = viewModel,
+ modifier = Modifier.padding(top = 24.dp).testTag("OutputArea")
+ )
}
},
belowFold = {
@@ -412,13 +442,13 @@
viewModel = viewModel,
pinButtonRowVerticalSpacing = 12.dp,
centerPatternDotsVertically = true,
- modifier = Modifier.align(Alignment.BottomCenter),
+ modifier = Modifier.align(Alignment.BottomCenter).testTag("InputArea"),
)
}
ActionArea(
viewModel = viewModel,
- modifier = Modifier.padding(top = 48.dp),
+ modifier = Modifier.padding(top = 48.dp).testTag("ActionArea"),
)
}
},
@@ -938,3 +968,8 @@
private val SceneTransitions = transitions {
from(SceneKeys.ContiguousSceneKey, to = SceneKeys.SplitSceneKey) { spec = tween() }
}
+
+@VisibleForTesting
+object BouncerMotionTestKeys {
+ val swapAnimationEnd = MotionTestValueKey<Boolean>("swapAnimationEnd")
+}
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 9c2fd64..069113b 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
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.composable
import android.view.HapticFeedbackConstants
+import androidx.annotation.VisibleForTesting
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.tween
@@ -50,6 +51,10 @@
import com.android.compose.animation.Easings
import com.android.compose.modifiers.thenIf
import com.android.internal.R
+import com.android.systemui.bouncer.ui.composable.MotionTestKeys.dotAppearFadeIn
+import com.android.systemui.bouncer.ui.composable.MotionTestKeys.dotAppearMoveUp
+import com.android.systemui.bouncer.ui.composable.MotionTestKeys.dotScaling
+import com.android.systemui.bouncer.ui.composable.MotionTestKeys.entryCompleted
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternDotViewModel
import com.android.systemui.compose.modifiers.sysuiResTag
@@ -58,6 +63,8 @@
import kotlin.math.sqrt
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
+import platform.test.motion.compose.values.MotionTestValueKey
+import platform.test.motion.compose.values.motionTestValues
/**
* UI for the input part of a pattern-requiring version of the bouncer.
@@ -68,7 +75,8 @@
* `false`, the dots will be pushed towards the end/bottom of the axis.
*/
@Composable
-internal fun PatternBouncer(
+@VisibleForTesting
+fun PatternBouncer(
viewModel: PatternBouncerViewModel,
centerDotsVertically: Boolean,
modifier: Modifier = Modifier,
@@ -111,33 +119,11 @@
remember(dots) {
dots.associateWith { dot -> with(density) { (80 + (20 * dot.y)).dp.toPx() } }
}
+
+ var entryAnimationCompleted by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
- dotAppearFadeInAnimatables.forEach { (dot, animatable) ->
- scope.launch {
- animatable.animateTo(
- targetValue = 1f,
- animationSpec =
- tween(
- delayMillis = 33 * dot.y,
- durationMillis = 450,
- easing = Easings.LegacyDecelerate,
- )
- )
- }
- }
- dotAppearMoveUpAnimatables.forEach { (dot, animatable) ->
- scope.launch {
- animatable.animateTo(
- targetValue = 1f,
- animationSpec =
- tween(
- delayMillis = 0,
- durationMillis = 450 + (33 * dot.y),
- easing = Easings.StandardDecelerate,
- )
- )
- }
- }
+ showEntryAnimation(dotAppearFadeInAnimatables, dotAppearMoveUpAnimatables)
+ entryAnimationCompleted = true
}
val view = LocalView.current
@@ -286,6 +272,12 @@
}
}
}
+ .motionTestValues {
+ entryAnimationCompleted exportAs entryCompleted
+ dotAppearFadeInAnimatables.map { it.value.value } exportAs dotAppearFadeIn
+ dotAppearMoveUpAnimatables.map { it.value.value } exportAs dotAppearMoveUp
+ dotScalingAnimatables.map { it.value.value } exportAs dotScaling
+ }
) {
gridCoordinates?.let { nonNullCoordinates ->
val containerSize = nonNullCoordinates.size
@@ -381,6 +373,40 @@
}
}
+private suspend fun showEntryAnimation(
+ dotAppearFadeInAnimatables: Map<PatternDotViewModel, Animatable<Float, AnimationVector1D>>,
+ dotAppearMoveUpAnimatables: Map<PatternDotViewModel, Animatable<Float, AnimationVector1D>>,
+) {
+ coroutineScope {
+ dotAppearFadeInAnimatables.forEach { (dot, animatable) ->
+ launch {
+ animatable.animateTo(
+ targetValue = 1f,
+ animationSpec =
+ tween(
+ delayMillis = 33 * dot.y,
+ durationMillis = 450,
+ easing = Easings.LegacyDecelerate,
+ )
+ )
+ }
+ }
+ dotAppearMoveUpAnimatables.forEach { (dot, animatable) ->
+ launch {
+ animatable.animateTo(
+ targetValue = 1f,
+ animationSpec =
+ tween(
+ delayMillis = 0,
+ durationMillis = 450 + (33 * dot.y),
+ easing = Easings.StandardDecelerate,
+ )
+ )
+ }
+ }
+ }
+}
+
/** Returns an [Offset] representation of the given [dot], in pixel coordinates. */
private fun pixelOffset(
dot: PatternDotViewModel,
@@ -490,3 +516,11 @@
private const val FAILURE_ANIMATION_DOT_SHRINK_ANIMATION_DURATION_MS = 50
private const val FAILURE_ANIMATION_DOT_SHRINK_STAGGER_DELAY_MS = 33
private const val FAILURE_ANIMATION_DOT_REVERT_ANIMATION_DURATION = 617
+
+@VisibleForTesting
+object MotionTestKeys {
+ val entryCompleted = MotionTestValueKey<Boolean>("PinBouncer::entryAnimationCompleted")
+ val dotAppearFadeIn = MotionTestValueKey<List<Float>>("PinBouncer::dotAppearFadeIn")
+ val dotAppearMoveUp = MotionTestValueKey<List<Float>>("PinBouncer::dotAppearMoveUp")
+ val dotScaling = MotionTestValueKey<List<Float>>("PinBouncer::dotScaling")
+}
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 ca4ff83..99f7d0f 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
@@ -36,9 +36,7 @@
* This is separate from the [LockscreenScene] because it's meant to support usage of this UI from
* outside the scene container framework.
*/
-class LockscreenContent
-@Inject
-constructor(
+class LockscreenContent(
private val viewModel: LockscreenContentViewModel,
private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
private val clockInteractor: KeyguardClockInteractor,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
index d996d25..166aa70 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
@@ -54,12 +54,19 @@
@SuppressLint("InflateParams")
val view =
remember(context) {
- LayoutInflater.from(context)
- .inflate(
- R.layout.keyguard_status_bar,
- null,
- false,
- ) as KeyguardStatusBarView
+ (LayoutInflater.from(context)
+ .inflate(
+ R.layout.keyguard_status_bar,
+ null,
+ false,
+ ) as KeyguardStatusBarView)
+ .also {
+ it.layoutParams =
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
}
val viewController =
remember(view) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index 1c675e3..e17a146 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -26,11 +26,14 @@
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import dagger.Lazy
+import java.util.Optional
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
@@ -40,6 +43,7 @@
constructor(
viewModel: NotificationsShadeSceneViewModel,
private val overlayShadeViewModel: OverlayShadeViewModel,
+ private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
) : ComposableScene {
override val key = Scenes.NotificationsShade
@@ -55,6 +59,7 @@
viewModel = overlayShadeViewModel,
modifier = modifier,
horizontalArrangement = Arrangement.Start,
+ lockscreenContent = lockscreenContent,
) {
Text(
text = "Notifications list",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index d109988..54a98dd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -69,7 +69,7 @@
private fun SceneScope.stateForQuickSettingsContent(
isSplitShade: Boolean,
- squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default
+ squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default }
): QSSceneAdapter.State {
return when (val transitionState = layoutState.transitionState) {
is TransitionState.Idle -> {
@@ -125,9 +125,9 @@
heightProvider: () -> Int,
isSplitShade: Boolean,
modifier: Modifier = Modifier,
- squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default,
+ squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
) {
- val contentState = stateForQuickSettingsContent(isSplitShade, squishiness)
+ val contentState = { stateForQuickSettingsContent(isSplitShade, squishiness) }
val transitionState = layoutState.transitionState
val isClosing =
transitionState is TransitionState.Transition &&
@@ -161,7 +161,7 @@
@Composable
private fun QuickSettingsContent(
qsSceneAdapter: QSSceneAdapter,
- state: QSSceneAdapter.State,
+ state: () -> QSSceneAdapter.State,
modifier: Modifier = Modifier,
) {
val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null)
@@ -185,10 +185,10 @@
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = { _ ->
- qsSceneAdapter.setState(state)
+ qsSceneAdapter.setState(state())
view
},
- update = { qsSceneAdapter.setState(state) }
+ update = { qsSceneAdapter.setState(state()) }
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
index 636c6c3..04f76f5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -26,13 +26,16 @@
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
+import java.util.Optional
@SysUISingleton
class QuickSettingsShadeScene
@@ -40,6 +43,7 @@
constructor(
viewModel: QuickSettingsShadeSceneViewModel,
private val overlayShadeViewModel: OverlayShadeViewModel,
+ private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
) : ComposableScene {
override val key = Scenes.QuickSettingsShade
@@ -55,6 +59,7 @@
viewModel = overlayShadeViewModel,
modifier = modifier,
horizontalArrangement = Arrangement.End,
+ lockscreenContent = lockscreenContent,
) {
Text(
text = "Quick settings grid",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 00ef11d..2f11085 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -24,14 +24,11 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
@@ -40,14 +37,19 @@
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import com.android.systemui.util.kotlin.getOrNull
+import dagger.Lazy
+import java.util.Optional
/** The overlay shade renders a lightweight shade UI container on top of a background scene. */
@Composable
fun SceneScope.OverlayShade(
viewModel: OverlayShadeViewModel,
horizontalArrangement: Arrangement.Horizontal,
+ lockscreenContent: Lazy<Optional<LockscreenContent>>,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
@@ -55,7 +57,10 @@
Box(modifier) {
if (backgroundScene == Scenes.Lockscreen) {
- Lockscreen()
+ // Lockscreen content is optionally injected, because variants of System UI without a
+ // lockscreen cannot provide it.
+ val lockscreenContentOrNull = lockscreenContent.get().getOrNull()
+ lockscreenContentOrNull?.apply { Content(Modifier.fillMaxSize()) }
}
Scrim(onClicked = viewModel::onScrimClicked)
@@ -70,16 +75,6 @@
}
@Composable
-private fun Lockscreen(
- modifier: Modifier = Modifier,
-) {
- // TODO(b/338025605): This is a placeholder, replace with the actual lockscreen.
- Box(modifier = modifier.fillMaxSize().background(Color.LightGray)) {
- Text(text = "Lockscreen", modifier = Modifier.align(Alignment.Center))
- }
-}
-
-@Composable
private fun SceneScope.Scrim(
onClicked: () -> Unit,
modifier: Modifier = Modifier,
@@ -99,12 +94,7 @@
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
- Box(
- modifier =
- modifier
- .width(OverlayShade.Dimensions.PanelWidth)
- .clip(OverlayShade.Shapes.RoundedCornerPanel)
- ) {
+ Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
Spacer(
modifier =
Modifier.element(OverlayShade.Elements.PanelBackground)
@@ -137,8 +127,6 @@
object Dimensions {
val ScrimContentPadding = 16.dp
val PanelCornerRadius = 46.dp
- // TODO(b/338033836): This width should not be fixed.
- val PanelWidth = 390.dp
}
object Shapes {
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 a0278a6..9d689fc 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
@@ -279,7 +279,7 @@
viewModel.qsSceneAdapter,
{ viewModel.qsSceneAdapter.qqsHeight },
isSplitShade = false,
- squishiness = tileSquishiness,
+ squishiness = { tileSquishiness },
)
}
@@ -468,7 +468,7 @@
heightProvider = { viewModel.qsSceneAdapter.qsHeight },
isSplitShade = true,
modifier = Modifier.fillMaxWidth(),
- squishiness = tileSquishiness,
+ squishiness = { tileSquishiness },
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
index 15df1be..76ffc8b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
@@ -68,13 +68,17 @@
@Composable
private fun Content(dialog: SystemUIDialog) {
val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle(true)
-
if (!isAvailable) {
SideEffect { dialog.dismiss() }
return
}
val slice by viewModel.popupSlice.collectAsStateWithLifecycle()
+ if (!viewModel.isClickable(slice)) {
+ SideEffect { dialog.dismiss() }
+ return
+ }
+
SliceAndroidView(
modifier = Modifier.fillMaxWidth(),
slice = slice,
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 b5e9313..48a348b 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
@@ -21,6 +21,7 @@
import androidx.compose.animation.core.SpringSpec
import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@@ -190,16 +191,17 @@
}
// Animate the progress to its target value.
+ // Important: We start atomically to make sure that we start the coroutine even if it is
+ // cancelled right after it is launched, so that finishTransition() is correctly called.
+ // Otherwise, this transition will never be stopped and we will never settle to Idle.
transition.job =
- launch { animatable.animateTo(targetProgress, animationSpec, initialVelocity) }
- .apply {
- invokeOnCompletion {
- // Settle the state to Idle(target). Note that this will do nothing if this
- // transition was replaced/interrupted by another one, and this also runs if
- // this coroutine is cancelled, i.e. if [this] coroutine scope is cancelled.
- layoutState.finishTransition(transition, targetScene)
- }
+ launch(start = CoroutineStart.ATOMIC) {
+ try {
+ animatable.animateTo(targetProgress, animationSpec, initialVelocity)
+ } finally {
+ layoutState.finishTransition(transition, targetScene)
}
+ }
return transition
}
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 6758990..1f81245 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
@@ -33,6 +33,7 @@
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@@ -684,7 +685,11 @@
val isTargetGreater = targetOffset > animatable.value
val job =
coroutineScope
- .launch {
+ // Important: We start atomically to make sure that we start the coroutine even
+ // if it is cancelled right after it is launched, so that snapToScene() is
+ // correctly called. Otherwise, this transition will never be stopped and we
+ // will never settle to Idle.
+ .launch(start = CoroutineStart.ATOMIC) {
// TODO(b/327249191): Refactor the code so that we don't even launch a
// coroutine if we don't need to animate.
if (skipAnimation) {
@@ -726,18 +731,15 @@
}
} finally {
bouncingScene = null
+ snapToScene(targetScene)
}
}
- // Make sure that we settle to target scene at the end of the animation or if
- // the animation is cancelled.
- .apply { invokeOnCompletion { snapToScene(targetScene) } }
OffsetAnimation(animatable, job)
}
}
fun snapToScene(scene: SceneKey) {
- if (layoutState.transitionState != this) return
cancelOffsetAnimation()
layoutState.finishTransition(this, idleScene = scene)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 20742ee..d2a1de3 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
@@ -49,6 +49,7 @@
import com.android.compose.animation.scene.transformation.PropertyTransformation
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.ui.util.lerp
+import kotlin.math.roundToInt
import kotlinx.coroutines.launch
/** An element on screen, that can be composed in one or more scenes. */
@@ -81,11 +82,13 @@
/** The last state this element had in this scene. */
var lastOffset = Offset.Unspecified
+ var lastSize = SizeUnspecified
var lastScale = Scale.Unspecified
var lastAlpha = AlphaUnspecified
/** The state of this element in this scene right before the last interruption (if any). */
var offsetBeforeInterruption = Offset.Unspecified
+ var sizeBeforeInterruption = SizeUnspecified
var scaleBeforeInterruption = Scale.Unspecified
var alphaBeforeInterruption = AlphaUnspecified
@@ -96,6 +99,7 @@
* they nicely animate from their values down to 0.
*/
var offsetInterruptionDelta = Offset.Zero
+ var sizeInterruptionDelta = IntSize.Zero
var scaleInterruptionDelta = Scale.Zero
var alphaInterruptionDelta = 0f
@@ -127,7 +131,14 @@
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
key: ElementKey,
-): Modifier = this.then(ElementModifier(layoutImpl, scene, key)).testTag(key.testTag)
+): Modifier {
+ // Make sure that we read the current transitions during composition and not during
+ // layout/drawing.
+ // TODO(b/341072461): Revert this and read the current transitions in ElementNode directly once
+ // we can ensure that SceneTransitionLayoutImpl will compose new scenes first.
+ val currentTransitions = layoutImpl.state.currentTransitions
+ return then(ElementModifier(layoutImpl, currentTransitions, scene, key)).testTag(key.testTag)
+}
/**
* An element associated to [ElementNode]. Note that this element does not support updates as its
@@ -135,18 +146,20 @@
*/
private data class ElementModifier(
private val layoutImpl: SceneTransitionLayoutImpl,
+ private val currentTransitions: List<TransitionState.Transition>,
private val scene: Scene,
private val key: ElementKey,
) : ModifierNodeElement<ElementNode>() {
- override fun create(): ElementNode = ElementNode(layoutImpl, scene, key)
+ override fun create(): ElementNode = ElementNode(layoutImpl, currentTransitions, scene, key)
override fun update(node: ElementNode) {
- node.update(layoutImpl, scene, key)
+ node.update(layoutImpl, currentTransitions, scene, key)
}
}
internal class ElementNode(
private var layoutImpl: SceneTransitionLayoutImpl,
+ private var currentTransitions: List<TransitionState.Transition>,
private var scene: Scene,
private var key: ElementKey,
) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode {
@@ -202,10 +215,13 @@
fun update(
layoutImpl: SceneTransitionLayoutImpl,
+ currentTransitions: List<TransitionState.Transition>,
scene: Scene,
key: ElementKey,
) {
check(layoutImpl == this.layoutImpl && scene == this.scene)
+ this.currentTransitions = currentTransitions
+
removeNodeFromSceneState()
val prevElement = this.element
@@ -236,7 +252,10 @@
measurable: Measurable,
constraints: Constraints,
): MeasureResult {
- val transitions = layoutImpl.state.currentTransitions
+ // Update the size this element has in this scene when idle.
+ sceneState.targetSize = lookaheadSize
+
+ val transitions = currentTransitions
val transition = elementTransition(element, transitions)
// If this element is not supposed to be laid out now, either because it is not part of any
@@ -251,11 +270,22 @@
sceneState.lastAlpha = Element.AlphaUnspecified
val placeable = measurable.measure(constraints)
- return layout(placeable.width, placeable.height) {}
+ sceneState.lastSize = placeable.size()
+
+ this as LookaheadScope
+ return layout(placeable.width, placeable.height) {
+ // Update the offset (relative to the SceneTransitionLayout) this element has in
+ // this scene when idle.
+ coordinates?.let { coords ->
+ sceneState.targetOffset =
+ lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
+ }
+ }
}
val placeable =
measure(layoutImpl, scene, element, transition, sceneState, measurable, constraints)
+ sceneState.lastSize = placeable.size()
return layout(placeable.width, placeable.height) {
place(
layoutImpl,
@@ -270,7 +300,7 @@
}
override fun ContentDrawScope.draw() {
- val transition = elementTransition(element, layoutImpl.state.currentTransitions)
+ val transition = elementTransition(element, currentTransitions)
val drawScale = getDrawScale(layoutImpl, scene, element, transition, sceneState)
if (drawScale == Scale.Default) {
drawContent()
@@ -324,10 +354,8 @@
if (transition != previousTransition && transition != null && previousTransition != null) {
// The previous transition was interrupted by another transition.
- prepareInterruption(element)
- }
-
- if (transition == null && previousTransition != null) {
+ prepareInterruption(element, transition, previousTransition)
+ } else if (transition == null && previousTransition != null) {
// The transition was just finished.
element.sceneStates.values.forEach {
it.clearValuesBeforeInterruption()
@@ -338,48 +366,108 @@
return transition
}
-private fun prepareInterruption(element: Element) {
- // We look for the last unique state of this element so that we animate the delta with its
- // future state.
- val sceneStates = element.sceneStates.values
- var lastUniqueState: Element.SceneState? = null
- for (sceneState in sceneStates) {
- val offset = sceneState.lastOffset
+private fun prepareInterruption(
+ element: Element,
+ transition: TransitionState.Transition,
+ previousTransition: TransitionState.Transition,
+) {
+ val previousUniqueState = reconcileStates(element, previousTransition)
+ if (previousUniqueState == null) {
+ reconcileStates(element, transition)
+ return
+ }
- // If the element was placed in this scene...
- if (offset != Offset.Unspecified) {
- // ... and it is the first (and potentially the only) scene where the element was
- // placed, save the state for later.
- if (lastUniqueState == null) {
- lastUniqueState = sceneState
- } else {
- // The element was placed in multiple scenes: we abort the interruption for this
- // element.
- // TODO(b/290930950): Better support cases where a shared element animation is
- // disabled and the same element is drawn/placed in multiple scenes at the same
- // time.
- lastUniqueState = null
- break
+ val fromSceneState = element.sceneStates[transition.fromScene]
+ val toSceneState = element.sceneStates[transition.toScene]
+
+ if (
+ fromSceneState == null ||
+ toSceneState == null ||
+ sharedElementTransformation(element.key, transition)?.enabled != false
+ ) {
+ // If there is only one copy of the element or if the element is shared, animate deltas in
+ // both scenes.
+ fromSceneState?.updateValuesBeforeInterruption(previousUniqueState)
+ toSceneState?.updateValuesBeforeInterruption(previousUniqueState)
+ }
+}
+
+/**
+ * Reconcile the state of [element] in the fromScene and toScene of [transition] so that the values
+ * before interruption have their expected values, taking shared transitions into account.
+ *
+ * If the element had a unique state, i.e. it is shared in [transition] or it is only present in one
+ * of the scenes, return it.
+ */
+private fun reconcileStates(
+ element: Element,
+ transition: TransitionState.Transition,
+): Element.SceneState? {
+ val fromSceneState = element.sceneStates[transition.fromScene]
+ val toSceneState = element.sceneStates[transition.toScene]
+ when {
+ // Element is in both scenes.
+ fromSceneState != null && toSceneState != null -> {
+ val isSharedTransformationDisabled =
+ sharedElementTransformation(element.key, transition)?.enabled == false
+ when {
+ // Element shared transition is disabled so the element is placed in both scenes.
+ isSharedTransformationDisabled -> {
+ fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+ toSceneState.updateValuesBeforeInterruption(toSceneState)
+ return null
+ }
+
+ // Element is shared and placed in fromScene only.
+ fromSceneState.lastOffset != Offset.Unspecified -> {
+ fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+ toSceneState.updateValuesBeforeInterruption(fromSceneState)
+ return fromSceneState
+ }
+
+ // Element is shared and placed in toScene only.
+ toSceneState.lastOffset != Offset.Unspecified -> {
+ fromSceneState.updateValuesBeforeInterruption(toSceneState)
+ toSceneState.updateValuesBeforeInterruption(toSceneState)
+ return toSceneState
+ }
+
+ // Element is in none of the scenes.
+ else -> {
+ fromSceneState.updateValuesBeforeInterruption(null)
+ toSceneState.updateValuesBeforeInterruption(null)
+ return null
+ }
}
}
+
+ // Element is only in fromScene.
+ fromSceneState != null -> {
+ fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+ return fromSceneState
+ }
+
+ // Element is only in toScene.
+ toSceneState != null -> {
+ toSceneState.updateValuesBeforeInterruption(toSceneState)
+ return toSceneState
+ }
+ else -> return null
}
+}
- val lastOffset = lastUniqueState?.lastOffset ?: Offset.Unspecified
- val lastScale = lastUniqueState?.lastScale ?: Scale.Unspecified
- val lastAlpha = lastUniqueState?.lastAlpha ?: Element.AlphaUnspecified
+private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState?) {
+ offsetBeforeInterruption = lastState?.lastOffset ?: Offset.Unspecified
+ sizeBeforeInterruption = lastState?.lastSize ?: Element.SizeUnspecified
+ scaleBeforeInterruption = lastState?.lastScale ?: Scale.Unspecified
+ alphaBeforeInterruption = lastState?.lastAlpha ?: Element.AlphaUnspecified
- // Store the state of the element before the interruption and reset the deltas.
- sceneStates.forEach { sceneState ->
- sceneState.offsetBeforeInterruption = lastOffset
- sceneState.scaleBeforeInterruption = lastScale
- sceneState.alphaBeforeInterruption = lastAlpha
-
- sceneState.clearInterruptionDeltas()
- }
+ clearInterruptionDeltas()
}
private fun Element.SceneState.clearInterruptionDeltas() {
offsetInterruptionDelta = Offset.Zero
+ sizeInterruptionDelta = IntSize.Zero
scaleInterruptionDelta = Scale.Zero
alphaInterruptionDelta = 0f
}
@@ -615,7 +703,6 @@
)
}
-@OptIn(ExperimentalComposeUiApi::class)
private fun ApproachMeasureScope.measure(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
@@ -625,20 +712,11 @@
measurable: Measurable,
constraints: Constraints,
): Placeable {
- // Update the size this element has in this scene when idle.
- val targetSizeInScene = lookaheadSize
- if (targetSizeInScene != sceneState.targetSize) {
- // TODO(b/290930950): Better handle when this changes to avoid instant size jumps.
- sceneState.targetSize = targetSizeInScene
- }
-
// Some lambdas called (max once) by computeValue() will need to measure [measurable], in which
// case we store the resulting placeable here to make sure the element is not measured more than
// once.
var maybePlaceable: Placeable? = null
- fun Placeable.size() = IntSize(width, height)
-
val targetSize =
computeValue(
layoutImpl,
@@ -653,15 +731,44 @@
::lerp,
)
- return maybePlaceable
- ?: measurable.measure(
- Constraints.fixed(
- targetSize.width.coerceAtLeast(0),
- targetSize.height.coerceAtLeast(0),
- )
+ // The measurable was already measured, so we can't take interruptions into account here given
+ // that we are not allowed to measure the same measurable twice.
+ maybePlaceable?.let { placeable ->
+ sceneState.sizeBeforeInterruption = Element.SizeUnspecified
+ sceneState.sizeInterruptionDelta = IntSize.Zero
+ return placeable
+ }
+
+ val interruptedSize =
+ computeInterruptedValue(
+ layoutImpl,
+ transition,
+ value = targetSize,
+ unspecifiedValue = Element.SizeUnspecified,
+ zeroValue = IntSize.Zero,
+ getValueBeforeInterruption = { sceneState.sizeBeforeInterruption },
+ setValueBeforeInterruption = { sceneState.sizeBeforeInterruption = it },
+ getInterruptionDelta = { sceneState.sizeInterruptionDelta },
+ setInterruptionDelta = { sceneState.sizeInterruptionDelta = it },
+ diff = { a, b -> IntSize(a.width - b.width, a.height - b.height) },
+ add = { a, b, bProgress ->
+ IntSize(
+ (a.width + b.width * bProgress).roundToInt(),
+ (a.height + b.height * bProgress).roundToInt(),
+ )
+ },
)
+
+ return measurable.measure(
+ Constraints.fixed(
+ interruptedSize.width.coerceAtLeast(0),
+ interruptedSize.height.coerceAtLeast(0),
+ )
+ )
}
+private fun Placeable.size(): IntSize = IntSize(width, height)
+
private fun ContentDrawScope.getDrawScale(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
@@ -745,10 +852,7 @@
// when idle.
val coords = coordinates ?: error("Element ${element.key} does not have any coordinates")
val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
- if (targetOffsetInScene != sceneState.targetOffset) {
- // TODO(b/290930950): Better handle when this changes to avoid instant offset jumps.
- sceneState.targetOffset = targetOffsetInScene
- }
+ sceneState.targetOffset = targetOffsetInScene
// No need to place the element in this scene if we don't want to draw it anyways.
if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 92d5c26..f1b2249 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -73,7 +73,16 @@
* the transition completes/settles.
*/
val isUserInputOngoing: Flow<Boolean>,
- ) : ObservableTransitionState
+ ) : ObservableTransitionState {
+ override fun toString(): String =
+ """Transition
+ |(from=$fromScene,
+ | to=$toScene,
+ | isInitiatedByUserInput=$isInitiatedByUserInput,
+ | isUserInputOngoing=$isUserInputOngoing
+ |)"""
+ .trimMargin()
+ }
fun isIdle(scene: SceneKey?): Boolean {
return this is Idle && (scene == null || this.currentScene == scene)
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 d383cec..7856498 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
@@ -126,6 +126,10 @@
orientation = Orientation.Vertical,
coroutineScope = coroutineScope,
)
+
+ // Make sure that the state is created on the same thread (most probably the main thread)
+ // than this STLImpl.
+ state.checkThread()
}
internal fun draggableHandler(orientation: Orientation): DraggableHandlerImpl =
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 4e3a032..a5b6d24 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
@@ -26,8 +26,10 @@
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.snapshots.SnapshotStateList
+import androidx.compose.runtime.setValue
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastFilter
import androidx.compose.ui.util.fastForEach
@@ -374,14 +376,17 @@
// TODO(b/290930950): Remove this flag.
internal var enableInterruptions: Boolean,
) : SceneTransitionLayoutState {
+ private val creationThread: Thread = Thread.currentThread()
+
/**
* 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.
*/
@VisibleForTesting
- internal val transitionStates: MutableList<TransitionState> =
- SnapshotStateList<TransitionState>().apply { add(TransitionState.Idle(initialScene)) }
+ internal var transitionStates: List<TransitionState> by
+ mutableStateOf(listOf(TransitionState.Idle(initialScene)))
+ private set
override val transitionState: TransitionState
get() = transitionStates.last()
@@ -417,6 +422,20 @@
*/
internal abstract fun CoroutineScope.onChangeScene(scene: SceneKey)
+ internal fun checkThread() {
+ val current = Thread.currentThread()
+ if (current !== creationThread) {
+ error(
+ """
+ Only the original thread that created a SceneTransitionLayoutState can mutate it
+ Expected: ${creationThread.name}
+ Current: ${current.name}
+ """
+ .trimIndent()
+ )
+ }
+ }
+
override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean {
val transition = currentTransition ?: return false
return transition.isTransitioning(from, to)
@@ -441,6 +460,8 @@
transitionKey: TransitionKey?,
chain: Boolean = true,
) {
+ checkThread()
+
// Compute the [TransformationSpec] when the transition starts.
val fromScene = transition.fromScene
val toScene = transition.toScene
@@ -465,7 +486,7 @@
if (!enableInterruptions) {
// Set the current transition.
check(transitionStates.size == 1)
- transitionStates[0] = transition
+ transitionStates = listOf(transition)
return
}
@@ -473,14 +494,12 @@
is TransitionState.Idle -> {
// Replace [Idle] by [transition].
check(transitionStates.size == 1)
- transitionStates[0] = transition
+ transitionStates = listOf(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)
- }
+ // Force the current transition to finish to currentScene. The transition will call
+ // [finishTransition] once it's finished.
+ currentState.finish()
val tooManyTransitions = transitionStates.size >= MAX_CONCURRENT_TRANSITIONS
val clearCurrentTransitions = !chain || tooManyTransitions
@@ -497,11 +516,11 @@
// we end up only with the new transition after appending it.
check(transitionStates.size == 1)
check(transitionStates[0] is TransitionState.Idle)
- transitionStates.clear()
+ transitionStates = listOf(transition)
+ } else {
+ // Append the new transition.
+ transitionStates = transitionStates + transition
}
-
- // Append the new transition.
- transitionStates.add(transition)
}
}
}
@@ -561,6 +580,8 @@
* nothing if [transition] was interrupted since it was started.
*/
internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ checkThread()
+
val existingIdleScene = finishedTransitions[transition]
if (existingIdleScene != null) {
// This transition was already finished.
@@ -571,6 +592,7 @@
return
}
+ val transitionStates = this.transitionStates
if (!transitionStates.contains(transition)) {
// This transition was already removed from transitionStates.
return
@@ -589,25 +611,42 @@
var lastRemovedIdleScene: SceneKey? = null
// Remove all first n finished transitions.
- while (transitionStates.isNotEmpty()) {
- val firstTransition = transitionStates[0]
- if (!finishedTransitions.contains(firstTransition)) {
+ var i = 0
+ val nStates = transitionStates.size
+ while (i < nStates) {
+ val t = transitionStates[i]
+ if (!finishedTransitions.contains(t)) {
// Stop here.
break
}
- // Remove the transition from the list and from the set of finished transitions.
- transitionStates.removeAt(0)
- lastRemovedIdleScene = finishedTransitions.remove(firstTransition)
+ // Remove the transition from the set of finished transitions.
+ lastRemovedIdleScene = finishedTransitions.remove(t)
+ i++
}
// If all transitions are finished, we are idle.
- if (transitionStates.isEmpty()) {
+ if (i == nStates) {
check(finishedTransitions.isEmpty())
- transitionStates.add(TransitionState.Idle(checkNotNull(lastRemovedIdleScene)))
+ this.transitionStates = listOf(TransitionState.Idle(checkNotNull(lastRemovedIdleScene)))
+ } else if (i > 0) {
+ this.transitionStates = transitionStates.subList(fromIndex = i, toIndex = nStates)
}
}
+ fun snapToScene(scene: SceneKey) {
+ checkThread()
+
+ // Force finish all transitions.
+ while (currentTransitions.isNotEmpty()) {
+ val transition = transitionStates[0] as TransitionState.Transition
+ finishTransition(transition, transition.currentScene)
+ }
+
+ check(transitionStates.size == 1)
+ transitionStates = listOf(TransitionState.Idle(scene))
+ }
+
private fun finishActiveTransitionLinks(idleScene: SceneKey) {
val previousTransition = this.transitionState as? TransitionState.Transition ?: return
for ((link, linkedTransition) in activeTransitionLinks) {
@@ -736,6 +775,8 @@
coroutineScope: CoroutineScope,
transitionKey: TransitionKey?,
): TransitionState.Transition? {
+ checkThread()
+
return coroutineScope.animateToScene(
layoutState = this@MutableSceneTransitionLayoutStateImpl,
target = targetScene,
@@ -748,17 +789,6 @@
override fun CoroutineScope.onChangeScene(scene: SceneKey) {
setTargetScene(scene, coroutineScope = this)
}
-
- override fun snapToScene(scene: SceneKey) {
- // Force finish all transitions.
- while (currentTransitions.isNotEmpty()) {
- val transition = transitionStates[0] as TransitionState.Transition
- finishTransition(transition, transition.currentScene)
- }
-
- check(transitionStates.size == 1)
- transitionStates[0] = TransitionState.Idle(scene)
- }
}
private const val TAG = "SceneTransitionLayoutState"
diff --git a/packages/SystemUI/compose/scene/tests/Android.bp b/packages/SystemUI/compose/scene/tests/Android.bp
index af13896..3509504 100644
--- a/packages/SystemUI/compose/scene/tests/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/Android.bp
@@ -25,8 +25,8 @@
android_test {
name: "PlatformComposeSceneTransitionLayoutTests",
manifest: "AndroidManifest.xml",
+ defaults: ["MotionTestDefaults"],
test_suites: ["device-tests"],
- certificate: "platform",
srcs: [
"src/**/*.kt",
@@ -38,7 +38,7 @@
static_libs: [
"PlatformComposeSceneTransitionLayoutTestsUtils",
-
+ "PlatformMotionTestingCompose",
"androidx.test.runner",
"androidx.test.ext.junit",
@@ -48,7 +48,7 @@
"truth",
],
-
+ asset_dirs: ["goldens"],
kotlincflags: ["-Xjvm-default=all"],
use_resource_processor: true,
}
diff --git a/packages/SystemUI/compose/scene/tests/AndroidManifest.xml b/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
index 1a9172e..174ad30 100644
--- a/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
+++ b/packages/SystemUI/compose/scene/tests/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.compose.animation.scene.tests" >
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredHeightOnly.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredHeightOnly.json
new file mode 100644
index 0000000..0843663
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredHeightOnly.json
@@ -0,0 +1,41 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "Bar_size",
+ "type": "dpSize",
+ "data_points": [
+ {
+ "type": "not_found"
+ },
+ {
+ "width": 200,
+ "height": 100
+ },
+ {
+ "width": 200,
+ "height": 90
+ },
+ {
+ "width": 200,
+ "height": 80
+ },
+ {
+ "width": 200,
+ "height": 70
+ },
+ {
+ "width": 200,
+ "height": 60
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
new file mode 100644
index 0000000..2df44091
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
@@ -0,0 +1,41 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "Bar_size",
+ "type": "dpSize",
+ "data_points": [
+ {
+ "type": "not_found"
+ },
+ {
+ "width": 100,
+ "height": 100
+ },
+ {
+ "width": 125.14286,
+ "height": 90
+ },
+ {
+ "width": 150,
+ "height": 80
+ },
+ {
+ "width": 175.14285,
+ "height": 70
+ },
+ {
+ "width": 200,
+ "height": 60
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
new file mode 100644
index 0000000..2b0a954
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
@@ -0,0 +1,41 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "Bar_size",
+ "type": "dpSize",
+ "data_points": [
+ {
+ "width": 100,
+ "height": 100
+ },
+ {
+ "width": 100,
+ "height": 100
+ },
+ {
+ "width": 125.14286,
+ "height": 90
+ },
+ {
+ "width": 150,
+ "height": 80
+ },
+ {
+ "width": 175.14285,
+ "height": 70
+ },
+ {
+ "type": "not_found"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
new file mode 100644
index 0000000..027df29
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
@@ -0,0 +1,41 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "Bar_size",
+ "type": "dpSize",
+ "data_points": [
+ {
+ "type": "not_found"
+ },
+ {
+ "width": 100,
+ "height": 60
+ },
+ {
+ "width": 125.14286,
+ "height": 60
+ },
+ {
+ "width": 150,
+ "height": 60
+ },
+ {
+ "width": 175.14285,
+ "height": 60
+ },
+ {
+ "width": 200,
+ "height": 60
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
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 e19dc96..9692fae 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
@@ -56,6 +56,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.lerp
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -63,11 +64,13 @@
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
import com.android.compose.animation.scene.subjects.assertThat
+import com.android.compose.test.assertSizeIsEqualTo
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -237,9 +240,9 @@
changeScene(SceneC)
}
- at(2 * frameDuration) { onElement(TestElements.Bar).assertIsNotDisplayed() }
+ at(3 * frameDuration) { onElement(TestElements.Bar).assertIsNotDisplayed() }
- at(3 * frameDuration) { onElement(TestElements.Bar).assertDoesNotExist() }
+ at(4 * frameDuration) { onElement(TestElements.Bar).assertDoesNotExist() }
}
}
@@ -578,6 +581,7 @@
}
@Test
+ @Ignore("b/341072461")
fun existingElementsDontRecomposeWhenTransitionStateChanges() {
var fooCompositions = 0
@@ -603,6 +607,43 @@
}
}
+ @Test
+ // TODO(b/341072461): Remove this test.
+ fun layoutGetsCurrentTransitionStateFromComposition() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) {
+ scaleSize(TestElements.Foo, width = 2f, height = 2f)
+ }
+ }
+ )
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state) {
+ scene(SceneA) { Box(Modifier.element(TestElements.Foo).size(20.dp)) }
+ scene(SceneB) {}
+ }
+ }
+
+ // Pause the clock to block recompositions.
+ rule.mainClock.autoAdvance = false
+
+ // Change the current transition.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, progress = { 0.5f }),
+ transitionKey = null,
+ )
+ }
+
+ // The size of Foo should still be 20dp given that the new state was not composed yet.
+ rule.onNode(isElement(TestElements.Foo)).assertSizeIsEqualTo(20.dp, 20.dp)
+ }
+
private fun setupOverscrollScenario(
layoutWidth: Dp,
layoutHeight: Dp,
@@ -616,11 +657,13 @@
var touchSlop = 0f
val state =
- MutableSceneTransitionLayoutState(
- initialScene = SceneA,
- transitions = transitions(sceneTransitions),
- )
- as MutableSceneTransitionLayoutStateImpl
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ initialScene = SceneA,
+ transitions = transitions(sceneTransitions),
+ )
+ as MutableSceneTransitionLayoutStateImpl
+ }
rule.setContent {
touchSlop = LocalViewConfiguration.current.touchSlop
@@ -726,16 +769,18 @@
val layoutHeight = 400.dp
val state =
- MutableSceneTransitionLayoutState(
- initialScene = SceneB,
- transitions =
- transitions {
- overscroll(SceneB, Orientation.Vertical) {
- translate(TestElements.Foo, y = overscrollTranslateY)
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ initialScene = SceneB,
+ transitions =
+ transitions {
+ overscroll(SceneB, Orientation.Vertical) {
+ translate(TestElements.Foo, y = overscrollTranslateY)
+ }
}
- }
- )
- as MutableSceneTransitionLayoutStateImpl
+ )
+ as MutableSceneTransitionLayoutStateImpl
+ }
rule.setContent {
touchSlop = LocalViewConfiguration.current.touchSlop
@@ -902,32 +947,36 @@
val duration = 4 * 16
val state =
- MutableSceneTransitionLayoutState(
- SceneA,
- transitions {
- // Foo is at the top left corner of scene A. We make it disappear during A => B
- // to the right edge so it translates to the right.
- from(SceneA, to = SceneB) {
- spec = tween(duration, easing = LinearEasing)
- translate(
- TestElements.Foo,
- edge = Edge.Right,
- startsOutsideLayoutBounds = false,
- )
- }
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions {
+ // Foo is at the top left corner of scene A. We make it disappear during A
+ // => B
+ // to the right edge so it translates to the right.
+ from(SceneA, to = SceneB) {
+ spec = tween(duration, easing = LinearEasing)
+ translate(
+ TestElements.Foo,
+ edge = Edge.Right,
+ startsOutsideLayoutBounds = false,
+ )
+ }
- // Bar is at the top right corner of scene C. We make it appear during B => C
- // from the left edge so it translates to the right at same time as Foo.
- from(SceneB, to = SceneC) {
- spec = tween(duration, easing = LinearEasing)
- translate(
- TestElements.Bar,
- edge = Edge.Left,
- startsOutsideLayoutBounds = false,
- )
+ // Bar is at the top right corner of scene C. We make it appear during B =>
+ // C
+ // from the left edge so it translates to the right at same time as Foo.
+ from(SceneB, to = SceneC) {
+ spec = tween(duration, easing = LinearEasing)
+ translate(
+ TestElements.Bar,
+ edge = Edge.Left,
+ startsOutsideLayoutBounds = false,
+ )
+ }
}
- }
- )
+ )
+ }
val layoutSize = 150.dp
val elemSize = 50.dp
@@ -1023,23 +1072,28 @@
val duration = 4 * 16
val state =
- MutableSceneTransitionLayoutStateImpl(
- SceneA,
- transitions {
- from(SceneA, to = SceneB) { spec = tween(duration, easing = LinearEasing) }
- from(SceneB, to = SceneC) { spec = tween(duration, easing = LinearEasing) }
- },
- enableInterruptions = false,
- )
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) { spec = tween(duration, easing = LinearEasing) }
+ from(SceneB, to = SceneC) { spec = tween(duration, easing = LinearEasing) }
+ },
+ )
+ }
val layoutSize = DpSize(200.dp, 100.dp)
- val fooSize = DpSize(20.dp, 10.dp)
@Composable
- fun SceneScope.Foo(modifier: Modifier = Modifier) {
- Box(modifier.element(TestElements.Foo).size(fooSize))
+ fun SceneScope.Foo(size: Dp, modifier: Modifier = Modifier) {
+ Box(modifier.element(TestElements.Foo).size(size))
}
+ // The size of Foo when idle in A, B or C.
+ val sizeInA = 10.dp
+ val sizeInB = 30.dp
+ val sizeInC = 50.dp
+
lateinit var layoutImpl: SceneTransitionLayoutImpl
rule.setContent {
SceneTransitionLayoutForTesting(
@@ -1049,33 +1103,35 @@
) {
// In scene A, Foo is aligned at the TopStart.
scene(SceneA) {
- Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) }
+ Box(Modifier.fillMaxSize()) { Foo(sizeInA, Modifier.align(Alignment.TopStart)) }
}
// In scene C, Foo is aligned at the BottomEnd, so it moves vertically when coming
// from B. We put it before (below) scene B so that we can check that interruptions
// values and deltas are properly cleared once all transitions are done.
scene(SceneC) {
- Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
+ Box(Modifier.fillMaxSize()) {
+ Foo(sizeInC, Modifier.align(Alignment.BottomEnd))
+ }
}
// In scene B, Foo is aligned at the TopEnd, so it moves horizontally when coming
// from A.
scene(SceneB) {
- Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopEnd)) }
+ Box(Modifier.fillMaxSize()) { Foo(sizeInB, Modifier.align(Alignment.TopEnd)) }
}
}
}
// The offset of Foo when idle in A, B or C.
val offsetInA = DpOffset.Zero
- val offsetInB = DpOffset(layoutSize.width - fooSize.width, 0.dp)
- val offsetInC =
- DpOffset(layoutSize.width - fooSize.width, layoutSize.height - fooSize.height)
+ val offsetInB = DpOffset(layoutSize.width - sizeInB, 0.dp)
+ val offsetInC = DpOffset(layoutSize.width - sizeInC, layoutSize.height - sizeInC)
// Initial state (idle in A).
rule
.onNode(isElement(TestElements.Foo, SceneA))
+ .assertSizeIsEqualTo(sizeInA)
.assertPositionInRootIsEqualTo(offsetInA.x, offsetInA.y)
// Current transition is A => B at 50%.
@@ -1088,9 +1144,11 @@
onFinish = neverFinish(),
)
val offsetInAToB = lerp(offsetInA, offsetInB, aToBProgress)
+ val sizeInAToB = lerp(sizeInA, sizeInB, aToBProgress)
rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
rule
.onNode(isElement(TestElements.Foo, SceneB))
+ .assertSizeIsEqualTo(sizeInAToB)
.assertPositionInRootIsEqualTo(offsetInAToB.x, offsetInAToB.y)
// Start B => C at 0%.
@@ -1105,26 +1163,30 @@
)
rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
- // The offset interruption delta, which will be multiplied by the interruption progress then
- // added to the current transition offset.
- val interruptionDelta = offsetInAToB - offsetInB
+ // The interruption deltas, which will be multiplied by the interruption progress then added
+ // to the current transition offset and size.
+ val offsetInterruptionDelta = offsetInAToB - offsetInB
+ val sizeInterruptionDelta = sizeInAToB - sizeInB
// Interruption progress is at 100% and bToC is at 0%, so Foo should be at the same offset
- // as right before the interruption.
+ // and size as right before the interruption.
rule
.onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(offsetInAToB.x, offsetInAToB.y)
+ .assertSizeIsEqualTo(sizeInAToB)
// Move the transition forward at 30% and set the interruption progress to 50%.
bToCProgress = 0.3f
interruptionProgress = 0.5f
val offsetInBToC = lerp(offsetInB, offsetInC, bToCProgress)
+ val sizeInBToC = lerp(sizeInB, sizeInC, bToCProgress)
val offsetInBToCWithInterruption =
offsetInBToC +
DpOffset(
- interruptionDelta.x * interruptionProgress,
- interruptionDelta.y * interruptionProgress,
+ offsetInterruptionDelta.x * interruptionProgress,
+ offsetInterruptionDelta.y * interruptionProgress,
)
+ val sizeInBToCWithInterruption = sizeInBToC + sizeInterruptionDelta * interruptionProgress
rule.waitForIdle()
rule
.onNode(isElement(TestElements.Foo, SceneB))
@@ -1132,6 +1194,7 @@
offsetInBToCWithInterruption.x,
offsetInBToCWithInterruption.y,
)
+ .assertSizeIsEqualTo(sizeInBToCWithInterruption)
// Finish the transition and interruption.
bToCProgress = 1f
@@ -1139,10 +1202,13 @@
rule
.onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+ .assertSizeIsEqualTo(sizeInC)
// Manually finish the transition.
- state.finishTransition(aToB, SceneB)
- state.finishTransition(bToC, SceneC)
+ rule.runOnUiThread {
+ state.finishTransition(aToB, SceneB)
+ state.finishTransition(bToC, SceneC)
+ }
rule.waitForIdle()
assertThat(state.transitionState).isIdle()
@@ -1151,10 +1217,162 @@
assertThat(foo.sceneStates.keys).containsExactly(SceneC)
val stateInC = foo.sceneStates.getValue(SceneC)
assertThat(stateInC.offsetBeforeInterruption).isEqualTo(Offset.Unspecified)
+ assertThat(stateInC.sizeBeforeInterruption).isEqualTo(Element.SizeUnspecified)
assertThat(stateInC.scaleBeforeInterruption).isEqualTo(Scale.Unspecified)
assertThat(stateInC.alphaBeforeInterruption).isEqualTo(Element.AlphaUnspecified)
assertThat(stateInC.offsetInterruptionDelta).isEqualTo(Offset.Zero)
+ assertThat(stateInC.sizeInterruptionDelta).isEqualTo(IntSize.Zero)
assertThat(stateInC.scaleInterruptionDelta).isEqualTo(Scale.Zero)
assertThat(stateInC.alphaInterruptionDelta).isEqualTo(0f)
}
+
+ @Test
+ fun interruption_sharedTransitionDisabled() = runTest {
+ // 4 frames of animation.
+ val duration = 4 * 16
+ val layoutSize = DpSize(200.dp, 100.dp)
+ val fooSize = 100.dp
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) { spec = tween(duration, easing = LinearEasing) }
+
+ // Disable the shared transition during B => C.
+ from(SceneB, to = SceneC) {
+ spec = tween(duration, easing = LinearEasing)
+ sharedElement(TestElements.Foo, enabled = false)
+ }
+ },
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ Box(modifier.element(TestElements.Foo).size(fooSize))
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+ scene(SceneA) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) }
+ }
+
+ scene(SceneB) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopEnd)) }
+ }
+
+ scene(SceneC) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
+ }
+ }
+ }
+
+ // The offset of Foo when idle in A, B or C.
+ val offsetInA = DpOffset.Zero
+ val offsetInB = DpOffset(layoutSize.width - fooSize, 0.dp)
+ val offsetInC = DpOffset(layoutSize.width - fooSize, layoutSize.height - fooSize)
+
+ // State is a transition A => B at 50% interrupted by B => C at 30%.
+ val aToB =
+ transition(from = SceneA, to = SceneB, progress = { 0.5f }, onFinish = neverFinish())
+ var bToCInterruptionProgress by mutableStateOf(1f)
+ val bToC =
+ transition(
+ from = SceneB,
+ to = SceneC,
+ progress = { 0.3f },
+ interruptionProgress = { bToCInterruptionProgress },
+ onFinish = neverFinish(),
+ )
+ rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
+ rule.waitForIdle()
+ rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
+
+ // Foo is placed in both B and C given that the shared transition is disabled. In B, its
+ // offset is impacted by the interruption but in C it is not.
+ val offsetInAToB = lerp(offsetInA, offsetInB, 0.5f)
+ val interruptionDelta = offsetInAToB - offsetInB
+ assertThat(interruptionDelta).isNotEqualTo(Offset.Zero)
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(
+ offsetInB.x + interruptionDelta.x,
+ offsetInB.y + interruptionDelta.y,
+ )
+
+ rule
+ .onNode(isElement(TestElements.Foo, SceneC))
+ .assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+
+ // Manually finish A => B so only B => C is remaining.
+ bToCInterruptionProgress = 0f
+ rule.runOnUiThread { state.finishTransition(aToB, SceneB) }
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
+ rule
+ .onNode(isElement(TestElements.Foo, SceneC))
+ .assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+
+ // Interrupt B => C by B => A, starting directly at 70%
+ val bToA =
+ transition(
+ from = SceneB,
+ to = SceneA,
+ progress = { 0.7f },
+ interruptionProgress = { 1f },
+ )
+ rule.runOnUiThread { state.startTransition(bToA, transitionKey = null) }
+
+ // Foo should have the position it had in B right before the interruption.
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
+ }
+
+ @Test
+ fun targetStateIsSetEvenWhenNotPlaced() {
+ // Start directly at A => B but with progress < 0f to overscroll on A.
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneA, Orientation.Horizontal) {} }
+ )
+ .apply {
+ startTransition(
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { -1f },
+ orientation = Orientation.Horizontal
+ ),
+ transitionKey = null,
+ )
+ }
+ }
+
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
+ rule.setContent {
+ SceneTransitionLayoutForTesting(
+ state,
+ Modifier.size(100.dp),
+ onLayoutImpl = { layoutImpl = it },
+ ) {
+ scene(SceneA) {}
+ scene(SceneB) { Box(Modifier.element(TestElements.Foo)) }
+ }
+ }
+
+ assertThat(layoutImpl.elements).containsKey(TestElements.Foo)
+ val foo = layoutImpl.elements.getValue(TestElements.Foo)
+
+ assertThat(foo.sceneStates).containsKey(SceneB)
+ val bState = foo.sceneStates.getValue(SceneB)
+
+ assertThat(bState.targetSize).isNotEqualTo(Element.SizeUnspecified)
+ assertThat(bState.targetOffset).isNotEqualTo(Offset.Unspecified)
+ }
}
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 692c18b..3751a22 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
@@ -76,12 +76,13 @@
/** The content under test. */
@Composable
- private fun TestContent() {
+ private fun TestContent(enableInterruptions: Boolean = true) {
layoutState =
updateSceneTransitionLayoutState(
currentScene,
{ currentScene = it },
- EmptyTestTransitions
+ EmptyTestTransitions,
+ enableInterruptions = enableInterruptions,
)
SceneTransitionLayout(
@@ -219,7 +220,7 @@
@Test
fun testSharedElement() {
- rule.setContent { TestContent() }
+ rule.setContent { TestContent(enableInterruptions = false) }
// In scene A, the shared element SharedFoo() is at the top end of the layout and has a size
// of 50.dp.
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 1dd9322..3a806a4 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
@@ -70,7 +70,9 @@
private fun layoutState(
initialScene: SceneKey = SceneA,
transitions: SceneTransitions = EmptyTestTransitions,
- ) = MutableSceneTransitionLayoutState(initialScene, transitions)
+ ): MutableSceneTransitionLayoutState {
+ return rule.runOnUiThread { MutableSceneTransitionLayoutState(initialScene, transitions) }
+ }
/** The content under test. */
@Composable
@@ -455,7 +457,7 @@
@Test
fun swipeEnabledLater() {
- val layoutState = MutableSceneTransitionLayoutState(SceneA)
+ val layoutState = layoutState()
var swipesEnabled by mutableStateOf(false)
var touchSlop = 0f
rule.setContent {
@@ -489,7 +491,7 @@
fun transitionKey() {
val transitionkey = TransitionKey(debugName = "foo")
val state =
- MutableSceneTransitionLayoutStateImpl(
+ layoutState(
SceneA,
transitions {
from(SceneA, to = SceneB) { fade(TestElements.Foo) }
@@ -553,7 +555,7 @@
}
val state =
- MutableSceneTransitionLayoutState(
+ layoutState(
SceneA,
transitions { from(SceneA, to = SceneB) { distance = swipeDistance } }
)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
index e555a01..7b99212 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
@@ -20,50 +20,48 @@
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TestElements
-import com.android.compose.animation.scene.testTransition
-import com.android.compose.test.assertSizeIsEqualTo
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.TransitionRecordingSpec
+import com.android.compose.animation.scene.featureOfElement
+import com.android.compose.animation.scene.recordTransition
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeFeatureCaptures
+import platform.test.motion.compose.createComposeMotionTestRule
+import platform.test.motion.testing.createGoldenPathManager
@RunWith(AndroidJUnit4::class)
class AnchoredSizeTest {
- @get:Rule val rule = createComposeRule()
+ private val goldenPaths =
+ createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
+
+ @get:Rule val motionRule = createComposeMotionTestRule(goldenPaths)
@Test
fun testAnchoredSizeEnter() {
- rule.testTransition(
+ assertBarSizeMatchesGolden(
fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
toSceneContent = {
Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
Box(Modifier.size(200.dp, 60.dp).element(TestElements.Bar))
},
transition = {
- // Scale during 4 frames.
spec = tween(16 * 4, easing = LinearEasing)
anchoredSize(TestElements.Bar, TestElements.Foo)
- },
- ) {
- // Bar is entering. It starts at the same size as Foo in scene A in and scales to its
- // final size in scene B.
- before { onElement(TestElements.Bar).assertDoesNotExist() }
- at(0) { onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp) }
- at(16) { onElement(TestElements.Bar).assertSizeIsEqualTo(125.dp, 90.dp) }
- at(32) { onElement(TestElements.Bar).assertSizeIsEqualTo(150.dp, 80.dp) }
- at(48) { onElement(TestElements.Bar).assertSizeIsEqualTo(175.dp, 70.dp) }
- at(64) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- after { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- }
+ }
+ )
}
@Test
fun testAnchoredSizeExit() {
- rule.testTransition(
+ assertBarSizeMatchesGolden(
fromSceneContent = {
Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo))
Box(Modifier.size(100.dp, 100.dp).element(TestElements.Bar))
@@ -73,22 +71,13 @@
// Scale during 4 frames.
spec = tween(16 * 4, easing = LinearEasing)
anchoredSize(TestElements.Bar, TestElements.Foo)
- },
- ) {
- // Bar is leaving. It starts at 100dp x 100dp in scene A and is scaled to 200dp x 60dp,
- // the size of Foo in scene B.
- before { onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp) }
- at(0) { onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp) }
- at(16) { onElement(TestElements.Bar).assertSizeIsEqualTo(125.dp, 90.dp) }
- at(32) { onElement(TestElements.Bar).assertSizeIsEqualTo(150.dp, 80.dp) }
- at(48) { onElement(TestElements.Bar).assertSizeIsEqualTo(175.dp, 70.dp) }
- after { onElement(TestElements.Bar).assertDoesNotExist() }
- }
+ }
+ )
}
@Test
fun testAnchoredWidthOnly() {
- rule.testTransition(
+ assertBarSizeMatchesGolden(
fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
toSceneContent = {
Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
@@ -98,20 +87,12 @@
spec = tween(16 * 4, easing = LinearEasing)
anchoredSize(TestElements.Bar, TestElements.Foo, anchorHeight = false)
},
- ) {
- before { onElement(TestElements.Bar).assertDoesNotExist() }
- at(0) { onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 60.dp) }
- at(16) { onElement(TestElements.Bar).assertSizeIsEqualTo(125.dp, 60.dp) }
- at(32) { onElement(TestElements.Bar).assertSizeIsEqualTo(150.dp, 60.dp) }
- at(48) { onElement(TestElements.Bar).assertSizeIsEqualTo(175.dp, 60.dp) }
- at(64) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- after { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- }
+ )
}
@Test
fun testAnchoredHeightOnly() {
- rule.testTransition(
+ assertBarSizeMatchesGolden(
fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
toSceneContent = {
Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
@@ -120,15 +101,23 @@
transition = {
spec = tween(16 * 4, easing = LinearEasing)
anchoredSize(TestElements.Bar, TestElements.Foo, anchorWidth = false)
- },
- ) {
- before { onElement(TestElements.Bar).assertDoesNotExist() }
- at(0) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 100.dp) }
- at(16) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 90.dp) }
- at(32) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 80.dp) }
- at(48) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 70.dp) }
- at(64) { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- after { onElement(TestElements.Bar).assertSizeIsEqualTo(200.dp, 60.dp) }
- }
+ }
+ )
+ }
+
+ private fun assertBarSizeMatchesGolden(
+ fromSceneContent: @Composable SceneScope.() -> Unit,
+ toSceneContent: @Composable SceneScope.() -> Unit,
+ transition: TransitionBuilder.() -> Unit,
+ ) {
+ val recordingSpec =
+ TransitionRecordingSpec(recordAfter = true) {
+ featureOfElement(TestElements.Bar, ComposeFeatureCaptures.dpSize)
+ }
+
+ val motion =
+ motionRule.recordTransition(fromSceneContent, toSceneContent, transition, recordingSpec)
+
+ motionRule.assertThat(motion).timeSeriesMatchesGolden()
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/SizeAssertions.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/SizeAssertions.kt
index fbd1b51..bca710f 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/SizeAssertions.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/SizeAssertions.kt
@@ -21,7 +21,11 @@
import androidx.compose.ui.test.assertWidthIsEqualTo
import androidx.compose.ui.unit.Dp
-fun SemanticsNodeInteraction.assertSizeIsEqualTo(expectedWidth: Dp, expectedHeight: Dp) {
+fun SemanticsNodeInteraction.assertSizeIsEqualTo(
+ expectedWidth: Dp,
+ expectedHeight: Dp = expectedWidth,
+): SemanticsNodeInteraction {
assertWidthIsEqualTo(expectedWidth)
assertHeightIsEqualTo(expectedHeight)
+ return this
}
diff --git a/packages/SystemUI/compose/scene/tests/utils/Android.bp b/packages/SystemUI/compose/scene/tests/utils/Android.bp
index 9089e6a..292efa0 100644
--- a/packages/SystemUI/compose/scene/tests/utils/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/utils/Android.bp
@@ -32,6 +32,7 @@
static_libs: [
"PlatformComposeSceneTransitionLayout",
+ "PlatformMotionTestingCompose",
"androidx.compose.runtime_runtime",
"androidx.compose.ui_ui-test-junit4",
],
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
index 2d71a6e..6724851 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
@@ -17,12 +17,24 @@
package com.android.compose.animation.scene
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import platform.test.motion.MotionTestRule
+import platform.test.motion.RecordedMotion
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.ComposeToolkit
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.feature
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.golden.FeatureCapture
+import platform.test.motion.golden.TimeSeriesCaptureScope
@DslMarker annotation class TransitionTestDsl
@@ -100,6 +112,66 @@
)
}
+data class TransitionRecordingSpec(
+ val recordBefore: Boolean = true,
+ val recordAfter: Boolean = true,
+ val timeSeriesCapture: TimeSeriesCaptureScope<SemanticsNodeInteractionsProvider>.() -> Unit
+)
+
+/** Captures the feature using [capture] on the [element]. */
+fun TimeSeriesCaptureScope<SemanticsNodeInteractionsProvider>.featureOfElement(
+ element: ElementKey,
+ capture: FeatureCapture<SemanticsNode, *>,
+ name: String = "${element.debugName}_${capture.name}"
+) {
+ feature(isElement(element), capture, name)
+}
+
+/** Records the transition between two scenes of [transitionLayout][SceneTransitionLayout]. */
+fun MotionTestRule<ComposeToolkit>.recordTransition(
+ fromSceneContent: @Composable SceneScope.() -> Unit,
+ toSceneContent: @Composable SceneScope.() -> Unit,
+ transition: TransitionBuilder.() -> Unit,
+ recordingSpec: TransitionRecordingSpec,
+ layoutModifier: Modifier = Modifier,
+ fromScene: SceneKey = TestScenes.SceneA,
+ toScene: SceneKey = TestScenes.SceneB,
+): RecordedMotion {
+ val state =
+ toolkit.composeContentTestRule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ fromScene,
+ transitions { from(fromScene, to = toScene, builder = transition) }
+ )
+ }
+
+ return recordMotion(
+ content = { play ->
+ LaunchedEffect(play) {
+ if (play) {
+ state.setTargetScene(toScene, coroutineScope = this)
+ }
+ }
+
+ SceneTransitionLayout(
+ state,
+ layoutModifier,
+ ) {
+ scene(fromScene, content = fromSceneContent)
+ scene(toScene, content = toSceneContent)
+ }
+ },
+ ComposeRecordingSpec(
+ MotionControl(delayRecording = { awaitCondition { state.isTransitioning() } }) {
+ awaitCondition { !state.isTransitioning() }
+ },
+ recordBefore = recordingSpec.recordBefore,
+ recordAfter = recordingSpec.recordAfter,
+ timeSeriesCapture = recordingSpec.timeSeriesCapture
+ )
+ )
+}
+
/**
* Test the transition between two scenes of [transitionLayout][SceneTransitionLayout] at different
* points in time.
diff --git a/packages/SystemUI/monet/Android.bp b/packages/SystemUI/monet/Android.bp
deleted file mode 100644
index c54fdab..0000000
--- a/packages/SystemUI/monet/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-package {
- default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
- name: "monet",
- platform_apis: true,
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.core_core",
- "libmonet",
- ],
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
deleted file mode 100644
index 624f18d..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.monet
-
-import android.annotation.ColorInt
-import android.app.WallpaperColors
-import android.graphics.Color
-import com.android.internal.graphics.ColorUtils
-import com.google.ux.material.libmonet.hct.Hct
-import com.google.ux.material.libmonet.scheme.DynamicScheme
-import com.google.ux.material.libmonet.scheme.SchemeContent
-import com.google.ux.material.libmonet.scheme.SchemeExpressive
-import com.google.ux.material.libmonet.scheme.SchemeFruitSalad
-import com.google.ux.material.libmonet.scheme.SchemeMonochrome
-import com.google.ux.material.libmonet.scheme.SchemeNeutral
-import com.google.ux.material.libmonet.scheme.SchemeRainbow
-import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
-import com.google.ux.material.libmonet.scheme.SchemeVibrant
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-const val TAG = "ColorScheme"
-
-const val ACCENT1_CHROMA = 48.0f
-const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
-const val MIN_CHROMA = 5
-
-enum class Style{
- SPRITZ,
- TONAL_SPOT,
- VIBRANT,
- EXPRESSIVE,
- RAINBOW,
- FRUIT_SALAD,
- CONTENT,
- MONOCHROMATIC,
- CLOCK,
- CLOCK_VIBRANT
-}
-
-class TonalPalette
-internal constructor(
- private val materialTonalPalette: com.google.ux.material.libmonet.palettes.TonalPalette
-) {
- @Deprecated("Do not use. For color system only")
- val allShades: List<Int>
- val allShadesMapped: Map<Int, Int>
-
- init{
- allShades = SHADE_KEYS.map {key -> getAtTone(key.toFloat()) }
- allShadesMapped = SHADE_KEYS.zip(allShades).toMap()
- }
-
- // Dynamically computed tones across the full range from 0 to 1000
- fun getAtTone(shade: Float): Int = materialTonalPalette.tone(((1000.0f - shade) / 10f).toInt())
-
- // Predefined & precomputed tones
- val s0: Int
- get() = this.allShades[0]
- val s10: Int
- get() = this.allShades[1]
- val s50: Int
- get() = this.allShades[2]
- val s100: Int
- get() = this.allShades[3]
- val s200: Int
- get() = this.allShades[4]
- val s300: Int
- get() = this.allShades[5]
- val s400: Int
- get() = this.allShades[6]
- val s500: Int
- get() = this.allShades[7]
- val s600: Int
- get() = this.allShades[8]
- val s700: Int
- get() = this.allShades[9]
- val s800: Int
- get() = this.allShades[10]
- val s900: Int
- get() = this.allShades[11]
- val s1000: Int
- get() = this.allShades[12]
-
- companion object {
- val SHADE_KEYS = listOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
- }
-}
-
-@Deprecated("Please use com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors " +
- "instead")
-class ColorScheme(
- @ColorInt val seed: Int,
- val isDark: Boolean,
- val style: Style,
- val contrastLevel: Double
-) {
- var materialScheme: DynamicScheme
-
- private val proposedSeedHct: Hct = Hct.fromInt(seed)
- private val seedHct: Hct = Hct.fromInt(if (seed == Color.TRANSPARENT) {
- GOOGLE_BLUE
- } else if (style != Style.CONTENT && proposedSeedHct.chroma < 5) {
- GOOGLE_BLUE
- } else {
- seed
- })
-
- val accent1: TonalPalette
- val accent2: TonalPalette
- val accent3: TonalPalette
- val neutral1: TonalPalette
- val neutral2: TonalPalette
-
- constructor(@ColorInt seed: Int, darkTheme: Boolean) : this(seed, darkTheme, Style.TONAL_SPOT)
-
- @JvmOverloads
- constructor(
- @ColorInt seed: Int,
- darkTheme: Boolean,
- style: Style
- ) : this(seed, darkTheme, style, 0.0)
-
- @JvmOverloads
- constructor(
- wallpaperColors: WallpaperColors,
- darkTheme: Boolean,
- style: Style = Style.TONAL_SPOT
- ) : this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style)
-
- val backgroundColor
- get() = ColorUtils.setAlphaComponent(if (isDark) neutral1.s700 else neutral1.s10, 0xFF)
-
- val accentColor
- get() = ColorUtils.setAlphaComponent(if (isDark) accent1.s100 else accent1.s500, 0xFF)
-
- init {
- materialScheme = when (style) {
- Style.SPRITZ -> SchemeNeutral(seedHct, isDark, contrastLevel)
- Style.TONAL_SPOT -> SchemeTonalSpot(seedHct, isDark, contrastLevel)
- Style.VIBRANT -> SchemeVibrant(seedHct, isDark, contrastLevel)
- Style.EXPRESSIVE -> SchemeExpressive(seedHct, isDark, contrastLevel)
- Style.RAINBOW -> SchemeRainbow(seedHct, isDark, contrastLevel)
- Style.FRUIT_SALAD -> SchemeFruitSalad(seedHct, isDark, contrastLevel)
- Style.CONTENT -> SchemeContent(seedHct, isDark, contrastLevel)
- Style.MONOCHROMATIC -> SchemeMonochrome(seedHct, isDark, contrastLevel)
-
- // SystemUI Schemes
- Style.CLOCK -> SchemeClock(seedHct, isDark, contrastLevel)
- Style.CLOCK_VIBRANT -> SchemeClockVibrant(seedHct, isDark, contrastLevel)
- }
-
- accent1 = TonalPalette(materialScheme.primaryPalette)
- accent2 = TonalPalette(materialScheme.secondaryPalette)
- accent3 = TonalPalette(materialScheme.tertiaryPalette)
- neutral1 = TonalPalette(materialScheme.neutralPalette)
- neutral2 = TonalPalette(materialScheme.neutralVariantPalette)
- }
-
- val seedTone: Float
- get() = 1000f - proposedSeedHct.tone.toFloat() * 10f
-
- override fun toString(): String {
- return "ColorScheme {\n" +
- " seed color: ${stringForColor(seed)}\n" +
- " style: $style\n" +
- " palettes: \n" +
- " ${humanReadable("PRIMARY", accent1.allShades)}\n" +
- " ${humanReadable("SECONDARY", accent2.allShades)}\n" +
- " ${humanReadable("TERTIARY", accent3.allShades)}\n" +
- " ${humanReadable("NEUTRAL", neutral1.allShades)}\n" +
- " ${humanReadable("NEUTRAL VARIANT", neutral2.allShades)}\n" +
- "}"
- }
-
- companion object {
- /**
- * Identifies a color to create a color scheme from.
- *
- * @param wallpaperColors Colors extracted from an image via quantization.
- * @param filter If false, allow colors that have low chroma, creating grayscale themes.
- * @return ARGB int representing the color
- */
- @JvmStatic
- @JvmOverloads
- @ColorInt
- fun getSeedColor(wallpaperColors: WallpaperColors, filter: Boolean = true): Int {
- return getSeedColors(wallpaperColors, filter).first()
- }
-
- /**
- * Filters and ranks colors from WallpaperColors.
- *
- * @param wallpaperColors Colors extracted from an image via quantization.
- * @param filter If false, allow colors that have low chroma, creating grayscale themes.
- * @return List of ARGB ints, ordered from highest scoring to lowest.
- */
- @JvmStatic
- @JvmOverloads
- fun getSeedColors(wallpaperColors: WallpaperColors, filter: Boolean = true): List<Int> {
- val totalPopulation =
- wallpaperColors.allColors.values.reduce { a, b -> a + b }.toDouble()
- val totalPopulationMeaningless = (totalPopulation == 0.0)
- if (totalPopulationMeaningless) {
- // WallpaperColors with a population of 0 indicate the colors didn't come from
- // quantization. Instead of scoring, trust the ordering of the provided primary
- // secondary/tertiary colors.
- //
- // In this case, the colors are usually from a Live Wallpaper.
- val distinctColors =
- wallpaperColors.mainColors
- .map { it.toArgb() }
- .distinct()
- .filter {
- if (!filter) {
- true
- } else {
- Hct.fromInt(it).chroma >= MIN_CHROMA
- }
- }
- .toList()
- if (distinctColors.isEmpty()) {
- return listOf(GOOGLE_BLUE)
- }
- return distinctColors
- }
-
- val intToProportion =
- wallpaperColors.allColors.mapValues { it.value.toDouble() / totalPopulation }
- val intToHct = wallpaperColors.allColors.mapValues { Hct.fromInt(it.key) }
-
- // Get an array with 360 slots. A slot contains the percentage of colors with that hue.
- val hueProportions = huePopulations(intToHct, intToProportion, filter)
- // Map each color to the percentage of the image with its hue.
- val intToHueProportion =
- wallpaperColors.allColors.mapValues {
- val hct = intToHct[it.key]!!
- val hue = hct.hue.roundToInt()
- var proportion = 0.0
- for (i in hue - 15..hue + 15) {
- proportion += hueProportions[wrapDegrees(i)]
- }
- proportion
- }
- // Remove any inappropriate seed colors. For example, low chroma colors look grayscale
- // raising their chroma will turn them to a much louder color that may not have been
- // in the image.
- val filteredIntToHct =
- if (!filter) intToHct
- else
- (intToHct.filter {
- val hct = it.value
- val proportion = intToHueProportion[it.key]!!
- hct.chroma >= MIN_CHROMA &&
- (totalPopulationMeaningless || proportion > 0.01)
- })
- // Sort the colors by score, from high to low.
- val intToScoreIntermediate =
- filteredIntToHct.mapValues { score(it.value, intToHueProportion[it.key]!!) }
- val intToScore = intToScoreIntermediate.entries.toMutableList()
- intToScore.sortByDescending { it.value }
-
- // Go through the colors, from high score to low score.
- // If the color is distinct in hue from colors picked so far, pick the color.
- // Iteratively decrease the amount of hue distinctness required, thus ensuring we
- // maximize difference between colors.
- val minimumHueDistance = 15
- val seeds = mutableListOf<Int>()
- maximizeHueDistance@ for (i in 90 downTo minimumHueDistance step 1) {
- seeds.clear()
- for (entry in intToScore) {
- val int = entry.key
- val existingSeedNearby =
- seeds.find {
- val hueA = intToHct[int]!!.hue
- val hueB = intToHct[it]!!.hue
- hueDiff(hueA, hueB) < i
- } != null
- if (existingSeedNearby) {
- continue
- }
- seeds.add(int)
- if (seeds.size >= 4) {
- break@maximizeHueDistance
- }
- }
- }
-
- if (seeds.isEmpty()) {
- // Use gBlue 500 if there are 0 colors
- seeds.add(GOOGLE_BLUE)
- }
-
- return seeds
- }
-
- private fun wrapDegrees(degrees: Int): Int {
- return when {
- degrees < 0 -> {
- (degrees % 360) + 360
- }
- degrees >= 360 -> {
- degrees % 360
- }
- else -> {
- degrees
- }
- }
- }
-
- private fun hueDiff(a: Double, b: Double): Double {
- return 180f - ((a - b).absoluteValue - 180f).absoluteValue
- }
-
- private fun stringForColor(color: Int): String {
- val width = 4
- val hct = Hct.fromInt(color)
- val h = "H${hct.hue.roundToInt().toString().padEnd(width)}"
- val c = "C${hct.chroma.roundToInt().toString().padEnd(width)}"
- val t = "T${hct.tone.roundToInt().toString().padEnd(width)}"
- val hex = Integer.toHexString(color and 0xffffff).padStart(6, '0').uppercase()
- return "$h$c$t = #$hex"
- }
-
- private fun humanReadable(paletteName: String, colors: List<Int>): String {
- return "$paletteName\n" +
- colors.map { stringForColor(it) }.joinToString(separator = "\n") { it }
- }
-
- private fun score(hct: Hct, proportion: Double): Double {
- val proportionScore = 0.7 * 100.0 * proportion
- val chromaScore =
- if (hct.chroma < ACCENT1_CHROMA) 0.1 * (hct.chroma - ACCENT1_CHROMA)
- else 0.3 * (hct.chroma - ACCENT1_CHROMA)
- return chromaScore + proportionScore
- }
-
- private fun huePopulations(
- hctByColor: Map<Int, Hct>,
- populationByColor: Map<Int, Double>,
- filter: Boolean = true
- ): List<Double> {
- val huePopulation = List(size = 360, init = { 0.0 }).toMutableList()
-
- for (entry in populationByColor.entries) {
- val population = populationByColor[entry.key]!!
- val hct = hctByColor[entry.key]!!
- val hue = hct.hue.roundToInt() % 360
- if (filter && hct.chroma <= MIN_CHROMA) {
- continue
- }
- huePopulation[hue] = huePopulation[hue] + population
- }
-
- return huePopulation
- }
- }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java b/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java
deleted file mode 100644
index 4747cc5..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java
+++ /dev/null
@@ -1,55 +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.monet;
-
-import static com.google.ux.material.libmonet.utils.MathUtils.clampDouble;
-
-import static java.lang.Double.max;
-
-import com.google.ux.material.libmonet.hct.Hct;
-import com.google.ux.material.libmonet.palettes.TonalPalette;
-import com.google.ux.material.libmonet.scheme.DynamicScheme;
-import com.google.ux.material.libmonet.scheme.Variant;
-
-public class SchemeClock extends DynamicScheme {
- public SchemeClock(Hct sourceColorHct, boolean isDark, double contrastLevel) {
- super(
- sourceColorHct,
- Variant.MONOCHROME,
- isDark,
- contrastLevel,
- /*primary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue(),
- /*chroma*/ max(sourceColorHct.getChroma(), 20)
- ),
- /*secondary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue() + 10.0,
- /*chroma*/ clampDouble(17, 40, sourceColorHct.getChroma() * 0.85)
- ),
- /*tertiary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue() + 20.0,
- /*chroma*/ max(sourceColorHct.getChroma() + 20, 50)
- ),
-
- //not used
- TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0),
- TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0));
- }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java b/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java
deleted file mode 100644
index fb5e972..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java
+++ /dev/null
@@ -1,53 +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.monet;
-
-import static java.lang.Double.max;
-
-import com.google.ux.material.libmonet.hct.Hct;
-import com.google.ux.material.libmonet.palettes.TonalPalette;
-import com.google.ux.material.libmonet.scheme.DynamicScheme;
-import com.google.ux.material.libmonet.scheme.Variant;
-
-public class SchemeClockVibrant extends DynamicScheme {
- public SchemeClockVibrant(Hct sourceColorHct, boolean isDark, double contrastLevel) {
- super(
- sourceColorHct,
- Variant.MONOCHROME,
- isDark,
- contrastLevel,
- /*primary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue(),
- /*chroma*/ max(sourceColorHct.getChroma(), 70)
- ),
- /*secondary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue() + 20.0,
- /*chroma*/ max(sourceColorHct.getChroma(), 70)
- ),
- /*tertiary*/
- TonalPalette.fromHueAndChroma(
- /*hue*/ sourceColorHct.getHue() + 60.0,
- /*chroma*/ max(sourceColorHct.getChroma(), 70)
- ),
-
- //not used
- TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0),
- TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0));
- }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
deleted file mode 100644
index c8b9fe0..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.monet;
-
-
-import androidx.annotation.ColorInt;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.ColorUtils;
-
-/**
- * Generate sets of colors that are shades of the same color
- */
-@VisibleForTesting
-public class Shades {
- /**
- * Combining the ability to convert between relative luminance and perceptual luminance with
- * contrast leads to a design system that can be based on a linear value to determine contrast,
- * rather than a ratio.
- *
- * This codebase implements a design system that has that property, and as a result, we can
- * guarantee that any shades 5 steps from each other have a contrast ratio of at least 4.5.
- * 4.5 is the requirement for smaller text contrast in WCAG 2.1 and earlier.
- *
- * However, lstar 50 does _not_ have a contrast ratio >= 4.5 with lstar 100.
- * lstar 49.6 is the smallest lstar that will lead to a contrast ratio >= 4.5 with lstar 100,
- * and it also contrasts >= 4.5 with lstar 100.
- */
- public static final float MIDDLE_LSTAR = 49.6f;
-
- /**
- * Generate shades of a color. Ordered in lightness _descending_.
- * <p>
- * The first shade will be at 95% lightness, the next at 90, 80, etc. through 0.
- *
- * @param hue hue in CAM16 color space
- * @param chroma chroma in CAM16 color space
- * @return shades of a color, as argb integers. Ordered by lightness descending.
- */
- public static @ColorInt int[] of(float hue, float chroma) {
- int[] shades = new int[12];
- // At tone 90 and above, blue and yellow hues can reach a much higher chroma.
- // To preserve a consistent appearance across all hues, use a maximum chroma of 40.
- shades[0] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 99);
- shades[1] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 95);
- for (int i = 2; i < 12; i++) {
- float lStar = (i == 6) ? MIDDLE_LSTAR : 100 - 10 * (i - 1);
- shades[i] = ColorUtils.CAMToColor(hue, chroma, lStar);
- }
- return shades;
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
index ca824cb..5757f67 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
@@ -42,7 +42,6 @@
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
@@ -90,11 +89,6 @@
locationController,
)
- @Before
- fun setup() {
- enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
- }
-
@Test
fun nightDisplayState_matchesAutoMode() =
scope.runTest {
@@ -126,6 +120,8 @@
@Test
fun nightDisplayState_matchesIsNightDisplayActivated() =
scope.runTest {
+ enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
+
val callbackCaptor = argumentCaptor<NightDisplayListener.Callback>()
val lastState by collectLastValue(underTest.nightDisplayState(testUser))
@@ -148,6 +144,7 @@
scope.runTest {
whenever(colorDisplayManager.nightDisplayAutoMode)
.thenReturn(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME)
+ enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
val lastState by collectLastValue(underTest.nightDisplayState(testUser))
runCurrent()
@@ -160,6 +157,7 @@
scope.runTest {
whenever(colorDisplayManager.nightDisplayAutoMode)
.thenReturn(ColorDisplayManager.AUTO_MODE_TWILIGHT)
+ enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
val lastState by collectLastValue(underTest.nightDisplayState(testUser))
runCurrent()
@@ -167,6 +165,24 @@
assertThat(lastState!!.autoMode).isEqualTo(ColorDisplayManager.AUTO_MODE_TWILIGHT)
}
+ /**
+ * When the value of the raw auto mode is missing the call to nightDisplayState should not crash
+ */
+ @Test
+ fun nightDisplayState_whenAutoModeSettingIsNotInitialized_loadsDataWithoutException() =
+ scope.runTest {
+ // only auto mode_available is set, and the raw auto_mode has nothing set
+ globalSettings.putString(
+ Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
+ NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE
+ )
+
+ val lastState by collectLastValue(underTest.nightDisplayState(testUser))
+ runCurrent()
+
+ assertThat(lastState!!.shouldForceAutoMode).isTrue()
+ }
+
@Test
fun nightDisplayState_matchesForceAutoMode() =
scope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index 325a324..89c5495 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -195,6 +195,7 @@
}
@EnableFlags(FLAG_COMMUNAL_HUB)
+ @DisableFlags(FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT)
@Test
fun hubShowsKeyguardWidgetsByDefault() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt
deleted file mode 100644
index 1e7ed63..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/FingerprintPropertyRepositoryTest.kt
+++ /dev/null
@@ -1,103 +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.keyguard.data.repository
-
-import android.hardware.fingerprint.FingerprintManager
-import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
-import com.android.systemui.coroutines.collectLastValue
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.Dispatchers
-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.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-
-@ExperimentalCoroutinesApi
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class FingerprintPropertyRepositoryTest : SysuiTestCase() {
- @JvmField @Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
- private val testScope = TestScope()
- private lateinit var underTest: FingerprintPropertyRepositoryImpl
- @Mock private lateinit var fingerprintManager: FingerprintManager
- @Captor
- private lateinit var fingerprintCallbackCaptor:
- ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
-
- @Before
- fun setup() {
- underTest =
- FingerprintPropertyRepositoryImpl(
- testScope.backgroundScope,
- Dispatchers.Main.immediate,
- fingerprintManager,
- )
- }
-
- @Test
- fun propertiesInitialized_onStartFalse() =
- testScope.runTest {
- val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
- assertThat(propertiesInitialized).isFalse()
- }
-
- @Test
- fun propertiesInitialized_onStartTrue() =
- testScope.runTest {
- // // collect sensorType to update fingerprintCallback before
- // propertiesInitialized
- // // is listened for
- val sensorType by collectLastValue(underTest.sensorType)
- runCurrent()
- captureFingerprintCallback()
-
- fingerprintCallbackCaptor.value.onAllAuthenticatorsRegistered(emptyList())
- val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
- assertThat(propertiesInitialized).isTrue()
- }
-
- @Test
- fun propertiesInitialized_updatedToTrue() =
- testScope.runTest {
- val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
- assertThat(propertiesInitialized).isFalse()
-
- captureFingerprintCallback()
- fingerprintCallbackCaptor.value.onAllAuthenticatorsRegistered(emptyList())
- assertThat(propertiesInitialized).isTrue()
- }
-
- private fun captureFingerprintCallback() {
- verify(fingerprintManager)
- .addAuthenticatorsRegisteredCallback(fingerprintCallbackCaptor.capture())
- }
-}
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 99cccb2..5756bca 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
@@ -40,7 +40,10 @@
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -527,7 +530,13 @@
@DisableSceneContainer
fun isInTransitionToState() =
testScope.runTest {
- val results by collectValues(underTest.isInTransitionToState(GONE))
+ val results by
+ collectValues(
+ underTest.isInTransition(
+ edge = Edge.create(OFF, OFF),
+ edgeWithoutSceneContainer = Edge.create(to = LOCKSCREEN)
+ )
+ )
sendSteps(
TransitionStep(AOD, DOZING, 0f, STARTED),
@@ -543,7 +552,7 @@
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, STARTED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
)
assertThat(results)
@@ -555,7 +564,7 @@
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, RUNNING),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
)
assertThat(results)
@@ -567,7 +576,7 @@
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, FINISHED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, FINISHED),
)
assertThat(results)
@@ -580,9 +589,9 @@
)
sendSteps(
- TransitionStep(GONE, DOZING, 0f, STARTED),
- TransitionStep(GONE, DOZING, 0f, RUNNING),
- TransitionStep(GONE, DOZING, 1f, FINISHED),
+ TransitionStep(LOCKSCREEN, DOZING, 0f, STARTED),
+ TransitionStep(LOCKSCREEN, DOZING, 0f, RUNNING),
+ TransitionStep(LOCKSCREEN, DOZING, 1f, FINISHED),
)
assertThat(results)
@@ -595,8 +604,8 @@
)
sendSteps(
- TransitionStep(DOZING, GONE, 0f, STARTED),
- TransitionStep(DOZING, GONE, 0f, RUNNING),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED),
+ TransitionStep(DOZING, LOCKSCREEN, 0f, RUNNING),
)
assertThat(results)
@@ -611,9 +620,96 @@
}
@Test
+ @EnableSceneContainer
+ fun isInTransitionFromScene() =
+ testScope.runTest {
+ val results by
+ collectValues(underTest.isInTransition(edge = Edge.create(Scenes.Lockscreen, null)))
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+
+ assertThat(results)
+ .isEqualTo(
+ listOf(
+ false,
+ )
+ )
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Shade))
+
+ assertThat(results)
+ .isEqualTo(
+ listOf(
+ false,
+ true,
+ )
+ )
+
+ kosmos.setSceneTransition(Idle(Scenes.Shade))
+
+ assertThat(results)
+ .isEqualTo(
+ listOf(
+ false,
+ true,
+ false,
+ )
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun isInTransitionToScene() =
+ testScope.runTest {
+ val results by
+ collectValues(underTest.isInTransition(edge = Edge.create(null, Scenes.Lockscreen)))
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+ kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
+
+ assertThat(results)
+ .isEqualTo(
+ listOf(
+ false,
+ true,
+ false,
+ )
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun isInTransitionStateToScene() =
+ testScope.runTest {
+ val results by
+ collectValues(underTest.isInTransition(edge = Edge.create(AOD, Scenes.Gone)))
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
+
+ sendSteps(
+ TransitionStep(AOD, UNDEFINED, 0f, STARTED),
+ TransitionStep(AOD, UNDEFINED, 0.5f, RUNNING),
+ TransitionStep(AOD, UNDEFINED, 1f, FINISHED),
+ )
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+ assertThat(results)
+ .isEqualTo(
+ listOf(
+ false,
+ true,
+ false,
+ )
+ )
+ }
+
+ @Test
fun isInTransitionFromState() =
testScope.runTest {
- val results by collectValues(underTest.isInTransitionFromState(DOZING))
+ val results by collectValues(underTest.isInTransition(Edge.create(from = DOZING)))
sendSteps(
TransitionStep(AOD, DOZING, 0f, STARTED),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
index d33c10e..be0d899 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt
@@ -23,12 +23,18 @@
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -67,6 +73,7 @@
}
@Test
+ @DisableSceneContainer
fun alpha_WhenNotGone_clockMigrationFlagIsOff_emitsKeyguardAlpha() =
testScope.runTest {
mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@@ -86,6 +93,7 @@
}
@Test
+ @DisableSceneContainer
fun alpha_WhenGoneToAod() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
@@ -110,6 +118,35 @@
}
@Test
+ @EnableSceneContainer
+ fun alpha_WhenGoneToAod_scene_container() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Lockscreen, to = Scenes.Gone))
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.UNDEFINED,
+ testScope = testScope,
+ )
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+ assertThat(alpha).isEqualTo(0f)
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.UNDEFINED,
+ to = KeyguardState.AOD,
+ testScope = testScope,
+ )
+ enterFromTopAnimationAlpha.value = 0.5f
+ assertThat(alpha).isEqualTo(0.5f)
+
+ enterFromTopAnimationAlpha.value = 1f
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
+ @DisableSceneContainer
fun alpha_WhenGoneToDozing() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
@@ -130,6 +167,25 @@
}
@Test
+ @EnableSceneContainer
+ fun alpha_WhenGoneToDozing_scene_container() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+ assertThat(alpha).isEqualTo(0f)
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.UNDEFINED,
+ to = KeyguardState.DOZING,
+ testScope = testScope,
+ )
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
+ @DisableSceneContainer
fun alpha_whenGone_equalsZero() =
testScope.runTest {
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@@ -166,6 +222,7 @@
}
@Test
+ @DisableSceneContainer
fun enterFromTopAlpha() =
testScope.runTest {
val alpha by collectLastValue(underTest.alpha)
@@ -184,4 +241,26 @@
enterFromTopAnimationAlpha.value = 1f
assertThat(alpha).isEqualTo(1f)
}
+
+ @Test
+ @EnableSceneContainer
+ fun enterFromTopAlpha_scene_container() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha)
+
+ kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.UNDEFINED,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+
+ enterFromTopAnimationAlpha.value = 0.2f
+ assertThat(alpha).isEqualTo(0.2f)
+
+ enterFromTopAnimationAlpha.value = 1f
+ assertThat(alpha).isEqualTo(1f)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
similarity index 62%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
index f61ddeb..68fbd1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -20,9 +20,15 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.accessibility.data.repository.fakeAccessibilityRepository
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
@@ -30,14 +36,16 @@
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel.Companion.UNLOCKED_DELAY_MS
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.Test
import org.junit.runner.RunWith
@ExperimentalCoroutinesApi
@@ -65,9 +73,10 @@
fun isLongPressEnabled_udfpsRunning() =
testScope.runTest {
val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
- fingerprintPropertyRepository.supportsUdfps()
- fingerprintAuthRepository.setIsRunning(true)
- keyguardRepository.setKeyguardDismissible(false)
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ )
assertThat(isLongPressEnabled).isFalse()
}
@@ -75,10 +84,10 @@
fun isLongPressEnabled_unlocked() =
testScope.runTest {
val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
- fingerprintPropertyRepository.supportsUdfps()
- keyguardRepository.setKeyguardDismissible(true)
- advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
- runCurrent()
+ setUpState(
+ isUdfpsSupported = true,
+ isLockscreenDismissible = true,
+ )
assertThat(isLongPressEnabled).isTrue()
}
@@ -86,10 +95,9 @@
fun isLongPressEnabled_lock() =
testScope.runTest {
val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
- keyguardRepository.setKeyguardDismissible(false)
+ setUpState(isUdfpsSupported = true)
// udfps supported
- fingerprintPropertyRepository.supportsUdfps()
assertThat(isLongPressEnabled).isTrue()
// udfps isn't supported
@@ -112,42 +120,90 @@
}
@Test
+ @DisableSceneContainer
fun iconType_fingerprint() =
testScope.runTest {
val iconType by collectLastValue(underTest.iconType)
- keyguardRepository.setKeyguardDismissible(false)
- fingerprintPropertyRepository.supportsUdfps()
- fingerprintAuthRepository.setIsRunning(true)
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ )
assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.FINGERPRINT)
}
@Test
+ @DisableSceneContainer
fun iconType_locked() =
testScope.runTest {
val iconType by collectLastValue(underTest.iconType)
- keyguardRepository.setKeyguardDismissible(false)
- fingerprintAuthRepository.setIsRunning(false)
+ setUpState()
assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.LOCK)
}
@Test
+ @DisableSceneContainer
fun iconType_unlocked() =
testScope.runTest {
val iconType by collectLastValue(underTest.iconType)
- keyguardRepository.setKeyguardDismissible(true)
- advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
- fingerprintAuthRepository.setIsRunning(false)
+ setUpState(isLockscreenDismissible = true)
assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.UNLOCK)
}
@Test
+ @DisableSceneContainer
fun iconType_none() =
testScope.runTest {
val iconType by collectLastValue(underTest.iconType)
- keyguardRepository.setKeyguardDismissible(true)
- advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
- fingerprintPropertyRepository.supportsUdfps()
- fingerprintAuthRepository.setIsRunning(true)
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ isLockscreenDismissible = true,
+ )
+ assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.NONE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun iconType_fingerprint_withSceneContainer() =
+ testScope.runTest {
+ val iconType by collectLastValue(underTest.iconType)
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ )
+ assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.FINGERPRINT)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun iconType_locked_withSceneContainer() =
+ testScope.runTest {
+ val iconType by collectLastValue(underTest.iconType)
+ setUpState()
+ assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.LOCK)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun iconType_unlocked_withSceneContainer() =
+ testScope.runTest {
+ val iconType by collectLastValue(underTest.iconType)
+ setUpState(
+ isLockscreenDismissible = true,
+ )
+ assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.UNLOCK)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun iconType_none_withSceneContainer() =
+ testScope.runTest {
+ val iconType by collectLastValue(underTest.iconType)
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ isLockscreenDismissible = true,
+ )
assertThat(iconType).isEqualTo(DeviceEntryIconView.IconType.NONE)
}
@@ -166,14 +222,12 @@
kosmos.fakeAccessibilityRepository.isEnabled.value = true
// interactive lock icon
- keyguardRepository.setKeyguardDismissible(false)
- fingerprintPropertyRepository.supportsUdfps()
+ setUpState(isUdfpsSupported = true)
assertThat(accessibilityDelegateHint)
.isEqualTo(DeviceEntryIconView.AccessibilityHintType.AUTHENTICATE)
// non-interactive lock icon
- keyguardRepository.setKeyguardDismissible(false)
fingerprintPropertyRepository.supportsRearFps()
assertThat(accessibilityDelegateHint)
@@ -187,10 +241,10 @@
kosmos.fakeAccessibilityRepository.isEnabled.value = true
// interactive unlock icon
- keyguardRepository.setKeyguardDismissible(true)
- fingerprintPropertyRepository.supportsUdfps()
- advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
- runCurrent()
+ setUpState(
+ isUdfpsSupported = true,
+ isLockscreenDismissible = true,
+ )
assertThat(accessibilityDelegateHint)
.isEqualTo(DeviceEntryIconView.AccessibilityHintType.ENTER)
@@ -199,4 +253,45 @@
private fun deviceEntryIconTransitionAlpha(alpha: Float) {
deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha)
}
+
+ private suspend fun TestScope.setUpState(
+ isUdfpsSupported: Boolean = false,
+ isUdfpsRunning: Boolean = false,
+ isLockscreenDismissible: Boolean = false,
+ ) {
+ if (isUdfpsSupported) {
+ fingerprintPropertyRepository.supportsUdfps()
+ }
+ if (isUdfpsRunning) {
+ check(isUdfpsSupported) { "Cannot set UDFPS as running if it's not supported!" }
+ fingerprintAuthRepository.setIsRunning(true)
+ } else {
+ fingerprintAuthRepository.setIsRunning(false)
+ }
+ if (isLockscreenDismissible) {
+ setLockscreenDismissible()
+ } else {
+ if (!SceneContainerFlag.isEnabled) {
+ keyguardRepository.setKeyguardDismissible(false)
+ }
+ }
+ runCurrent()
+ }
+
+ private suspend fun TestScope.setLockscreenDismissible() {
+ if (SceneContainerFlag.isEnabled) {
+ // Need to set up a collection for the authentication to be propagated.
+ val unused by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+ runCurrent()
+ assertThat(
+ kosmos.authenticationInteractor.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN
+ )
+ )
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
+ } else {
+ keyguardRepository.setKeyguardDismissible(true)
+ }
+ advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
index 365a7c3..856c3fe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
@@ -195,6 +195,7 @@
eq(PACKAGE_NAME),
eq(true),
eq(dialogTransitionController),
+ eq(null),
eq(null)
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractorTest.kt
index 954f691..28f2a43 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractorTest.kt
@@ -25,11 +25,8 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
-import com.android.systemui.qs.tiles.impl.screenrecord.domain.model.ScreenRecordTileModel
-import com.android.systemui.screenrecord.RecordingController
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
@@ -37,7 +34,6 @@
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.verify
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -46,13 +42,13 @@
class ScreenRecordTileDataInteractorTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val testScope = kosmos.testScope
- private val controller = mock<RecordingController>()
+ private val screenRecordRepo = kosmos.screenRecordRepository
private val underTest: ScreenRecordTileDataInteractor =
- ScreenRecordTileDataInteractor(testScope.testScheduler, controller)
+ ScreenRecordTileDataInteractor(screenRecordRepo)
- private val isRecording = ScreenRecordTileModel.Recording
- private val isDoingNothing = ScreenRecordTileModel.DoingNothing
- private val isStarting0 = ScreenRecordTileModel.Starting(0)
+ private val isRecording = ScreenRecordModel.Recording
+ private val isDoingNothing = ScreenRecordModel.DoingNothing
+ private val isStarting0 = ScreenRecordModel.Starting(0)
@Test
fun isAvailable_returnsTrue() = runTest {
@@ -62,85 +58,31 @@
}
@Test
- fun dataMatchesController() =
+ fun dataMatchesRepo() =
testScope.runTest {
- whenever(controller.isRecording).thenReturn(false)
- whenever(controller.isStarting).thenReturn(false)
-
- val callbackCaptor = argumentCaptor<RecordingController.RecordingStateChangeCallback>()
-
val lastModel by
collectLastValue(
underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
)
runCurrent()
- verify(controller).addCallback(callbackCaptor.capture())
- val callback = callbackCaptor.value
-
assertThat(lastModel).isEqualTo(isDoingNothing)
- val expectedModelStartingIn1 = ScreenRecordTileModel.Starting(1)
- callback.onCountdown(1)
+ val expectedModelStartingIn1 = ScreenRecordModel.Starting(1)
+ screenRecordRepo.screenRecordState.value = expectedModelStartingIn1
assertThat(lastModel).isEqualTo(expectedModelStartingIn1)
- val expectedModelStartingIn0 = isStarting0
- callback.onCountdown(0)
- assertThat(lastModel).isEqualTo(expectedModelStartingIn0)
-
- callback.onCountdownEnd()
- assertThat(lastModel).isEqualTo(isDoingNothing)
-
- callback.onRecordingStart()
- assertThat(lastModel).isEqualTo(isRecording)
-
- callback.onRecordingEnd()
- assertThat(lastModel).isEqualTo(isDoingNothing)
- }
-
- @Test
- fun data_whenRecording_matchesController() =
- testScope.runTest {
- whenever(controller.isRecording).thenReturn(true)
- whenever(controller.isStarting).thenReturn(false)
-
- val lastModel by
- collectLastValue(
- underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
- )
- runCurrent()
-
- assertThat(lastModel).isEqualTo(isRecording)
- }
-
- @Test
- fun data_whenStarting_matchesController() =
- testScope.runTest {
- whenever(controller.isRecording).thenReturn(false)
- whenever(controller.isStarting).thenReturn(true)
-
- val lastModel by
- collectLastValue(
- underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
- )
- runCurrent()
-
+ screenRecordRepo.screenRecordState.value = isStarting0
assertThat(lastModel).isEqualTo(isStarting0)
- }
- @Test
- fun data_whenRecordingAndStarting_matchesControllerRecording() =
- testScope.runTest {
- whenever(controller.isRecording).thenReturn(true)
- whenever(controller.isStarting).thenReturn(true)
+ screenRecordRepo.screenRecordState.value = isDoingNothing
+ assertThat(lastModel).isEqualTo(isDoingNothing)
- val lastModel by
- collectLastValue(
- underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
- )
- runCurrent()
-
+ screenRecordRepo.screenRecordState.value = isRecording
assertThat(lastModel).isEqualTo(isRecording)
+
+ screenRecordRepo.screenRecordState.value = isDoingNothing
+ assertThat(lastModel).isEqualTo(isDoingNothing)
}
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
index 91f4ea8..e87c8ad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
@@ -33,8 +33,8 @@
import com.android.systemui.plugins.activityStarter
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
-import com.android.systemui.qs.tiles.impl.screenrecord.domain.model.ScreenRecordTileModel
import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -89,7 +89,7 @@
@Test
fun handleClick_whenStarting_cancelCountdown() = runTest {
- val startingModel = ScreenRecordTileModel.Starting(0)
+ val startingModel = ScreenRecordModel.Starting(0)
underTest.handleInput(QSTileInputTestKtx.click(startingModel))
@@ -98,7 +98,7 @@
@Test
fun handleClick_whenRecording_stopRecording() = runTest {
- val recordingModel = ScreenRecordTileModel.Recording
+ val recordingModel = ScreenRecordModel.Recording
underTest.handleInput(QSTileInputTestKtx.click(recordingModel))
@@ -107,7 +107,7 @@
@Test
fun handleClick_whenDoingNothing_createDialogDismissPanelShowDialog() = runTest {
- val recordingModel = ScreenRecordTileModel.DoingNothing
+ val recordingModel = ScreenRecordModel.DoingNothing
underTest.handleInput(QSTileInputTestKtx.click(recordingModel))
val onStartRecordingClickedCaptor = argumentCaptor<Runnable>()
@@ -143,7 +143,7 @@
kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
- val recordingModel = ScreenRecordTileModel.DoingNothing
+ val recordingModel = ScreenRecordModel.DoingNothing
underTest.handleInput(
QSTileInputTestKtx.click(recordingModel, UserHandle.CURRENT, expandable)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt
index d7b7ab6..31ae9c5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt
@@ -25,11 +25,11 @@
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.screenrecord.domain.model.ScreenRecordTileModel
import com.android.systemui.qs.tiles.impl.screenrecord.domain.ui.ScreenRecordTileMapper
import com.android.systemui.qs.tiles.impl.screenrecord.qsScreenRecordTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,7 +58,7 @@
@Test
fun activeStateMatchesRecordingDataModel() {
- val inputModel = ScreenRecordTileModel.Recording
+ val inputModel = ScreenRecordModel.Recording
val outputState = mapper.map(config, inputModel)
@@ -74,7 +74,7 @@
@Test
fun activeStateMatchesStartingDataModel() {
val timeLeft = 0L
- val inputModel = ScreenRecordTileModel.Starting(timeLeft)
+ val inputModel = ScreenRecordModel.Starting(timeLeft)
val outputState = mapper.map(config, inputModel)
@@ -89,7 +89,7 @@
@Test
fun inactiveStateMatchesDisabledDataModel() {
- val inputModel = ScreenRecordTileModel.DoingNothing
+ val inputModel = ScreenRecordModel.DoingNothing
val outputState = mapper.map(config, inputModel)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
index c660ff3..afe7b8f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
@@ -257,7 +257,7 @@
runCurrent()
clearInvocations(qsImpl!!)
- underTest.setState(QSSceneAdapter.State.UnsquishingQQS(squishiness))
+ underTest.setState(QSSceneAdapter.State.UnsquishingQQS { squishiness })
with(qsImpl!!) {
verify(this).setQsVisible(true)
verify(this)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
index ebd65fd..63ce67c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
@@ -32,7 +32,7 @@
@Test
fun expanding_squishiness1() {
- assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness).isEqualTo(1f)
+ assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness()).isEqualTo(1f)
}
@Test
@@ -51,14 +51,14 @@
@Test
fun unsquishingQQS_expansionSameAsQQS() {
val squishiness = 0.6f
- assertThat(QSSceneAdapter.State.UnsquishingQQS(squishiness).expansion)
+ assertThat(QSSceneAdapter.State.UnsquishingQQS { squishiness }.expansion)
.isEqualTo(QSSceneAdapter.State.QQS.expansion)
}
@Test
fun unsquishingQS_expansionSameAsQS() {
val squishiness = 0.6f
- assertThat(QSSceneAdapter.State.UnsquishingQS(squishiness).expansion)
+ assertThat(QSSceneAdapter.State.UnsquishingQS { squishiness }.expansion)
.isEqualTo(QSSceneAdapter.State.QS.expansion)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 2fa94ef..229a711 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -126,6 +126,31 @@
}
@Test
+ fun changeScene_toGoneWhenTransitionToLockedFromGone() =
+ testScope.runTest {
+ underTest = kosmos.sceneInteractor
+ val currentScene by collectLastValue(underTest.currentScene)
+ val transitionTo by collectLastValue(underTest.transitioningTo)
+ kosmos.sceneContainerRepository.setTransitionState(
+ flowOf(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Gone,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = flowOf(.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ )
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(transitionTo).isEqualTo(Scenes.Lockscreen)
+
+ underTest.changeScene(Scenes.Gone, "simulate double tap power")
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
fun snapToScene_toUnknownScene_doesNothing() =
testScope.runTest {
val sceneKeys =
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 677477d..ac66e66 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
@@ -49,6 +49,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -383,6 +384,43 @@
}
@Test
+ fun switchToGoneWhenDoubleTapPowerGestureIsTriggeredFromGone() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val transitionStateFlow =
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = true,
+ initialSceneKey = Scenes.Gone,
+ )
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ underTest.start()
+
+ kosmos.fakePowerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON,
+ powerButtonLaunchGestureTriggered = false,
+ )
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Gone,
+ toScene = Scenes.Lockscreen,
+ currentScene = flowOf(Scenes.Lockscreen),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+
+ kosmos.fakePowerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_WAKE,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON,
+ powerButtonLaunchGestureTriggered = true,
+ )
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
fun hydrateSystemUiState() =
testScope.runTest {
val transitionStateFlow = prepareState()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index d6e3879..636d5a7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -129,7 +129,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
// Preferred refresh rate is equal to the first displayMode's refresh rate
- mPreferredRefreshRate = mContext.getDisplay().getSupportedModes()[0].getRefreshRate();
+ mPreferredRefreshRate = mContext.getDisplay().getSystemSupportedModes()[0].getRefreshRate();
overrideResource(
R.integer.config_keyguardRefreshRate,
(int) mPreferredRefreshRate
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
index bba9991..8b4265f 100644
--- 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
@@ -23,8 +23,14 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
+import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
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
@@ -41,9 +47,19 @@
@RunWith(AndroidJUnit4::class)
@EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
class HeadsUpNotificationInteractorTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos =
+ testKosmos().apply {
+ fakeKeyguardTransitionRepository =
+ FakeKeyguardTransitionRepository(initInLockscreen = false)
+ }
private val testScope = kosmos.testScope
- private val repository = kosmos.headsUpNotificationRepository
+ private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
+ private val headsUpRepository by lazy { kosmos.headsUpNotificationRepository }
+ private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+ private val keyguardViewStateRepository by lazy {
+ kosmos.notificationsKeyguardViewStateRepository
+ }
+ private val shadeTestUtil by lazy { kosmos.shadeTestUtil }
private val underTest = kosmos.headsUpNotificationInteractor
@@ -60,7 +76,7 @@
testScope.runTest {
val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
// WHEN no pinned rows are set
- repository.setNotifications(
+ headsUpRepository.setNotifications(
fakeHeadsUpRowRepository("key 0"),
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
@@ -76,7 +92,7 @@
testScope.runTest {
val hasPinnedRows by collectLastValue(underTest.hasPinnedRows)
// WHEN a pinned rows is set
- repository.setNotifications(
+ headsUpRepository.setNotifications(
fakeHeadsUpRowRepository("key 0", isPinned = true),
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
@@ -98,7 +114,7 @@
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// WHEN a row gets pinned
@@ -120,7 +136,7 @@
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// THEN that row gets unpinned
@@ -144,7 +160,7 @@
testScope.runTest {
val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
// WHEN no rows are pinned
- repository.setNotifications(
+ headsUpRepository.setNotifications(
fakeHeadsUpRowRepository("key 0"),
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
@@ -166,7 +182,7 @@
fakeHeadsUpRowRepository("key 1", isPinned = true),
fakeHeadsUpRowRepository("key 2"),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// THEN the unpinned rows are filtered
@@ -184,7 +200,7 @@
fakeHeadsUpRowRepository("key 1", isPinned = true),
fakeHeadsUpRowRepository("key 2"),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// WHEN all rows gets pinned
@@ -206,7 +222,7 @@
fakeHeadsUpRowRepository("key 1", isPinned = true),
fakeHeadsUpRowRepository("key 2", isPinned = true),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// THEN no rows are filtered
@@ -224,7 +240,7 @@
fakeHeadsUpRowRepository("key 1", isPinned = true),
fakeHeadsUpRowRepository("key 2", isPinned = true),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
// WHEN a row gets unpinned
@@ -246,7 +262,7 @@
fakeHeadsUpRowRepository("key 1"),
fakeHeadsUpRowRepository("key 2"),
)
- repository.setNotifications(rows)
+ headsUpRepository.setNotifications(rows)
runCurrent()
rows[0].isPinned.value = true
@@ -262,6 +278,96 @@
assertThat(pinnedHeadsUpRows).containsExactly(rows[0])
}
+ @Test
+ fun showHeadsUpStatusBar_true() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN a row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
+
+ assertThat(showHeadsUpStatusBar).isTrue()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_withoutPinnedNotifications_false() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN no row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = false))
+
+ assertThat(showHeadsUpStatusBar).isFalse()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_whenShadeExpanded_false() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN a row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
+ // AND the shade is expanded
+ shadeTestUtil.setShadeExpansion(1.0f)
+
+ assertThat(showHeadsUpStatusBar).isFalse()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_notificationsAreHidden_false() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN a row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
+ // AND the notifications are hidden
+ keyguardViewStateRepository.areNotificationsFullyHidden.value = true
+
+ assertThat(showHeadsUpStatusBar).isFalse()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_onLockScreen_false() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN a row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
+ // AND the lock screen is shown
+ keyguardTransitionRepository.emitInitialStepsFromOff(to = KeyguardState.LOCKSCREEN)
+
+ assertThat(showHeadsUpStatusBar).isFalse()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_onByPassLockScreen_true() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN a row is pinned
+ headsUpRepository.setNotifications(fakeHeadsUpRowRepository("key 0", isPinned = true))
+ // AND the lock screen is shown
+ keyguardTransitionRepository.emitInitialStepsFromOff(to = KeyguardState.LOCKSCREEN)
+ // AND bypass is enabled
+ faceAuthRepository.isBypassEnabled.value = true
+
+ assertThat(showHeadsUpStatusBar).isTrue()
+ }
+
+ @Test
+ fun showHeadsUpStatusBar_onByPassLockScreen_withoutNotifications_false() =
+ testScope.runTest {
+ val showHeadsUpStatusBar by collectLastValue(underTest.showHeadsUpStatusBar)
+
+ // WHEN no pinned rows
+ // AND the lock screen is shown
+ keyguardTransitionRepository.emitInitialStepsFromOff(to = KeyguardState.LOCKSCREEN)
+ // AND bypass is enabled
+ faceAuthRepository.isBypassEnabled.value = true
+
+ assertThat(showHeadsUpStatusBar).isFalse()
+ }
+
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/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index cc5df74..9fde116 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -524,9 +524,9 @@
// WHEN there are no pinned rows
val rows =
arrayListOf(
- fakeHeadsUpRowRepository(key = "0"),
- fakeHeadsUpRowRepository(key = "1"),
- fakeHeadsUpRowRepository(key = "2"),
+ FakeHeadsUpRowRepository(key = "0"),
+ FakeHeadsUpRowRepository(key = "1"),
+ FakeHeadsUpRowRepository(key = "2"),
)
headsUpRepository.setNotifications(
rows,
@@ -565,8 +565,8 @@
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
headsUpRepository.setNotifications(
- fakeHeadsUpRowRepository(key = "0", isPinned = true),
- fakeHeadsUpRowRepository(key = "1")
+ FakeHeadsUpRowRepository(key = "0", isPinned = true),
+ FakeHeadsUpRowRepository(key = "1")
)
runCurrent()
@@ -580,8 +580,8 @@
val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
headsUpRepository.setNotifications(
- fakeHeadsUpRowRepository(key = "0"),
- fakeHeadsUpRowRepository(key = "1"),
+ FakeHeadsUpRowRepository(key = "0"),
+ FakeHeadsUpRowRepository(key = "1"),
)
runCurrent()
@@ -607,7 +607,7 @@
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
shadeTestUtil.setQsExpansion(0.0f)
- fakeKeyguardRepository.setKeyguardShowing(false)
+ fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
runCurrent()
assertThat(animationsEnabled).isTrue()
@@ -620,14 +620,9 @@
val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
shadeTestUtil.setQsExpansion(0.0f)
- fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeKeyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
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/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
index a163ca0..d620639 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
@@ -192,10 +192,12 @@
fun streamNotAffectedByMute_isNotMutable() {
with(kosmos) {
testScope.runTest {
- audioRepository.setIsAffectedByMute(audioStream, false)
- val isMutable = underTest.isAffectedByMute(audioStream)
+ val audioStreamModel by collectLastValue(underTest.getAudioStream(audioStream))
+ audioRepository.setAudioStreamModel(
+ audioStreamModel!!.copy(isAffectedByMute = false)
+ )
- assertThat(isMutable).isFalse()
+ assertThat(audioStreamModel!!.isAffectedByMute).isFalse()
}
}
}
@@ -230,6 +232,7 @@
testScope.runTest {
val audioStreamModel by
collectLastValue(audioRepository.getAudioStream(audioStream))
+ underTest.setVolume(audioStream, audioStreamModel!!.maxVolume)
runCurrent()
underTest.setVolume(audioStream, audioStreamModel!!.minVolume)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
index dddf582..9a95274 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
@@ -18,20 +18,13 @@
import android.bluetooth.BluetoothDevice
import android.net.Uri
+import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.settingslib.media.MediaDevice
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.volume.localMediaRepository
-import com.android.systemui.volume.localMediaRepositoryFactory
import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
import com.android.systemui.volume.panel.component.anc.sliceViewManager
import com.google.common.truth.Truth.assertThat
@@ -41,10 +34,14 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AncSliceRepositoryTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -57,23 +54,23 @@
val slice = FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
whenever(sliceViewManager.bindSlice(any<Uri>())).thenReturn(slice)
- underTest =
- AncSliceRepositoryImpl(
- localMediaRepositoryFactory,
- testScope.testScheduler,
- testScope.testScheduler,
- sliceViewManager,
- )
+ underTest = AncSliceRepositoryImpl(testScope.testScheduler, sliceViewManager)
}
}
@Test
- fun noConnectedDevice_noSlice() {
+ fun connectedDevice_noUri_noSlice() {
with(kosmos) {
testScope.runTest {
- localMediaRepository.updateCurrentConnectedDevice(null)
-
- val slice by collectLastValue(underTest.ancSlice(1, false, false))
+ val slice by
+ collectLastValue(
+ underTest.ancSlice(
+ device = createMediaDevice(""),
+ width = 1,
+ isCollapsed = false,
+ hideLabel = false,
+ )
+ )
runCurrent()
assertThat(slice).isNull()
@@ -82,12 +79,18 @@
}
@Test
- fun connectedDevice_sliceReturned() {
+ fun connectedDevice_hasUri_sliceReturned() {
with(kosmos) {
testScope.runTest {
- localMediaRepository.updateCurrentConnectedDevice(createMediaDevice())
-
- val slice by collectLastValue(underTest.ancSlice(1, false, false))
+ val slice by
+ collectLastValue(
+ underTest.ancSlice(
+ device = createMediaDevice("content://test.slice"),
+ width = 1,
+ isCollapsed = false,
+ hideLabel = false,
+ )
+ )
runCurrent()
assertThat(slice).isNotNull()
@@ -95,21 +98,13 @@
}
}
- private fun createMediaDevice(sliceUri: String = "content://test.slice"): MediaDevice {
- val bluetoothDevice: BluetoothDevice = mock {
- whenever(getMetadata(any()))
- .thenReturn(
- ("<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" +
- sliceUri +
- "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>")
- .toByteArray()
- )
- }
- val cachedBluetoothDevice: CachedBluetoothDevice = mock {
- whenever(device).thenReturn(bluetoothDevice)
- }
- return mock<BluetoothMediaDevice> {
- whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
- }
+ private fun createMediaDevice(sliceUri: String): BluetoothDevice = mock {
+ on { getMetadata(any()) }
+ .thenReturn(
+ ("<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" +
+ sliceUri +
+ "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>")
+ .toByteArray()
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
index 553aed8..8d052fe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
@@ -16,7 +16,9 @@
package com.android.systemui.volume.panel.component.anc.domain
+import android.media.AudioManager
import android.net.Uri
+import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -26,10 +28,13 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.data.repository.audioRepository
+import com.android.systemui.volume.localMediaRepository
import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
import com.android.systemui.volume.panel.component.anc.ancSliceInteractor
import com.android.systemui.volume.panel.component.anc.ancSliceRepository
import com.android.systemui.volume.panel.component.anc.sliceViewManager
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.TestMediaDevicesFactory
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -41,6 +46,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AncAvailabilityCriteriaTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -74,6 +80,10 @@
fun hasSlice_available() {
with(kosmos) {
testScope.runTest {
+ audioRepository.setMode(AudioManager.MODE_NORMAL)
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.bluetoothMediaDevice()
+ )
ancSliceRepository.putSlice(
1,
FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
index 81e6ac4..741671e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
@@ -16,15 +16,21 @@
package com.android.systemui.volume.panel.component.anc.domain.interactor
+import android.media.AudioManager
+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.testScope
import com.android.systemui.testKosmos
+import com.android.systemui.volume.data.repository.audioRepository
+import com.android.systemui.volume.localMediaRepository
import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
+import com.android.systemui.volume.panel.component.anc.ancSliceInteractor
import com.android.systemui.volume.panel.component.anc.ancSliceRepository
import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.TestMediaDevicesFactory
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -36,6 +42,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AncSliceInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -43,14 +50,12 @@
private lateinit var underTest: AncSliceInteractor
@Before
- fun setup() {
- with(kosmos) {
- underTest = AncSliceInteractor(ancSliceRepository, testScope.backgroundScope)
- }
+ fun setUp() {
+ underTest = kosmos.ancSliceInteractor
}
@Test
- fun errorSlice_returnsNull() {
+ fun errorSlice_returnsUnavailable() {
with(kosmos) {
testScope.runTest {
ancSliceRepository.putSlice(
@@ -67,7 +72,7 @@
}
@Test
- fun noSliceItem_returnsNull() {
+ fun noSliceItem_returnsUnavailable() {
with(kosmos) {
testScope.runTest {
ancSliceRepository.putSlice(
@@ -84,9 +89,31 @@
}
@Test
+ fun sliceItem_noError_noDevice_returnsUnavailable() {
+ with(kosmos) {
+ testScope.runTest {
+ ancSliceRepository.putSlice(
+ 1,
+ FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
+ )
+
+ val slice by collectLastValue(underTest.ancSlices)
+ runCurrent()
+
+ assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)
+ }
+ }
+ }
+
+ @Test
fun sliceItem_noError_returnsSlice() {
with(kosmos) {
testScope.runTest {
+ audioRepository.setMode(AudioManager.MODE_NORMAL)
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.bluetoothMediaDevice()
+ )
+
ancSliceRepository.putSlice(
1,
FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
index 737b7f3..777240c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
@@ -19,13 +19,13 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.spatializerInteractor
-import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
val Kosmos.spatialAudioComponentInteractor by
Kosmos.Fixture {
SpatialAudioComponentInteractor(
- mediaOutputInteractor,
+ audioOutputInteractor,
spatializerInteractor,
testScope.backgroundScope
)
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 e36ae60..c6c46fa 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
@@ -29,7 +29,6 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.spatializerInteractor
import com.android.systemui.media.spatializerRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -37,9 +36,9 @@
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
import com.android.systemui.volume.mediaControllerRepository
-import com.android.systemui.volume.mediaOutputInteractor
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -76,12 +75,7 @@
mediaControllerRepository.setActiveSessions(listOf(localMediaController))
- underTest =
- SpatialAudioComponentInteractor(
- mediaOutputInteractor,
- spatializerInteractor,
- testScope.backgroundScope,
- )
+ underTest = spatialAudioComponentInteractor
}
}
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index b419880..57fd9ea 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -69,8 +69,8 @@
<string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"افتح القفل بكلمة مرور أو ببصمة إصبع."</string>
<string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"افتح بالنقش أو بصمة الإصبع"</string>
<string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"لمزيد من الأمان، تم قفل الجهاز وفقًا لسياسة العمل."</string>
- <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"يجب إدخال رقم التعريف الشخصي بعد إلغاء التأمين."</string>
- <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"يجب إدخال كلمة المرور بعد إلغاء التأمين."</string>
+ <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"يجب إدخال رقم التعريف الشخصي بعد إلغاء الفتح الذكي."</string>
+ <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"يجب إدخال كلمة المرور بعد إلغاء الفتح الذكي."</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"يجب رسم النقش بعد إلغاء التأمين."</string>
<string name="kg_prompt_unattended_update" msgid="4366635751738712452">"سيتم تثبيت التحديث عندما لا يكون الجهاز قيد الاستخدام."</string>
<string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"يجب تعزيز الأمان. لم يُستخدَم رقم PIN لبعض الوقت."</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 71a60a8..f014c29 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"צריך להזין קוד אימות"</string>
+ <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"מה קוד האימות שלך?"</string>
<string name="keyguard_enter_pin" msgid="8114529922480276834">"צריך להזין קוד אימות"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"יש להזין קו ביטול נעילה"</string>
<string name="keyguard_enter_pattern" msgid="7616595160901084119">"צריך לצייר קו ביטול נעילה"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 224f1ae..2fd42f4 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -28,7 +28,7 @@
<string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड हाल्नुहोस्"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"अमान्य कार्ड।"</string>
<string name="keyguard_charged" msgid="5478247181205188995">"चार्ज भयो"</string>
- <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तारविनै चार्ज गर्दै"</string>
+ <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
<string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज हुँदै छ"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज गरिँदै"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै छ"</string>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index 274b72a..9bb0b6d 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"अझ छिटो चार्ज गर्न फोनलाई फेरि मिलाउनुहोस्"</string>
- <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"तारविनै चार्ज गर्न फोनलाई फेरि मिलाउनुहोस्"</string>
+ <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"वायरलेस तरिकाले चार्ज गर्न फोन फेरि मिलाउनुहोस्"</string>
<string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Android टिभी यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string>
<string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"यो डिभाइस चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="408124574073032188">"ट्याब्लेटमा SIM कार्ड हालिएको छैन।"</string>
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
index a30a122..c32acf2 100644
--- a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
@@ -15,16 +15,10 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/qs_tile_ripple_color">
- <!-- We don't really use the ripple effect here, but changing it to LayerDrawable causes
- performance regression, see: b/339412453.
- Since this ripple has just one layer inside, we can try to remove that extra "background"
- layer. However this should only be done when the flag
- com.android.systemui.qs_tile_focus_state has completed all its stages and this drawable
- fully replaces the previous one to ensure consistency with code sections searching for
- specific ids in drawable hierarchy
- -->
<item
- android:id="@id/background">
+ android:id="@android:id/mask"
+ android:drawable="@drawable/qs_tile_background_shape" />
+ <item android:id="@id/background">
<layer-list>
<item
android:id="@+id/qs_tile_background_base"
@@ -32,22 +26,8 @@
<item android:id="@+id/qs_tile_background_overlay">
<selector>
<item
- android:state_hovered="true"
- android:drawable="@drawable/qs_tile_background_shape" />
- </selector>
- </item>
- <!-- In the layer below we have negative insets because we need the focus outline
- to draw outside the bounds, around the main background. We use 5dp because
- the outline stroke is 3dp and the required padding is 2dp.-->
- <item
- android:top="-5dp"
- android:right="-5dp"
- android:left="-5dp"
- android:bottom="-5dp">
- <selector>
- <item
- android:state_focused="true"
- android:drawable="@drawable/qs_tile_focused_background"/>
+ android:drawable="@drawable/qs_tile_background_shape"
+ android:state_hovered="true" />
</selector>
</item>
</layer-list>
diff --git a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
index fd456df..33f0d02 100644
--- a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
@@ -13,10 +13,14 @@
~ 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">
- <corners android:radius="30dp"/>
- <stroke android:width="3dp" android:color="?androidprv:attr/materialColorSecondaryFixed"/>
-</shape>
\ No newline at end of file
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="-5dp">
+ <shape xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="30dp" />
+ <stroke
+ android:width="3dp"
+ android:color="?androidprv:attr/materialColorSecondaryFixed" />
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml
index bb8cece..ad6c154 100644
--- a/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml
+++ b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml
@@ -14,10 +14,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape
+<inset
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/materialColorSurfaceBright"/>
- <corners android:radius="10000dp"/> <!-- fully-rounded radius -->
-</shape>
+ android:insetLeft="@dimen/overlay_action_container_minimum_edge_spacing"
+ android:insetRight="@dimen/overlay_action_container_minimum_edge_spacing">
+ <shape
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
+ <corners android:radius="10000dp"/> <!-- fully-rounded radius -->
+ </shape>
+</inset>
\ No newline at end of file
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 05f6fae..8b9eabc 100644
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -33,8 +33,7 @@
layout="@layout/biometric_prompt_button_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginBottom="40dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/bottomGuideline"
app:layout_constraintEnd_toEndOf="@id/panel"
app:layout_constraintStart_toStartOf="@id/panel" />
diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
index 0bbe73c..9f4ad0e 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
@@ -23,11 +23,12 @@
<!-- Negative Button, reserved for app -->
<Button
android:id="@+id/button_negative"
- style="@style/Widget.Dialog.Button.BorderButton"
+ style="@style/AuthCredentialNegativeButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
android:ellipsize="end"
android:maxLines="2"
android:visibility="invisible"
@@ -37,11 +38,12 @@
<!-- Cancel Button, replaces negative button when biometric is accepted -->
<Button
android:id="@+id/button_cancel"
- style="@style/Widget.Dialog.Button.BorderButton"
+ style="@style/AuthCredentialNegativeButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
android:text="@string/cancel"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
@@ -50,11 +52,12 @@
<!-- "Use Credential" Button, replaces if device credential is allowed -->
<Button
android:id="@+id/button_use_credential"
- style="@style/Widget.Dialog.Button.BorderButton"
+ style="@style/AuthCredentialNegativeButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
@@ -67,6 +70,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="24dp"
+ android:layout_marginBottom="8dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_confirm"
@@ -82,6 +86,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="24dp"
+ android:layout_marginBottom="8dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_try_again"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index fa4d9a8..9b5b59f 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -31,8 +31,7 @@
layout="@layout/biometric_prompt_button_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginBottom="40dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/bottomGuideline"
app:layout_constraintEnd_toEndOf="@id/panel"
app:layout_constraintStart_toStartOf="@id/panel" />
diff --git a/packages/SystemUI/res/layout/clipboard_overlay2.xml b/packages/SystemUI/res/layout/clipboard_overlay2.xml
index 521369e..65005f8 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay2.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay2.xml
@@ -24,6 +24,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/clipboard_overlay_window_name">
+ <!-- Min edge spacing guideline off of which the preview and actions can be anchored (without
+ this we'd need to express margins as the sum of two different dimens). -->
+ <androidx.constraintlayout.widget.Guideline
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/min_edge_guideline"
+ app:layout_constraintGuide_begin="@dimen/overlay_action_container_minimum_edge_spacing"
+ android:orientation="vertical"/>
+ <!-- Negative horizontal margin because this container background must render beyond the thing
+ it's constrained by (the actions themselves). -->
<FrameLayout
android:id="@+id/actions_container_background"
android:visibility="gone"
@@ -31,11 +41,12 @@
android:layout_width="0dp"
android:elevation="4dp"
android:background="@drawable/shelf_action_chip_container_background"
- android:layout_marginStart="@dimen/overlay_action_container_minimum_edge_spacing"
+ android:layout_marginStart="@dimen/negative_overlay_action_container_minimum_edge_spacing"
+ android:layout_marginEnd="@dimen/negative_overlay_action_container_minimum_edge_spacing"
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_constraintStart_toStartOf="@id/min_edge_guideline"
+ app:layout_constraintTop_toTopOf="@id/actions_container"
+ app:layout_constraintEnd_toEndOf="@id/actions_container"
app:layout_constraintBottom_toBottomOf="parent"/>
<HorizontalScrollView
android:id="@+id/actions_container"
@@ -76,7 +87,7 @@
android:layout_marginBottom="@dimen/overlay_preview_container_margin"
android:elevation="7dp"
android:background="@drawable/overlay_border"
- app:layout_constraintStart_toStartOf="@id/actions_container_background"
+ app:layout_constraintStart_toStartOf="@id/min_edge_guideline"
app:layout_constraintTop_toTopOf="@id/clipboard_preview"
app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
app:layout_constraintBottom_toBottomOf="@id/actions_container_background"/>
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index 49d3a8e..f3f472b 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -19,43 +19,15 @@
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">
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/screenshot_static"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
- <FrameLayout
- android:id="@+id/actions_container_background"
- android:visibility="gone"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:elevation="4dp"
- android:background="@drawable/shelf_action_chip_container_background"
- android:layout_marginHorizontal="@dimen/overlay_action_container_minimum_edge_spacing"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@id/guideline"
- >
- <HorizontalScrollView
- android:id="@+id/actions_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="@dimen/overlay_action_container_padding_vertical"
- android:layout_marginHorizontal="@dimen/overlay_action_chip_margin_start"
- android:background="@drawable/shelf_action_container_clipping_shape"
- android:clipToOutline="true"
- android:scrollbars="none">
- <LinearLayout
- android:id="@+id/screenshot_actions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:showDividers="middle"
- android:divider="@drawable/shelf_action_chip_divider"
- android:animateLayoutChanges="true"
- />
- </HorizontalScrollView>
- </FrameLayout>
<View
android:id="@+id/screenshot_preview_border"
android:layout_width="0dp"
@@ -101,6 +73,36 @@
android:visibility="invisible"
app:layout_constraintStart_toStartOf="@id/screenshot_preview_border"
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"/>
+ <!-- Action bar should be drawn on top of the thumbnail -->
+ <FrameLayout
+ android:id="@+id/actions_container_background"
+ android:visibility="gone"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:elevation="4dp"
+ android:background="@drawable/shelf_action_chip_container_background"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
+ >
+ <HorizontalScrollView
+ android:id="@+id/actions_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="@dimen/overlay_action_container_padding_vertical"
+ android:layout_marginHorizontal="@dimen/overlay_action_chip_margin_start"
+ android:background="@drawable/shelf_action_container_clipping_shape"
+ android:clipToOutline="true"
+ android:scrollbars="none">
+ <LinearLayout
+ android:id="@+id/screenshot_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:showDividers="middle"
+ android:divider="@drawable/shelf_action_chip_divider"
+ android:animateLayoutChanges="true"
+ android:orientation="horizontal" />
+ </HorizontalScrollView>
+ </FrameLayout>
<ImageView
android:id="@+id/screenshot_badge"
android:layout_width="56dp"
diff --git a/packages/SystemUI/res/raw/face_dialog_authenticating.json b/packages/SystemUI/res/raw/face_dialog_authenticating.json
new file mode 100644
index 0000000..4e25e6d
--- /dev/null
+++ b/packages/SystemUI/res/raw/face_dialog_authenticating.json
@@ -0,0 +1 @@
+{"v":"5.7.13","fr":60,"ip":0,"op":61,"w":64,"h":64,"nm":"face_scanning 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,32,0],"ix":2,"l":2},"a":{"a":0,"k":[27.25,27.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[95,95,100]},{"t":60,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.243],[-1.244,0],[0,1.243],[1.242,0]],"o":[[0,1.243],[1.242,0],[0,-1.243],[-1.244,0]],"v":[[-2.249,0.001],[0.001,2.251],[2.249,0.001],[0.001,-2.251]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.658823529412,0.780392216701,0.980392216701,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[60]},{"t":60,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.1,20.495],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.243],[-1.242,0],[0,1.243],[1.242,0]],"o":[[0,1.243],[1.242,0],[0,-1.243],[-1.242,0]],"v":[[-2.249,0],[0.001,2.25],[2.249,0],[0.001,-2.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.658823529412,0.780392216701,0.980392216701,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[60]},{"t":60,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[39.4,20.495],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[2.814,3.523],[-2.814,3.523],[-2.814,1.363],[0.652,1.363],[0.652,-3.523],[2.814,-3.523]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.658823529412,0.780392216701,0.980392216701,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[60]},{"t":60,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.791,28.479],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.154,0.15],[0,0],[0.117,-0.095],[0,0],[0.228,-0.121],[0.358,-0.103],[0.922,0.261],[0.3,0.16],[0.24,0.185],[0.14,0.139],[0.178,0.261],[0.143,0.451],[0,0],[0,0.494],[0,0],[-0.214,-0.676],[-0.392,-0.572],[-0.323,-0.317],[-0.228,-0.177],[-0.333,-0.179],[-0.503,-0.145],[-0.662,0],[-0.653,0.184],[-0.437,0.233],[-0.336,0.258],[0,0],[0,0]],"o":[[0,0],[-0.107,0.106],[0,0],[-0.24,0.185],[-0.301,0.16],[-0.92,0.261],[-0.357,-0.103],[-0.228,-0.121],[-0.158,-0.122],[-0.225,-0.221],[-0.272,-0.393],[0,0],[-0.147,-0.466],[0,0],[0,0.716],[0.206,0.656],[0.256,0.372],[0.204,0.201],[0.336,0.258],[0.436,0.233],[0.655,0.184],[0.662,0],[0.503,-0.145],[0.332,-0.179],[0,0],[0,0],[0.165,-0.136]],"v":[[6.094,1.465],[4.579,-0.076],[4.242,0.225],[4.124,0.315],[3.43,0.771],[2.439,1.165],[-0.342,1.165],[-1.331,0.771],[-2.027,0.315],[-2.48,-0.075],[-3.087,-0.801],[-3.712,-2.075],[-3.712,-2.075],[-3.934,-3.523],[-6.094,-3.523],[-5.771,-1.424],[-4.868,0.424],[-3.995,1.465],[-3.344,2.027],[-2.35,2.676],[-0.934,3.243],[1.049,3.523],[3.031,3.243],[4.449,2.676],[5.441,2.027],[5.482,1.997],[5.615,1.895]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.658823529412,0.780392216701,0.980392216701,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[60]},{"t":60,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[26.201,40.411],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.398,0],[0,-13.4],[13.398,0],[0,13.4]],"o":[[13.398,0],[0,13.4],[-13.398,0],[0,-13.4]],"v":[[0,-24.3],[24.3,0],[0,24.3],[-24.3,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[14.904,0],[0,-14.904],[-14.904,0],[0,14.904]],"o":[[-14.904,0],[0,14.904],[14.904,0],[0,-14.904]],"v":[[0,-27],[-27,0],[0,27],[27,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.658823529412,0.780392216701,0.980392216701,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[60]},{"t":60,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.25,27.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index cc8f9c2..abbb4cb 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Stuur"</string>
<string name="cancel" msgid="1089011503403416730">"Kanselleer"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Applogo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bevestig"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Probeer weer"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tik om stawing te kanselleer"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netwerke is nie beskikbaar nie"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Geen Wi-Fi-netwerke beskikbaar nie"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Skakel tans aan …"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Skermuitsending"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Saai uit"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Saai tans uit"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Onbenoemde toestel"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen toestelle beskikbaar nie"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Eenhandmodus"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Gehoortoestelle"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Gehoortoestelle"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bind nuwe toestel saam"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pasmaak legstukke"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-ikoon vir gedeaktiveerde legstuk"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikoon vir ’n legstuk wat geïnstalleer word"</string>
<string name="edit_widget" msgid="9030848101135393954">"Wysig legstuk"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Demp %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Ontdemp %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"gedemp"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibreer"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Bel met"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index b00dc78..3bdf212 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ላክ"</string>
<string name="cancel" msgid="1089011503403416730">"ይቅር"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"የመተግበሪያ ዓርማ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"አረጋግጥ"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"እንደገና ይሞክሩ"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ማረጋገጥን ለመሰረዝ መታ ያድርጉ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"አውታረ መረቦች አይገኙም"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"ምንም የWi-Fi አውታረ መረቦች የሉም"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"በማብራት ላይ..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"የማያ ገፅ መውሰድ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"በመውሰድ ላይ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ያልተሰየመ መሣሪያ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ምንም መሣሪያዎች አይገኙም"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ባትሪ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"የአንድ እጅ ሁነታ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ንጽጽር"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"መደበኛ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"መካከለኛ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ከፍተኛ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"የመስሚያ መሣሪያዎች"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"የመስማት ችሎታ መሣሪያ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"አዲስ መሣሪያ ያጣምሩ"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ምግብሮችን አብጅ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"የመተግበሪያ አዶ ለተሰናከለ ምግብር"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"የምግብር የመተግበሪያ አዶ ሲጫን"</string>
<string name="edit_widget" msgid="9030848101135393954">"ምግብርን አርትዕ"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"ድምፀ-ከል አድርግ %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"ድምፀ-ከልን አንሳ %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ድምፀ-ከል ተደርጓል"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"መንዘር"</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_ongoing_call" msgid="208426888064112006">"በጥሪ ላይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d498154..ac210e2 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"إرسال"</string>
<string name="cancel" msgid="1089011503403416730">"إلغاء"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"شعار التطبيق"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"تأكيد"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"إعادة المحاولة"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"انقر لإلغاء المصادقة."</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"الشبكات غير متوفرة"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"لا تتوفر أي شبكة Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"جارٍ التفعيل…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"بث الشاشة"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"الإرسال"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"جارٍ الإرسال"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"جهاز لا يحمل اسمًا"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"لا يتوفر أي جهاز"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"البطارية"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"التباين"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"عادي"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"مرتفع"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعات الأذن الطبية"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعات الأذن الطبية"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"إقران جهاز جديد"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"تخصيص التطبيقات المصغَّرة"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"رمز التطبيق المصغّر غير المفعّل"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"رمز تطبيق مصغَّر جارٍ تثبيته"</string>
<string name="edit_widget" msgid="9030848101135393954">"تعديل التطبيق المصغَّر"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"تخصيص التطبيقات المصغَّرة"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"التطبيقات المصغّرة على شاشة القفل"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"اختيار التطبيق المصغّر"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"إزالة التطبيق المصغّر"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"إضافة التطبيق المصغّر المحدَّد"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
@@ -631,18 +626,13 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"كتم صوت \"%s\""</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"إعادة صوت \"%s\""</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"تم كتم الصوت"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"اهتزاز"</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>
- <!-- no translation found for media_output_title_ongoing_call (208426888064112006) -->
- <skip />
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"هناك مكالمة جارية"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"أداة ضبط واجهة مستخدم النظام"</string>
<string name="status_bar" msgid="4357390266055077437">"شريط الحالة"</string>
<string name="demo_mode" msgid="263484519766901593">"وضع تجريبي لواجهة مستخدم النظام"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index daefd83..45363dd 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"পঠিয়াওক"</string>
<string name="cancel" msgid="1089011503403416730">"বাতিল কৰক"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"এপৰ ল’গ’"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"নিশ্চিত কৰক"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"আকৌ চেষ্টা কৰক"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ বাতিল কৰিবলৈ টিপক"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"নেটৱৰ্ক উপলব্ধ নহয়"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"কোনো ৱাই-ফাই নেটৱৰ্ক নাই"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"অন কৰি থকা হৈছে…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"স্ক্ৰীন কাষ্ট"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"কাষ্ট"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"কাষ্টিং"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"নাম নথকা ডিভাইচ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইচ নাই"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"বেটাৰী"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"কনট্ৰাষ্ট"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"মানক"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"মধ্যমীয়া"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"উচ্চ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"শুনাৰ ডিভাইচ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"শুনাৰ ডিভাইচ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ৱিজেট কাষ্টমাইজ কৰক"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"অক্ষম কৰা ৱিজেটৰ বাবে এপৰ চিহ্ন"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ইনষ্টল কৰি থকা এটা ৱিজেটৰ বাবে এপৰ চিহ্ন"</string>
<string name="edit_widget" msgid="9030848101135393954">"ৱিজেট সম্পাদনা কৰক"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s মিউট কৰক"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s আনমিউট কৰক"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"মিউট কৰা হৈছে"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"কম্পন"</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_ongoing_call" msgid="208426888064112006">"কল চলি আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 399e621..e796364 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Göndərin"</string>
<string name="cancel" msgid="1089011503403416730">"Ləğv edin"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Tətbiq loqosu"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Təsdiq"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Yenidən cəhd edin"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Doğrulanmanı ləğv etmək üçün toxunun"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Şəbəkələr əlçatan deyil"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Heç bir Wi-Fi şəbəkəsi əlçatan deyil"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Aktiv edilir..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekran Paylaşımı"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Yayım"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Yayım"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Adsız cihaz"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Heç bir cihaz əlçatan deyil"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batareya"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Birəlli rejim"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksək"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eşitmə cihazları"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eşitmə cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz birləşdirin"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidcetləri fərdiləşdirin"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Deaktiv edilmiş vidcet üçün tətbiq ikonası"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Quraşdırılan vidcet üçün tətbiq ikonası"</string>
<string name="edit_widget" msgid="9030848101135393954">"Vidceti redaktə edin"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Səssiz edin: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Səsi açın: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"səssiz edilib"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrasiya"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Zəng edilir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 16056660..23a09cad 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Pošalji"</string>
<string name="cancel" msgid="1089011503403416730">"Otkaži"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip aplikacije"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdi"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Probaj ponovo"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Dodirnite da biste otkazali potvrdu identiteta"</string>
@@ -168,7 +170,7 @@
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Identitet je potvrđen"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Otkažite potvrdu identiteta"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Još opcija"</string>
- <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
+ <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristi PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite šablon"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Koristite lozinku"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Pogrešan PIN"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nije dostupna nijedna WiFi mreža"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Uključuje se..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Prebacivanje ekrana"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Prebacivanje"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Prebacivanje"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Neimenovani uređaj"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nije dostupan nijedan uređaj"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterija"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednom rukom"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardno"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Upari novi uređaj"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi vidžete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućen vidžet"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za vidžet koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Izmeni vidžet"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Isključite zvuk za: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Uključite zvuk za: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"zvuk je isključen"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibracija"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Poziv na uređaju"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 89a4701..7dc9480 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Адправіць"</string>
<string name="cancel" msgid="1089011503403416730">"Скасаваць"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Лагатып праграмы"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Пацвердзіць"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Паўтарыць спробу"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Націсніце, каб скасаваць аўтэнтыфікацыю"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сеткі недаступныя"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Няма даступнай сеткі Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Уключэнне…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Трансляцыя экрана"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Трансляцыя"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Ідзе перадача"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Прылада без назвы"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма даступных прылад"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Акумулятар"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Рэжым кіравання адной рукой"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Кантрастнасць"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартная"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Сярэдняя"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Высокая"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слыхавыя апараты"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слыхавыя апараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спалучыць новую прыладу"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Наладзіць віджэты"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок праграмы для адключанага віджэта"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок праграмы для віджэта ў працэсе ўсталявання"</string>
<string name="edit_widget" msgid="9030848101135393954">"Змяніць віджэт"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Выключыць гук: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Уключыць гук: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"гук выключаны"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вібрацыя"</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_ongoing_call" msgid="208426888064112006">"Ідзе выклік"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bdd9fd4..42265b0 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Изпращане"</string>
<string name="cancel" msgid="1089011503403416730">"Отказ"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Лого на приложението"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Потвърждаване"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Нов опит"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Докоснете, за да анулирате удостоверяването"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Няма достъпни мрежи"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Няма налични Wi-Fi мрежи"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Включва се..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Предаване на екрана"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Предаване"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Предава се"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Устройство без име"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма налични устройства"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батерия"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим за работа с една ръка"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартен"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Среден"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Висок"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухови апарати"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухови апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Сдвояване на ново устройство"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Персонализиране на приспособленията"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона на приложение за деактивирано приспособление"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона на приложение, чието приспособление се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Редактиране на приспособлението"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string>
@@ -629,17 +626,13 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Спиране на звука на %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Включване на звука на %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"звукът е спрян"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вибриране"</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_ongoing_call" msgid="208426888064112006">"Активно обаждане"</string>
+ <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Обаждане на"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Тунер на системния потребителски интерфейс"</string>
<string name="status_bar" msgid="4357390266055077437">"Лента на състоянието"</string>
<string name="demo_mode" msgid="263484519766901593">"Демонстрационен режим на системния ПИ"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2c47b12..3d008cb 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"পাঠান"</string>
<string name="cancel" msgid="1089011503403416730">"বাতিল করুন"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"অ্যাপের লোগো"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"কনফার্ম করুন"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"আবার চেষ্টা করুন"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"যাচাইকরণ বাতিল করতে ট্যাপ করুন"</string>
@@ -201,7 +203,7 @@
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"\'ফেস আনলক\' সেট-আপ করুন"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"\'ফেস আনলক\' আবার সেট-আপ করতে, বর্তমানে থাকা আপনার ফেস মডেলটি মুছে ফেলা হবে।\n\nফেস ব্যবহার করে আপনার ফোন আনলক করার জন্য আপনাকে আবার এই ফিচার সেট-আপ করতে হবে।"</string>
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"\'ফেস আনলক\' সেট-আপ করা যায়নি। আবার চেষ্টা করতে সেটিংসে যান।"</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ফিঙ্গারপ্রিন্ট সেন্সর টাচ করুন"</string>
<string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"চালিয়ে যেতে \'আনলক করুন\' আইকনে প্রেস করুন"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"মুখ চেনা যায়নি। পরিবর্তে ফিঙ্গারপ্রিন্ট ব্যবহার করুন।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"নেটওয়ার্ক উপলভ্য নেই"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"কোনো ওয়াই-ফাই নেটওয়ার্ক উপলব্ধ নেই"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"চালু করা হচ্ছে…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"স্ক্রিন কাস্ট"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"কাস্ট করুন"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"কাস্ট করা হচ্ছে"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"নামবিহীন ডিভাইস"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইস উপলব্ধ নয়"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ব্যাটারি"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এক হাতে ব্যবহার করার মোড"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"কনট্রাস্ট"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"স্ট্যান্ডার্ড"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"মিডিয়াম"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"হাই"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"হিয়ারিং ডিভাইস"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"হিয়ারিং ডিভাইস"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইস পেয়ার করুন"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"উইজেট কাস্টমাইজ করুন"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"বন্ধ করা উইজেটের জন্য অ্যাপের আইকন"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ইনস্টল করা হচ্ছে এমন উইজেটের অ্যাপ আইকন"</string>
<string name="edit_widget" msgid="9030848101135393954">"উইজেট এডিট করুন"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s মিউট করুন"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s আনমিউট করুন"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"মিউট করা হয়েছে"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ভাইব্রেট"</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_ongoing_call" msgid="208426888064112006">"কল চালু আছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 8621b43..96b83c1 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Pošalji"</string>
<string name="cancel" msgid="1089011503403416730">"Otkaži"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip aplikacije"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdi"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Pokušaj ponovo"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Dodirnite da otkažete autentifikaciju"</string>
@@ -168,7 +170,7 @@
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificirano"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Otkažite autentifikaciju"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Više opcija"</string>
- <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristi PIN"</string>
+ <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristi uzorak"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Koristi lozinku"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Pogrešan PIN kôd"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nema dostupnih WiFi mreža"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Uključivanje…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emitiranje na ekranu"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Emitiranje"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Prebacivanje"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Neimenovani uređaj"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterija"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardno"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodite vidžete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni vidžet"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za vidžet koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Uredite vidžet"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Isključivanje zvuka parametra %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Uključivanje zvuka parametra %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"isključen zvuk"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibracija"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Reproducira se <xliff:g id="LABEL">%s</xliff:g> na"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Reprodukcija zvuka na"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Poziv putem"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 6ebfd86..cf9717f 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Envia"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel·la"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip de l\'aplicació"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirma"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Torna-ho a provar"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toca per cancel·lar l\'autenticació"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Xarxes no disponibles"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No hi ha cap xarxa Wi-Fi disponible"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"S\'està activant…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emet la pantalla"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Emet"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"En emissió"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositiu sense nom"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hi ha cap dispositiu disponible."</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode d\'una mà"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estàndard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mitjà"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alt"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audiòfons"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audiòfons"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincula un dispositiu nou"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalitza els widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona de l\'aplicació per a widget desactivat"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona de l\'aplicació d\'un widget que s\'està instal·lant"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edita el widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Silencia %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Deixa de silenciar %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenciat"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibra"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Trucant des de"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 7d2202d..a5a88d4 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Odeslat"</string>
<string name="cancel" msgid="1089011503403416730">"Zrušit"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo aplikace"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdit"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Zkusit znovu"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Klepnutím zrušíte ověření"</string>
@@ -302,7 +304,7 @@
<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>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Vzdálená obrazovka"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Odesílání"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Odesílání"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nepojmenované zařízení"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nejsou dostupná žádná zařízení"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterie"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardní"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Střední"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoká"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Naslouchátka"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Naslouchátka"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovat nové zařízení"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Přizpůsobit widgety"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikace s deaktivovaným widgetem"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikace při probíhající instalaci widgetu"</string>
<string name="edit_widget" msgid="9030848101135393954">"Upravit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string>
@@ -562,7 +559,7 @@
<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="2587481497846342760">"Zařízení uzamčeno, příliš mnoho pokusů o ověření"</string>
+ <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Zařízení bylo 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>
@@ -618,7 +615,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Omezení hluku"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Prostorový zvuk"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Vypnuto"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Pevný"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fixovaný"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sledování hlavy"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Klepnutím změníte režim vyzvánění"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Ztlumit %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Zapnout zvuk %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ztlumeno"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrace"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Přehrávání <xliff:g id="LABEL">%s</xliff:g> přes"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk se bude přehrávat přes"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Volání na zařízení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ec03938..55a5de9 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Annuller"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Applogo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bekræft"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Prøv igen"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tryk for at annullere godkendelsen"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ingen tilgængelige netværk"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Der er ingen tilgængelige Wi-Fi-netværk"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Aktiverer…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Cast skærm"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Caster"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Enhed uden navn"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Der er ingen tilgængelige enheder"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batteri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Middel"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Høj"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Par ny enhed"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpas widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktiveret widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikonet for en widget er ved at blive installeret"</string>
<string name="edit_widget" msgid="9030848101135393954">"Rediger widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Slå lyden fra for %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Slå lyden til for %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"lyden er slået fra"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibration"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Ringer på"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index d38ad3a..1f0550f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Senden"</string>
<string name="cancel" msgid="1089011503403416730">"Abbrechen"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App-Logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bestätigen"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Noch einmal versuchen"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Zum Abbrechen der Authentifizierung tippen"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netzwerke nicht verfügbar"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Keine WLANs verfügbar"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Wird aktiviert…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Bildschirm übertragen"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Streamen"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Wird übertragen"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unbenanntes Gerät"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Keine Geräte verfügbar"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Akku"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mittel"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoch"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörgeräte"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörgeräte"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Neues Gerät koppeln"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets anpassen"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-Symbol für deaktiviertes Widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App-Symbol für ein Widget, das gerade installiert wird"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget bearbeiten"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s stummschalten"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Stummschaltung von %s aufheben"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"stummgeschaltet"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrieren"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Anruf auf"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c6dad44..937ba70 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Αποστολή"</string>
<string name="cancel" msgid="1089011503403416730">"Ακύρωση"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Λογότυπο εφαρμογής"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Επιβεβαίωση"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Δοκιμάστε ξανά"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Πατήστε για ακύρωση του ελέγχου ταυτότητας"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Δεν υπάρχουν διαθέσιμα δίκτυα"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Δεν υπάρχουν διαθέσιμα δίκτυα Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ενεργοποίηση…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Μετάδοση οθόνης"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Μετάδοση"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Μετάδοση"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Ανώνυμη συσκευή"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Δεν υπάρχουν διαθέσιμες συσκευές"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Μπαταρία"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Λειτουργία ενός χεριού"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Αντίθεση"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Τυπική"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Μέτρια"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Υψηλή"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Συσκευές ακοής"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Συσκευές ακοής"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Σύζευξη νέας συσκευής"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Προσαρμογή γραφικών στοιχείων"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Εικονίδιο εφαρμογής για απενεργοποιημένο γραφικό στοιχείο"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Εικονίδιο εφαρμογής για ένα γραφικό στοιχείου που εγκαθίσταται"</string>
<string name="edit_widget" msgid="9030848101135393954">"Επεξεργασία γραφικού στοιχείου"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Σίγαση %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Κατάργηση σίγασης %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"σε σίγαση"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"δόνηση"</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_ongoing_call" msgid="208426888064112006">"Ενεργή κλήση σε"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index cbb2298..137b243 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirm"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Try again"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tap to cancel authentication"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No Wi-Fi networks available"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Turning on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unnamed device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Unmute %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"muted"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrate"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index fa007b6..1f68f46 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirm"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Try again"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tap to cancel authentication"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No Wi-Fi networks available"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Turning on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unnamed device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cbb2298..137b243 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirm"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Try again"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tap to cancel authentication"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No Wi-Fi networks available"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Turning on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unnamed device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Unmute %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"muted"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrate"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index cbb2298..137b243 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirm"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Try again"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tap to cancel authentication"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No Wi-Fi networks available"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Turning on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unnamed device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mute %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Unmute %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"muted"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrate"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 248360b..eb705ae 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Cancel"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirm"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Try again"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tap to cancel authentication"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No Wi-Fi networks available"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Turning on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Unnamed device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Battery"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 28230f1..ea7748c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -97,7 +97,7 @@
<string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Límite izquierdo: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Límite derecho: <xliff:g id="PERCENT">%1$d</xliff:g> por ciento"</string>
<string name="screenshot_work_profile_notification" msgid="203041724052970693">"Se guardó en <xliff:g id="APP">%1$s</xliff:g> en el perfil de trabajo"</string>
- <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Guardada en <xliff:g id="APP">%1$s</xliff:g> en el perfil personal"</string>
+ <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Se guardó en el perfil privado de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Archivos"</string>
<string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detectó que tomaste una captura de pantalla."</string>
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras apps en ejecución detectaron que tomaste una captura de pantalla."</string>
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotipo de la app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Volver a intentarlo"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Presiona para cancelar la autenticación"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes no disponible"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No hay redes Wi-Fi disponibles"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transmisión de pantalla"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Transmitiendo"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sin nombre"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batería"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo una mano"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo nuevo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícono de la app de widget inhabilitado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícono de la app para un widget que se está instalando"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modificar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Activar sonido de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"en silencio"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Llamando en"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index fd2ac85..8365067 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotipo de la aplicación"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Reintentar"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toca para cancelar la autenticación"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes no disponibles"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"No hay ninguna red Wi-Fi disponible"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Enviar pantalla"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Enviar"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Enviando"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sin nombre"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batería"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo Una mano"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audífonos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audífonos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Emparejar nuevo dispositivo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icono de la aplicación de widget inhabilitado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Instalando icono de aplicación para widget"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Activar sonido de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenciado"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Llamando desde"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 7f97176..2df5681 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Saada"</string>
<string name="cancel" msgid="1089011503403416730">"Tühista"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Rakenduse logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Kinnita"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Proovi uuesti"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Puudutage autentimise tühistamiseks"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Võrgud pole saadaval"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"WiFi-võrke pole saadaval"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Sisselülitamine …"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekraanikuva ülekandmine"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Ülekandmine"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Osatäitjad"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nimeta seade"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ühtegi seadet pole saadaval"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Aku"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastsus"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavaline"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Keskmine"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Kõrge"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuuldeseadmed"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuuldeseadmed"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uue seadme sidumine"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Kohanda vidinaid"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Keelatud vidina rakenduseikoon"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Installitava vidina rakenduseikoon"</string>
<string name="edit_widget" msgid="9030848101135393954">"Muuda vidinat"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Parameetri %s vaigistamine"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Parameetri %s vaigistuse tühistamine"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"vaigistatud"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibreerimine"</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 esitatakse seadmes"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Helistamine seadmes"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 685b592..1f10821 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Bidali"</string>
<string name="cancel" msgid="1089011503403416730">"Utzi"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Aplikazioaren logotipoa"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Berretsi"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Saiatu berriro"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Sakatu hau autentifikazioa bertan behera uzteko"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ez dago sarerik erabilgarri"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ez dago Wi-Fi sarerik erabilgarri"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Aktibatzen…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Pantaila igortzeko aukera"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Igorri"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Igortzen"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Izenik gabeko gailua"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ez dago gailurik erabilgarri"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Esku bakarreko modua"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastea"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Arrunta"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Tartekoa"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Altua"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Entzumen-gailuak"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Entzumen-gailuak"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parekatu beste gailu bat"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pertsonalizatu widgetak"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Desgaitutako widgetaren aplikazio-ikonoa"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Instalatzen ari den widget bati dagokion aplikazioaren ikonoa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editatu widgeta"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Desaktibatu honen audioa: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Aktibatu honen audioa: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"audioa desaktibatuta dauka"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"dardara"</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">"Audioak abian jarraituko du hemen:"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Honen bidez deitzen"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d21fdd3..94befe4 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ارسال"</string>
<string name="cancel" msgid="1089011503403416730">"لغو"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"نشانواره برنامه"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"تأیید"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"امتحان مجدد"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"برای لغو راستیآزمایی ضربه بزنید"</string>
@@ -203,7 +205,7 @@
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"«قفلگشایی با چهره» راهاندازی نشد. برای امتحان مجدد، به «تنظیمات» بروید."</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"حسگر اثر انگشت را لمس کنید"</string>
<string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"برای ادامه، نماد قفلگشایی را فشار دهید"</string>
- <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"چهره شناسایی نشد، از اثر انگشت استفاده کنید."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
<skip />
<string name="keyguard_face_failed" msgid="2346762871330729634">"چهره شناسایی نشد"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"شبکه دردسترس نیست"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"هیچ شبکه Wi-Fi موجود نیست"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"روشن کردن…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"فرستادن محتوای صفحه"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"پخش محتوا"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"در حال فرستادن"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"دستگاه بدون نام"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"دستگاهی موجود نیست"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"باتری"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت یکدستی"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"تضاد"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"استاندارد"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"بالا"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سمعک"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سمعک"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"جفت کردن دستگاه جدید"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشیسازی ابزارکها، فشار طولانی دهید"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"سفارشیسازی ابزارکها"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"نماد برنامه برای ابزارک غیرفعال"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"نماد برنامه مربوط به ابزارکی که درحال نصب است"</string>
<string name="edit_widget" msgid="9030848101135393954">"ویرایش ابزارک"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"بیصدا کردن %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"باصدا کردن %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"بیصدا شد"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"لرزش"</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_ongoing_call" msgid="208426888064112006">"تماس برقرار است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 8910bf3..08c7adb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Lähetä"</string>
<string name="cancel" msgid="1089011503403416730">"Peru"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Sovelluksen logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Vahvista"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Yritä uudelleen"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Peru todennus napauttamalla"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ei verkkoja käytettävissä"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ei Wi-Fi-verkkoja käytettävissä"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Otetaan käyttöön…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Näytön striimaus"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Suoratoisto"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Lähetetään"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nimetön laite"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Laitteita ei ole käytettävissä"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Akku"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasti"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavallinen"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Keskitaso"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Suuri"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuulolaitteet"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuulolaitteet"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Muodosta uusi laitepari"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Muokkaa widgettejä"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Käytöstä poistetun widgetin sovelluskuvake"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Sovelluskuvake widgetin asentamisesta"</string>
<string name="edit_widget" msgid="9030848101135393954">"Muokkaa widgetiä"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mykistä %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Poista mykistys: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"mykistetty"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"värinä"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Puhelu kesken:"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index df5f59f..59b9e42 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Envoyer"</string>
<string name="cancel" msgid="1089011503403416730">"Annuler"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo de l\'application"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmer"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Réessayer"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Touchez ici pour annuler l\'authentification"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Aucun réseau accessible"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Aucun réseau Wi-Fi à proximité"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activation en cours…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Diffusion de l\'écran"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Diffuser"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Diffusion"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Appareil sans nom"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil à proximité"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Pile"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Moyen"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Élevé"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'application pour un widget désactivé"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icône d\'appli indiquant qu\'un widget est en cours d\'installation"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Désactivez le son de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Réactivez le son de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"son désactivé"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibration"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Appel en cours"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b02d547..79f70af 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Envoyer"</string>
<string name="cancel" msgid="1089011503403416730">"Annuler"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo de l\'appli"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmer"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Réessayer"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Appuyer pour annuler l\'authentification"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Réseaux non disponibles"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Aucun réseau Wi-Fi disponible"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activation…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Diffusion écran"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Caster"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Diffusion"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Appareil sans nom"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil disponible."</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batterie"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Moyen"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Élevé"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'appli du widget désactivé"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icône d\'application indiquant qu\'un widget est en cours d\'installation"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Couper le son de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Réactiver le son de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"son coupé"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibreur"</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">"Lecture audio sur"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Appel défini sur"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 8e2a011..fe2f112 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotipo da aplicación"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tentar de novo"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toca para cancelar a autenticación"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Non hai redes dispoñibles"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Non hai redes wifi dispoñibles"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emitir pantalla"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Emisión"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Emitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sen nome"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Non hai dispositivos dispoñibles"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batería"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Nivel estándar"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Nivel medio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Nivel alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo novo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona da aplicación de widget desactivado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona da aplicación para un widget que se está instalando"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string>
@@ -618,7 +615,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Control de ruído"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Audio espacial"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Desactivar"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fixo"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fixado"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seguimento da cabeza"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar o modo de timbre"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Silenciar %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Activar o son de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenciouse"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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">"Reproducirase en"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chamada en curso"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c0f6be9..299598f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"મોકલો"</string>
<string name="cancel" msgid="1089011503403416730">"રદ કરો"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ઍપનો લોગો"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"કન્ફર્મ કરો"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ફરી પ્રયાસ કરો"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"પ્રમાણીકરણ રદ કરવા માટે ટૅપ કરો"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"નેટવર્ક અનુપલબ્ધ છે"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"કોઈ વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ નથી"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ચાલુ કરી રહ્યાં છીએ…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"સ્ક્રીન કાસ્ટ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"કાસ્ટ કરો"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"કાસ્ટ કરી રહ્યાં છે"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"અનામાંકિત ઉપકરણ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"કોઈ ઉપકરણો ઉપલબ્ધ નથી"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"બૅટરી"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"એક-હાથે વાપરો મોડ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"કોન્ટ્રાસ્ટ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"સ્ટૅન્ડર્ડ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"મધ્યમ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"વધુ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"વિજેટ કસ્ટમાઇઝ કરો"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"બંધ કરેલા વિજેટ માટેની ઍપનું આઇકન"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ઇન્સ્ટૉલ થઈ રહેલા વિજેટ માટે ઍપનું આઇકન"</string>
<string name="edit_widget" msgid="9030848101135393954">"વિજેટમાં ફેરફાર કરો"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%sને મ્યૂટ કરો"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%sને અનમ્યૂટ કરો"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"મ્યૂટ કરી છે"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"વાઇબ્રેટ"</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_ongoing_call" msgid="208426888064112006">"કૉલ ચાલુ છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 4cf74b5..4c34814 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"भेजें"</string>
<string name="cancel" msgid="1089011503403416730">"रद्द करें"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ऐप्लिकेशन का लोगो"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"पुष्टि करें"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"फिर से कोशिश करें"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"पुष्टि की प्रक्रिया रद्द करने के लिए टैप करें"</string>
@@ -168,7 +170,7 @@
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"पुष्टि हो गई"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"पुष्टि करने की प्रोसेस को रद्द करें"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"ज़्यादा विकल्प"</string>
- <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन इस्तेमाल करें"</string>
+ <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन का इस्तेमाल करें"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पैटर्न इस्तेमाल करें"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"पासवर्ड इस्तेमाल करें"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"गलत पिन"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध नहीं हैं"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"कोई भी वाई-फ़ाई नेटवर्क उपलब्ध नहीं है"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"वाई-फ़ाई चालू हो रहा है…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"स्क्रीन कास्ट"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"कास्ट करें"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"कास्टिंग"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"अनाम डिवाइस"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोई डिवाइस उपलब्ध नहीं"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"बैटरी"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"वन-हैंडेड मोड"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"कंट्रास्ट"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"स्टैंडर्ड"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"सामान्य"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ज़्यादा"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"कान की मशीनें"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट अपनी पसंद के मुताबिक बनाएं"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद किए गए विजेट के लिए ऐप्लिकेशन आइकॉन"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इंस्टॉल हो रहे विजेट के लिए ऐप्लिकेशन आइकॉन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट में बदलाव करें"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s को म्यूट करें"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s को अनम्यूट करें"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"म्यूट किया गया"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"वाइब्रेट"</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_ongoing_call" msgid="208426888064112006">"कॉल चालू है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b211c94..5b5bddc 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Pošalji"</string>
<string name="cancel" msgid="1089011503403416730">"Odustani"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip aplikacije"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdi"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Pokušaj ponovo"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Dodirnite da biste otkazali autentifikaciju"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nije dostupna nijedna Wi-Fi mreža"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Uključivanje…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Emitiranje zaslona"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Emitiranje"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Emitiranje"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Uređaj bez naziva"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterija"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoki"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušna pomagala"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi widgete"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za widget koji se instalira"</string>
<string name="edit_widget" msgid="9030848101135393954">"Uredi widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Isključi zvuk za %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Uključi zvuk za %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"isključen zvuk"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibriranje"</string>
<string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> se reproducira na"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk će se reproducirati na"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Pozivanje na uređaju"</string>
@@ -892,10 +885,10 @@
<string name="finder_active" msgid="7907846989716941952">"Telefon možete pronaći pomoću usluge Pronađi moj uređaj čak i kada je isključen"</string>
<string name="shutdown_progress" msgid="5464239146561542178">"Isključivanje…"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pročitajte upute za održavanje"</string>
- <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte što trebate učiniti"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Iskopčajte uređaj"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Vaš se uređaj zagrijava u blizini priključka za punjenje. Ako je priključen u punjač ili USB uređaj, iskopčajte ga. Pazite jer se i kabel možda zagrijao."</string>
- <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upute za održavanje"</string>
+ <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte što trebate učiniti"</string>
<string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lijevi prečac"</string>
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desni prečac"</string>
<string name="lockscreen_unlock_left" msgid="1417801334370269374">"Lijevi prečac također otključava"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e736537..a2cf7b2 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Küldés"</string>
<string name="cancel" msgid="1089011503403416730">"Mégse"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Alkalmazás emblémája"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Megerősítés"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Újrapróbálkozás"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Koppintson a hitelesítés visszavonásához"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nem használhatók hálózatok"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nincs elérhető Wi-Fi-hálózat"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Bekapcsolás…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Képernyőátküldés"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Tartalomátküldés"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Átküldés"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Név nélküli eszköz"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nem áll rendelkezésre eszköz"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Akkumulátor"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontraszt"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Normál"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Közepes"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Nagy"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hallókészülékek"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hallókészülékek"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Új eszköz párosítása"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Modulok személyre szabása"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Letiltott modul alkalmazásikonja"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Folyamatban van egy modul alkalmazásikonjának telepítése"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modul szerkesztése"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s némítása"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s némításának feloldása"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"elnémítva"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"rezgés"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Hívás folyamatban itt:"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 6a905c5..b0f4848 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Ուղարկել"</string>
<string name="cancel" msgid="1089011503403416730">"Չեղարկել"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Հավելվածի լոգո"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Հաստատել"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Նորից փորձել"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Հպեք՝ նույնականացումը չեղարկելու համար"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Անհասանելի ցանցեր"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Հասանելի Wi-Fi ցանցեր չկան"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Միացում…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Էկրանի հեռարձակում"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Հեռարձակում"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Հեռարձակում"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Անանուն սարք"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Հասանելի սարքեր չկան"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Մարտկոց"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Մեկ ձեռքի ռեժիմ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Կոնտրաստ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Սովորական"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Միջին"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Բարձր"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Լսողական սարքեր"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Լսողական սարքեր"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Նոր սարքի զուգակցում"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Հարմարեցնել վիջեթները"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Հավելվածի պատկերակ անջատված վիջեթի համար"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Տեղադրվող վիջեթի հավելվածի պատկերակ"</string>
<string name="edit_widget" msgid="9030848101135393954">"Փոփոխել վիջեթը"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Անջատել ձայնը (%s)"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Միացնել ձայնը (%s)"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ձայնն անջատված է"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"թրթռոց"</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_ongoing_call" msgid="208426888064112006">"Զանգն ընթացքում է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 23d8397..a0795dc 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Kirim"</string>
<string name="cancel" msgid="1089011503403416730">"Batal"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo aplikasi"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Konfirmasi"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Coba lagi"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Ketuk untuk membatalkan autentikasi"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Jaringan tidak tersedia"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Tidak ada jaringan Wi-Fi yang tersedia"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Mengaktifkan…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transmisi Layar"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Melakukan transmisi"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Perangkat tanpa nama"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Perangkat tak tersedia"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterai"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standar"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sedang"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon aplikasi untuk widget yang dinonaktifkan"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikon aplikasi untuk widget yang sedang diinstal"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sesuaikan widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget di layar kunci"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pilih widget"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"hapus widget"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"letakkan widget yang dipilih"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string>
@@ -631,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Membisukan %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Membunyikan %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"dibisukan"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"getar"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Menelepon di"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 2c77eb1..f32f6a6 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Senda"</string>
<string name="cancel" msgid="1089011503403416730">"Hætta við"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Lógó forrits"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Staðfesta"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Reyna aftur"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Ýttu til að hætta við auðkenningu"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Net er ekki tiltækt"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Engin Wi-Fi net í boði"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Kveikir…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Skjáútsending"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Útsending"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Sendir út"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Ónefnt tæki"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Engin tæki til staðar"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Rafhlaða"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Birtuskil"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Staðlað"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Miðlungs"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Mikið"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Heyrnartæki"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Heyrnartæki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Para nýtt tæki"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sérsníða græjur"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Forritstákn fyrir græju sem slökkt er á"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Forritatákn fyrir græju sem verið er að setja upp"</string>
<string name="edit_widget" msgid="9030848101135393954">"Breyta græju"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Þagga %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Kveikja á hljóði %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"þaggað"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"titringur"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Símtal í gangi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 056c286..1988459 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Invia"</string>
<string name="cancel" msgid="1089011503403416730">"Annulla"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo dell\'app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Conferma"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Riprova"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tocca per annullare l\'autenticazione"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Reti non disponibili"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nessuna rete Wi-Fi disponibile"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Attivazione…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Trasmissione schermo"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Trasmetti"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"In trasmissione"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo senza nome"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nessun dispositivo disponibile"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batteria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrasto"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizza widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona dell\'app per widget disattivati"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Icona dell\'app per un widget in fase di installazione"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifica widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizza widget"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget su schermata di blocco"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleziona widget"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"rimuovi widget"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"posiziona il widget selezionato"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
@@ -631,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Silenzia %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Riattiva audio di %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"silenziato"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrazione"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Chiamata in corso"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6670b09..d31a95d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"שליחה"</string>
<string name="cancel" msgid="1089011503403416730">"ביטול"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"לוגו של האפליקציה"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"אישור"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ניסיון נוסף"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"יש להקיש כדי לבטל את האימות"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"אין רשתות זמינות"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"אין רשתות Wi-Fi זמינות"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"בתהליך הפעלה…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"הפעלת Cast למסך"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"העברה (cast)"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"מופעל Cast"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"מכשיר ללא שם"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"אין מכשירים זמינים"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"סוללה"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"מצב שימוש ביד אחת"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ניגודיות"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"רגילה"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"בינונית"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"גבוהה"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"מכשירי שמיעה"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"מכשירי שמיעה"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"התאמה של מכשיר חדש"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"התאמה אישית של ווידג\'טים"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"סמל האפליקציה לווידג\'ט שהושבת"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"סמל האפליקציה של ווידג\'ט בתהליך התקנה"</string>
<string name="edit_widget" msgid="9030848101135393954">"עריכת הווידג\'ט"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"התאמה אישית של ווידג\'טים"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ווידג\'טים במסך הנעילה"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"צריך לבחור ווידג\'ט"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"הסרת הווידג\'ט"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"צריך למקם את הווידג\'ט שנבחר"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
@@ -631,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"השתקה של %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"ביטול ההשתקה של %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"השתקה"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"רטט"</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_ongoing_call" msgid="208426888064112006">"מתבצעת שיחה במכשיר"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e3c0dbc..bff8487 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"送信"</string>
<string name="cancel" msgid="1089011503403416730">"キャンセル"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"アプリのロゴ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"確認"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"再試行"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"タップすると認証をキャンセルします"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"利用できるネットワークがありません"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fiネットワークを利用できません"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ON にしています…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"画面のキャスト"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"キャスト"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"キャストしています"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"名前のないデバイス"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"利用可能なデバイスがありません"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"バッテリー"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"片手モード"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"コントラスト"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"補聴器"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"補聴器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"新しいデバイスとペア設定"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ウィジェットのカスタマイズ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"無効なウィジェットのアプリアイコン"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"インストール中のウィジェットのアプリアイコン"</string>
<string name="edit_widget" msgid="9030848101135393954">"ウィジェットを編集"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s をミュート"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s のミュートを解除"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ミュート中"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"バイブレーション"</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_ongoing_call" msgid="208426888064112006">"通話中"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 0251ac0..51ba080 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"გაგზავნა"</string>
<string name="cancel" msgid="1089011503403416730">"გაუქმება"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"აპის ლოგო"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"დადასტურება"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ხელახლა ცდა"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"შეეხეთ ავტორიზაციის გასაუქმებლად"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ქსელები მიუწვდომელია"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi ქსელები მიუწვდომელია"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ირთვება…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ეკრანის გადაცემა"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ტრანსლირება"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"გადაიცემა"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"უსახელო მოწყობილობა"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"მოწყობილობები მიუწვდომელია"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ბატარეა"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ცალი ხელის რეჟიმი"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"კონტრასტი"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"სტანდარტული"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"საშუალო"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"მაღალი"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"სმენის აპარატები"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"სმენის აპარატები"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ახალი მოწყობილობის დაწყვილება"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ვიჯეტების მორგება"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"აპის ხატულა გათიშული ვიჯეტისთვის"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ინსტალაციის პროცესში მყოფი ვიჯეტის აპის ხატულა"</string>
<string name="edit_widget" msgid="9030848101135393954">"ვიჯეტის რედაქტირება"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s-ის დადუმება"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s-ის დადუმების მოხსნა"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"დადუმებული"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ვიბრაცია"</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_ongoing_call" msgid="208426888064112006">"მიმდინარეობს ზარი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 9c96a4e..27c8512 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Жіберу"</string>
<string name="cancel" msgid="1089011503403416730">"Бас тарту"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Қолданба логотипі"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Растау"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Қайта көру"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Аутентификациядан бас тарту үшін түртіңіз."</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Желілер қолжетімді емес."</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Қолжетімді Wi-Fi желілері жоқ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Қосылып жатыр…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Экранды трансляциялау"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Трансляция"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Трансляциялануда"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Атаусыз құрылғы"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Құрылғылар қол жетімді емес"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батарея"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бір қолмен басқару режимі"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартты режим"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Орташа"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Жоғары"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Есту құрылғылары"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерді реттеу"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өшірілген виджеттің қолданба белгішесі"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджетке арналған қолдана белгішесі орнатылып жатыр."</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетті өзгерту"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s дыбысын өшіру"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s дыбысын қосу"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"дыбысы өшірілді"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"дірілдету"</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_ongoing_call" msgid="208426888064112006">"Қоңырау шалып жатыр"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index dc9a747..bd0bf98 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ផ្ញើ"</string>
<string name="cancel" msgid="1089011503403416730">"បោះបង់"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"និមិត្តសញ្ញាកម្មវិធី"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"បញ្ជាក់"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ព្យាយាមម្ដងទៀត"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ចុចដើម្បីបោះបង់ការផ្ទៀងផ្ទាត់"</string>
@@ -201,7 +203,7 @@
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"រៀបចំការដោះសោដោយស្កេនមុខ"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"ដើម្បីរៀបចំដោះសោតាមទម្រង់មុខម្ដងទៀត គំរូមុខបច្ចុប្បន្នរបស់អ្នកនឹងត្រូវបានលុប។\n\nអ្នកនឹងត្រូវរៀបចំមុខងារនេះម្ដងទៀត ដើម្បីប្រើមុខរបស់អ្នកសម្រាប់ដោះសោទូរសព្ទរបស់អ្នក។"</string>
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"មិនអាចរៀបចំការដោះសោតាមទម្រង់មុខបានទេ។ សូមចូលទៅកាន់ការកំណត់ ដើម្បីព្យាយាមម្ដងទៀត។"</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះសេនស័រចាប់ស្នាមម្រាមដៃ"</string>
<string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"សូមចុចរូបដោះសោ ដើម្បីបន្ត"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"មិនស្គាល់មុខទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"មិនអាចប្រើបណ្តាញបានទេ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"គ្មានបណ្តាញ Wi-Fi ទេ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"កំពុងបើក..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ការបញ្ចាំងអេក្រង់"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ភ្ជាប់"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ការចាត់ថ្នាក់"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ឧបករណ៍ដែលមិនមានឈ្មោះ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"មិនមានឧបករណ៍ដែលអាចប្រើបាន"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ថ្ម"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"មុខងារប្រើដៃម្ខាង"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"កម្រិតរំលេចពណ៌"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ស្តង់ដារ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"មធ្យម"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ខ្ពស់"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុចឱ្យយូរ ដើម្បីប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"រូបកម្មវិធីសម្រាប់ធាតុក្រាហ្វិកដែលបានបិទ"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"រូបតំណាងកម្មវិធីសម្រាប់ធាតុក្រាហ្វិកកំពុងត្រូវបានដំឡើង"</string>
<string name="edit_widget" msgid="9030848101135393954">"កែធាតុក្រាហ្វិក"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុក្រាហ្វិក"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"បិទសំឡេង %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"បើកសំឡេង %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"បានបិទសំឡេង"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ញ័រ"</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_ongoing_call" msgid="208426888064112006">"កំពុងនិយាយទូរសព្ទ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 46a679c..bc7ab50 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ಕಳುಹಿಸಿ"</string>
<string name="cancel" msgid="1089011503403416730">"ರದ್ದುಮಾಡಿ"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ಆ್ಯಪ್ ಲೋಗೋ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"ದೃಢೀಕರಿಸಿ"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ದೃಢೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"ಯಾವುದೇ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ಸ್ಕ್ರೀನ್ ಕ್ಯಾಸ್ಟ್"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ಬಿತ್ತರಿಸುವಿಕೆ"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ಹೆಸರಿಸದಿರುವ ಸಾಧನ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ಯಾವುದೇ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ಬ್ಯಾಟರಿ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ಒಂದು ಕೈ ಮೋಡ್"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ಕಾಂಟ್ರಾಸ್ಟ್"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ಪ್ರಮಾಣಿತ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ಮಧ್ಯಮ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ಹೆಚ್ಚು"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ವಿಜೆಟ್ಗಾಗಿ ಆ್ಯಪ್ ಐಕಾನ್"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ವಿಜೆಟ್ಗಾಗಿ ಆ್ಯಪ್ ಐಕಾನ್"</string>
<string name="edit_widget" msgid="9030848101135393954">"ವಿಜೆಟ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ಮ್ಯೂಟ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ವೈಬ್ರೇಟ್"</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_ongoing_call" msgid="208426888064112006">"ಕರೆ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 54dcfce..0e6f9bf 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"보내기"</string>
<string name="cancel" msgid="1089011503403416730">"취소"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"앱 로고"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"확인"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"다시 시도하세요."</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"탭하여 인증 취소"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"네트워크 사용 불가"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"사용 가능한 Wi-Fi 네트워크 없음"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"켜는 중..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"화면 전송"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"전송 중"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"이름이 없는 기기"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"사용 가능한 기기가 없습니다."</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"배터리"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"대비"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"표준"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"보통"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"높음"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"청각 보조 기기"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"청각 보조 기기"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"새 기기와 페어링"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"위젯 맞춤설정"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"사용 중지된 위젯의 앱 아이콘"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"설치 중인 위젯의 앱 아이콘"</string>
<string name="edit_widget" msgid="9030848101135393954">"위젯 수정"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s 음소거"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s 음소거 해제"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"음소거됨"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"진동"</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_ongoing_call" msgid="208426888064112006">"전화 거는 중"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index a224ac7..383a8e1 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -49,7 +49,7 @@
<string name="label_view" msgid="6815442985276363364">"Карап көрүү"</string>
<string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> туташып турганда, <xliff:g id="APPLICATION">%1$s</xliff:g> ар дайым ачык болсун"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> туташып турганда, <xliff:g id="APPLICATION">%1$s</xliff:g> ар дайым ачык болсун"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"USB аркылуу жөндөөгө уруксат берилсинби?"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"USB аркылуу жөндөөгө уруксат бересизби?"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"Компүтердин RSA ачкычынын контролдук суммасы:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Бул компүтерден дайыма уруксат берилсин"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Ооба"</string>
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Жөнөтүү"</string>
<string name="cancel" msgid="1089011503403416730">"Баш тартуу"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Колдонмонун логотиби"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Ырастоо"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Кайталоо"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Аныктыгын текшерүүнү жокко чыгаруу үчүн таптаңыз"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Тармактар жеткиликсиз"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Бир дагы жеткиликтүү Wi-Fi тармагы жок"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Күйгүзүлүүдө…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Тышкы экранга чыгаруу"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Тышкы экранга чыгаруу"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Тышкы экранга чыгарылууда"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Аты жок түзмөк"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Жеткиликтүү түзмөктөр жок"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батарея"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бир кол режими"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Кадимки"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Орточо"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Жогору"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Угуу аппараттары"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Угуу аппараттары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңы түзмөк кошуу"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерди ыңгайлаштыруу"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өчүрүлгөн виджет үчүн колдонмонун сүрөтчөсү"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджет үчүн колдонмонун сүрөтчөсү орнотулууда"</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетти түзөтүү"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s үнүн басуу"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s үнүн чыгаруу"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"үнсүз"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"дирилдөө"</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_ongoing_call" msgid="208426888064112006">"Чалууда"</string>
@@ -944,7 +937,7 @@
<string name="auto_data_switch_dialog_negative_button" msgid="2370876875999891444">"Жок, рахмат"</string>
<string name="auto_data_switch_dialog_positive_button" msgid="8531782041263087564">"Ооба, которулам"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Уруксат берүү сурамыңыз көрүнбөй калгандыктан, Параметрлер жообуңузду ырастай албай жатат."</string>
- <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
+ <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат бересизби?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунда аракеттерди аткарат"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"<xliff:g id="APP">%1$s</xliff:g> бардык колдонмолордун үлгүлөрүн көрсөтүүгө уруксат берүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 88866e3..a136976 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ສົ່ງ"</string>
<string name="cancel" msgid="1089011503403416730">"ຍົກເລີກ"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ໂລໂກ້ແອັບ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"ຢືນຢັນ"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ລອງໃໝ່"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ແຕະເພື່ອຍົກເລີກການກວດສອບຄວາມຖືກຕ້ອງ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ບໍ່ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"ບໍ່ມີເຄືອຂ່າຍ Wi-Fi ຢູ່"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ກຳລັງເປີດ..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ການສົ່ງສັນຍານໜ້າຈໍ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ການສົ່ງສັນຍານ"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ກຳລັງສົ່ງສັນຍານ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ອຸປະກອນບໍ່ມີຊື່"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ບໍ່ມີອຸປະກອນທີ່ສາມາດໃຊ້ໄດ້"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ແບັດເຕີຣີ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ໂໝດມືດຽວ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ຄອນທຣາສ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ມາດຕະຖານ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ປານກາງ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ສູງ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ປັບແຕ່ງວິດເຈັດ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ໄອຄອນແອັບສຳລັບວິດເຈັດທີ່ຖືກປິດການນຳໃຊ້"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ກຳລັງຕິດຕັ້ງໄອຄອນແອັບສຳລັບວິດເຈັດ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ແກ້ໄຂວິດເຈັດ"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string>
@@ -619,7 +616,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"ສຽງຮອບທິດທາງ"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"ປິດ"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ຄົງທີ່"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ການຕິດຕາມການເຄື່ອນໄຫວຂອງຫົວ"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ການຕິດຕາມຫົວ"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"ແຕະເພື່ອປ່ຽນໂໝດຣິງເກີ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"ປິດສຽງ %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"ເຊົາປິດສຽງ %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ປິດສຽງແລ້ວ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ສັ່ນເຕືອນ"</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_ongoing_call" msgid="208426888064112006">"ກຳລັງໂທ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 46ac304..96be8e2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Siųsti"</string>
<string name="cancel" msgid="1089011503403416730">"Atšaukti"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Programos logotipas"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Patvirtinkite"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Bandyti dar kartą"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Palieskite, jei norite atšaukti autentifikavimą"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tinklai nepasiekiami"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nėra jokių pasiekiamų „Wi-Fi“ tinklų"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Įjungiama…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekrano perdavimas"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Perdavimas"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Perduodama"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Įrenginys be pavadinimo"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nėra pasiekiamų įrenginių"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Akumuliatorius"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastas"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Įprastas"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vidutinis"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Aukštas"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Klausos įrenginiai"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Klausos įrenginiai"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Susieti naują įrenginį"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tinkinti valdiklius"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Išjungto valdiklio programos piktograma"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Įdiegiamo valdiklio programos piktograma"</string>
<string name="edit_widget" msgid="9030848101135393954">"Redaguoti valdiklį"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Nutildyti: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Įjungti garsą: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"nutildyta"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibruoti"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Skambinama"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 979f59e..b8a5476 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Sūtīt"</string>
<string name="cancel" msgid="1089011503403416730">"Atcelt"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Lietotnes logotips"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Apstiprināt"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Mēģināt vēlreiz"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Pieskarieties, lai atceltu autentifikāciju."</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tīkli nav pieejami"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nav pieejams neviens Wi-Fi tīkls."</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Notiek ieslēgšana…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekrāna apraide"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Apraide"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Notiek apraide…"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nenosaukta ierīce"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nav pieejamu ierīču."</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Akumulators"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasts"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standarta"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vidējs"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Augsts"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienot pārī jaunu ierīci"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pielāgot logrīkus"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Lietotnes ikona atspējotam logrīkam"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Tiek instalēta lietotnes ikona logrīkam."</string>
<string name="edit_widget" msgid="9030848101135393954">"Rediģēt logrīku"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Izslēgt skaņu: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Ieslēgt skaņu: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"izslēgta skaņa"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"iestatīta vibrācija"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Aktīvs zvans ierīcē"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e305c9e..2e0edbe 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Испрати"</string>
<string name="cancel" msgid="1089011503403416730">"Откажи"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Лого на апликацијата"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Потврди"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Обиди се повторно"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Допрете за да ја откажете проверката"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Не се достапни мрежи"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Нема достапни Wi-Fi мрежи"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Се вклучува…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Емитување екран"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Емитување"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Емитување"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Неименуван уред"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нема достапни уреди"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батерија"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим со една рака"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандарден"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Среден"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Висок"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спари нов уред"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Приспособете ги виџетите"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона за апликација за оневозможен виџет"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона за апликација за виџет што се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Изменување виџети"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Приспособете ги виџетите"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виџети на заклучен екран"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"изберете виџет"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"отстранете го виџетот"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"поставете го избраниот виџет"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијава ќе се избришат."</string>
@@ -631,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"исклучување звук на %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"вклучување звук на %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"придушено"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вибрации"</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_ongoing_call" msgid="208426888064112006">"Повик во тек"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index c14cc41..ad7d723 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -20,9 +20,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"സിസ്റ്റം UI"</string>
- <string name="battery_low_title" msgid="5319680173344341779">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
- <string name="battery_low_description" msgid="3282977755476423966">"നിങ്ങളുടെ ബാറ്ററിയിൽ <xliff:g id="PERCENTAGE">%s</xliff:g> ചാർജ് ശേഷിക്കുന്നു. ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
- <string name="battery_low_intro" msgid="5148725009653088790">"ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ബാറ്ററി സേവർ ഓണാക്കണോ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"നിങ്ങളുടെ ബാറ്ററിയിൽ <xliff:g id="PERCENTAGE">%s</xliff:g> ചാർജ് ശേഷിക്കുന്നു. ബാറ്ററി സേവർ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ബാറ്ററി സേവർ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB വഴി ചാർജ് ചെയ്യാനാകില്ല"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ഉപകരണത്തിനൊപ്പം ലഭിച്ച ചാർജർ ഉപയോഗിക്കുക"</string>
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"അയയ്ക്കുക"</string>
<string name="cancel" msgid="1089011503403416730">"റദ്ദാക്കുക"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ആപ്പ് ലോഗോ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"സ്ഥിരീകരിക്കുക"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"വീണ്ടും ശ്രമിക്കുക"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"നെറ്റ്വർക്കുകൾ ലഭ്യമല്ല"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"വൈഫൈ നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ഓണാക്കുന്നു…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"സ്ക്രീൻ കാസ്റ്റ്"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"കാസ്റ്റുചെയ്യുക"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"കാസ്റ്റുചെയ്യുന്നു"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"പേരിടാത്ത ഉപകരണം"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
@@ -338,7 +340,7 @@
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ഡാർക്ക് തീം"</string>
- <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"ബാറ്ററി ലാഭിക്കൽ"</string>
+ <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"ബാറ്ററി സേവർ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"സൂര്യാസ്തമയത്തിന്"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"സൂര്യോദയം വരെ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ബാറ്ററി"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ഒറ്റക്കൈ മോഡ്"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"കോൺട്രാസ്റ്റ്"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"സ്റ്റാൻഡേർഡ്"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ഇടത്തരം"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"കൂടുതൽ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"പ്രവർത്തനരഹിതമാക്കിയ വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ ഇൻസ്റ്റാൾ ചെയ്തു"</string>
<string name="edit_widget" msgid="9030848101135393954">"വിജറ്റ് എഡിറ്റ് ചെയ്യുക"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s മ്യൂട്ട് ചെയ്യുക"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s അൺമ്യൂട്ട് ചെയ്യുക"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"മ്യൂട്ട് ചെയ്തു"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"വൈബ്രേറ്റ് ചെയ്യുക"</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_ongoing_call" msgid="208426888064112006">"കോൾ പുരോഗമിക്കുന്നു"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 573c8ff..fb3531f 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Илгээх"</string>
<string name="cancel" msgid="1089011503403416730">"Цуцлах"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Аппын лого"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Баталгаажуулах"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Дахин оролдох"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Нотолгоог цуцлахын тулд товшино уу"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сүлжээ боломжгүй"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi сүлжээ байхгүй байна"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Асааж байна…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Дэлгэцийг дамжуулах"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Дамжуулах"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Дамжуулж байна"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Нэргүй төхөөрөмж"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Төхөөрөмж байхгүй"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батарей"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Нэг гарын горим"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Ялгарал"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандарт"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Дунд зэрэг"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Өндөр"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Сонсголын төхөөрөмжүүд"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Сонсголын төхөөрөмжүүд"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Шинэ төхөөрөмж хослуулах"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджетүүдийг өөрчлөх"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Идэвхгүй болгосон виджетийн аппын дүрс тэмдэг"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Виджет суулгах явцын аппын дүрс тэмдэг"</string>
<string name="edit_widget" msgid="9030848101135393954">"Виджетийг засах"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s-н дууг хаах"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s-н дууг нээх"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"дууг хаасан"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"чичрэх"</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_ongoing_call" msgid="208426888064112006">"Дуудлага хийгдэж буй:"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3667f1e..249e7ac 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"पाठवा"</string>
<string name="cancel" msgid="1089011503403416730">"रद्द करा"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"अॅप लोगो"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"कन्फर्म करा"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"पुन्हा प्रयत्न करा"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ऑथेंटिकेशन रद्द करण्यासाठी टॅप करा"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध नाहीत"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"वाय-फाय नेटवर्क उपलब्ध नाहीत"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"सुरू करत आहे…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"स्क्रीन कास्ट"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"कास्ट करा"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"कास्ट करत आहे"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"निनावी डिव्हाइस"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोणतेही डिव्हाइसेस उपलब्ध नाहीत"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"बॅटरी"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एकहाती मोड"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"कॉंट्रास्ट"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"साधारण"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"श्रवणयंत्रे"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"श्रवणयंत्रे"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नवीन डिव्हाइस पेअर करा"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट कस्टमाइझ करा"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद केलेल्या विजेटच्या अॅपचे आयकन"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इंस्टॉल होत असलेल्या विजेटसाठी अॅपचा आयकन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट संपादित करा"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s म्यूट करा"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s अनम्यूट करा"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"म्यूट केले आहे"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"व्हायब्रेट करा"</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_ongoing_call" msgid="208426888064112006">"यावर कॉल करत आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 60aedfa..e21daa2 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Hantar"</string>
<string name="cancel" msgid="1089011503403416730">"Batal"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo apl"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Sahkan"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Cuba lagi"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Ketik untuk membatalkan pengesahan"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Rangkaian tidak tersedia"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Tiada rangkaian Wi-Fi tersedia"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Menghidupkan…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Penghantaran Skrin"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Hantar"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Menghantar"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Peranti tidak bernama"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Tiada peranti tersedia"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mod sebelah tangan"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sederhana"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Peranti pendengaran"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Peranti pendengaran"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Gandingkan peranti baharu"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon apl untuk melumpuhkan widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikon apl untuk widget yang sedang dipasang"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Redamkan %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Nyahredamkan %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"diredamkan"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"getar"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Membuat panggilan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index b7398d0..000d7d3 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ပို့ရန်"</string>
<string name="cancel" msgid="1089011503403416730">"မလုပ်တော့"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"အက်ပ်လိုဂို"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"အတည်ပြုရန်"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ထပ်စမ်းကြည့်ရန်"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်ရန် တို့ပါ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ကွန်ရက်များ မရနိုင်ပါ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi ကွန်ရက် မရှိပါ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ဖွင့်နေသည်…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"မျက်နှာပြင် ကာ့စ်လုပ်ခြင်း"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ကာစ်တင်"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"အမည်မတပ် ကိရိယာ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ကိရိယာများ မရှိ"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ဘက်ထရီ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"လက်တစ်ဖက်သုံးမုဒ်"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ဆန့်ကျင်ဘက်"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ပုံမှန်"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"အသင့်အတင့်"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"များ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"နားကြားကိရိယာ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"နားကြားကိရိယာ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"စက်အသစ်တွဲချိတ်ရန်"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ပိတ်ထားသော ဝိဂျက်အတွက် အက်ပ်သင်္ကေတ"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ထည့်သွင်းနေသော ဝိဂျက်အတွက် အက်ပ်သင်္ကေတ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ဝိဂျက်ပြင်ရန်"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s အသံပိတ်ရန်"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s အသံပြန်ဖွင့်ရန်"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"အသံပိတ်ထားသည်"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"တုန်ခါရန်"</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_ongoing_call" msgid="208426888064112006">"ဖုန်းဆက်နေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2b131c7..3fdb8f1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Send"</string>
<string name="cancel" msgid="1089011503403416730">"Avbryt"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Applogo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bekreft"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Prøv på nytt"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Trykk for å avbryte autentiseringen"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nettverk er utilgjengelige"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ingen tilgjengelige wifi-nettverk"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Slår på …"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Skjermcasting"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Enhet uten navn"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ingen enheter er tilgjengelige"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batteri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Middels"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Høy"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Koble til en ny enhet"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpass moduler"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktivert modul"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikon for en modul som installeres"</string>
<string name="edit_widget" msgid="9030848101135393954">"Endre modul"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Kutt lyden for %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Slå på lyden for %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"dempet"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrer"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Aktiv samtale på"</string>
@@ -891,8 +884,8 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskjerm"</string>
<string name="finder_active" msgid="7907846989716941952">"Du kan finne denne telefonen med Finn enheten min, selv når den er slått av"</string>
<string name="shutdown_progress" msgid="5464239146561542178">"Slår av …"</string>
- <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se vedlikeholdstrinnene"</string>
- <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se hva du kan gjøre"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se hva du kan gjøre"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Koble fra enheten"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Enheten begynner å bli varm nær ladeporten. Hvis den er koblet til en lader eller et USB-tilbehør, må du koble den fra. Vær forsiktig da kabelen også kan være varm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vedlikeholdstrinnene"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 42abd44..fe4b412 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"पठाउनुहोस्"</string>
<string name="cancel" msgid="1089011503403416730">"रद्द गर्नुहोस्"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"एपको लोगो"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"पुष्टि गर्नुहोस्"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"फेरि प्रयास गर्नुहोस्"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"प्रमाणीकरण रद्द गर्न ट्याप गर्नुहोस्"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध छैन"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi नेटवर्क अनुपलब्ध"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"सक्रिय गर्दै…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"स्क्रिन Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"प्रसारण गर्दै"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"बेनाम उपकरण"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कुनै उपकरणहरू उपलब्ध छैन"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ब्याट्री"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एक हाते मोड"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"कन्ट्रास्ट"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"डिफल्ट"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"हियरिङ डिभाइसहरू"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"हियरिङ डिभाइसहरू"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
@@ -403,7 +401,7 @@
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"तपाईंलाई अलार्म, रिमाइन्डर, कार्यक्रम र तपाईंले निर्दिष्ट गर्नुभएका कलरहरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"तपाईंलाई अलार्महरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
- <string name="zen_priority_customize_button" msgid="4119213187257195047">"आफू अनुकूल बनाउनुहोस्"</string>
+ <string name="zen_priority_customize_button" msgid="4119213187257195047">" कस्टम बनाउनुहोस्"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"यसले अलार्म, सङ्गीत, भिडियो, र खेलहरू लगायत सबैका ध्वनि र कम्पनहरूमाथि रोक लगाउँछ। तपाईं अझै पनि फोन कलहरू गर्न सक्नुहुनेछ।"</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"यसले अलार्म, सङ्गीत, भिडियोहरू र खेलहरूसहित सबै ध्वनिहरू र कम्पनहरूलाई रोक्छ।"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
@@ -433,7 +431,7 @@
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"पूरै\nशान्त"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"प्राथमिकता \nमात्र"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"अलार्महरू \nमात्र"</string>
- <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • तारविनै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
+ <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • वायरलेस तरिकाले चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरा चार्ज हुन्छ"</string>
<string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
<string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • छिटो चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • बिस्तारै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेटहरू कस्टमाइज गर्नुहोस्"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"अफ गरिएको विजेटको एप जनाउने आइकन"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"इन्स्टल भइरहेको विजेटको एप आइकन"</string>
<string name="edit_widget" msgid="9030848101135393954">"विजेट सम्पादन गर्नुहोस्"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s म्युट गर्नुहोस्"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s अनम्युट गर्नुहोस्"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"म्यूट गरिएको छ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"भाइब्रेट गर्नुहोस्"</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_ongoing_call" msgid="208426888064112006">"कल चलिरहेको छ"</string>
@@ -670,7 +663,7 @@
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"स्याटलाइट SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाइल"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"केहीका लागि रमाइलो हुन्छ तर सबैका लागि होइन"</string>
- <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनरले तपाईँलाई Android प्रयोगकर्ता इन्टरफेस आफू अनुकूल गर्न र ट्विक गर्न थप तरिकाहरू प्रदान गर्छ। यी प्रयोगात्मक सुविधाहरू भावी विमोचनमा परिवर्तन हुन, बिग्रिन वा हराउन सक्ने छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
+ <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनरले तपाईँलाई Android प्रयोगकर्ता इन्टरफेस कस्टम गर्न र ट्विक गर्न थप तरिकाहरू प्रदान गर्छ। यी प्रयोगात्मक सुविधाहरू भावी विमोचनमा परिवर्तन हुन, बिग्रिन वा हराउन सक्ने छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"यी प्रयोगात्मक सुविधाहरू भावी विमोचनहरूमा परिवर्तन हुन, बिग्रन वा हराउन सक्छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string>
<string name="got_it" msgid="477119182261892069">"बुझेँ"</string>
<string name="tuner_toast" msgid="3812684836514766951">"बधाईँ छ! सेटिङहरूमा सिस्टम UI ट्युनर थप गरिएको छ"</string>
@@ -715,7 +708,7 @@
<string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचना सम्बन्धी नियन्त्रणहरूलाई खोलियो"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचना सम्बन्धी नियन्त्रणहरूलाई बन्द गरियो"</string>
<string name="notification_more_settings" msgid="4936228656989201793">"थप सेटिङहरू"</string>
- <string name="notification_app_settings" msgid="8963648463858039377">"आफू अनुकूल पार्नुहोस्"</string>
+ <string name="notification_app_settings" msgid="8963648463858039377">" कस्टम पार्नुहोस्"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"बबल देखाउनुहोस्"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"बबलहरू हटाउनुहोस्"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index c459b93..add74db 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Verzenden"</string>
<string name="cancel" msgid="1089011503403416730">"Annuleren"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"App-logo"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bevestigen"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Opnieuw proberen"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tik om de verificatie te annuleren"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netwerken niet beschikbaar"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Geen wifi-netwerken beschikbaar"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Aanzetten…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screencast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Casten"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Casten"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Naamloos apparaat"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen apparaten beschikbaar"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batterij"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Bediening met 1 hand"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Gemiddeld"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hoortoestellen"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hoortoestellen"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Nieuw apparaat koppelen"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets aanpassen"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-icoon voor uitgezette widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App-icoon voor een widget die wordt geïnstalleerd"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget bewerken"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string>
@@ -463,10 +460,8 @@
<string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widgets aanpassen"</string>
<string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets op het vergrendelscherm"</string>
<string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"widget selecteren"</string>
- <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) -->
- <skip />
- <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) -->
- <skip />
+ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"widget verwijderen"</string>
+ <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"geselecteerde widget plaatsen"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
@@ -631,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Geluid van %s uitzetten"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Geluid van %s aanzetten"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"geluid uit"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"trillen"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Bellen actief"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 1444e6d..6a93557 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ପଠାନ୍ତୁ"</string>
<string name="cancel" msgid="1089011503403416730">"ବାତିଲ କରନ୍ତୁ"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ଆପ ଲୋଗୋ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ପ୍ରାମାଣିକତା ବାତିଲ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"କୌଣସି ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ଅନ୍ ହେଉଛି…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ସ୍କ୍ରିନ କାଷ୍ଟ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"କାଷ୍ଟ"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"କାଷ୍ଟିଙ୍ଗ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ନାମହୀନ ଡିଭାଇସ୍"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ବେଟେରୀ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ଏକ-ହାତ ମୋଡ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"କଣ୍ଟ୍ରାଷ୍ଟ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ଷ୍ଟାଣ୍ଡାର୍ଡ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ମଧ୍ୟମ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ଅଧିକ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କରନ୍ତୁ"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ଅକ୍ଷମ କରାଯାଇଥିବା ୱିଜେଟ ପାଇଁ ଆପ ଆଇକନ"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ଏକ ୱିଜେଟ ପାଇଁ ଆପ ଆଇକନକୁ ଇନଷ୍ଟଲ କରାଯାଉଛି"</string>
<string name="edit_widget" msgid="9030848101135393954">"ୱିଜେଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
@@ -618,7 +615,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ନଏଜ କଣ୍ଟ୍ରୋଲ"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"ସ୍ପାସିଅଲ ଅଡିଓ"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"ବନ୍ଦ ଅଛି"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ନିର୍ଦ୍ଦିଷ୍ଟ"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ନିଶ୍ଚିତ ହୋଇଛି"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ହେଡ ଟ୍ରାକିଂ"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"ରିଙ୍ଗର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%sକୁ ମ୍ୟୁଟ କରନ୍ତୁ"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%sକୁ ଅନମ୍ୟୁଟ କରନ୍ତୁ"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ମ୍ୟୁଟେଡ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ଭାଇବ୍ରେଟ୍"</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_ongoing_call" msgid="208426888064112006">"କଲ ଚାଲିଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 23914b3..c908618 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ਭੇਜੋ"</string>
<string name="cancel" msgid="1089011503403416730">"ਰੱਦ ਕਰੋ"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ਐਪ ਲੋਗੋ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"ਤਸਦੀਕ ਕਰੋ"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"ਕੋਈ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"ਸਕ੍ਰੀਨ ਕਾਸਟ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ਕਾਸਟ ਕਰੋ"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ਕਾਸਟਿੰਗ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"ਬਿਨਾਂ ਨਾਮ ਦਾ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ਕੋਈ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"ਬੈਟਰੀ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ਕੰਟ੍ਰਾਸਟ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ਮਿਆਰੀ"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ਦਰਮਿਆਨਾ"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ਜ਼ਿਆਦਾ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ਬੰਦ ਵਿਜੇਟ ਲਈ ਐਪ ਪ੍ਰਤੀਕ"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ਸਥਾਪਤ ਕੀਤੇ ਜਾ ਰਹੇ ਵਿਜੇਟ ਲਈ ਐਪ ਪ੍ਰਤੀਕ"</string>
<string name="edit_widget" msgid="9030848101135393954">"ਵਿਜੇਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s ਨੂੰ ਮਿਊਟ ਕਰੋ"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s ਨੂੰ ਅਣਮਿਊਟ ਕਰੋ"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ਮਿਊਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"ਥਰਥਰਾਹਟ"</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_ongoing_call" msgid="208426888064112006">"ਕਾਲ ਜਾਰੀ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4609f08..a13a1d6 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Wyślij"</string>
<string name="cancel" msgid="1089011503403416730">"Anuluj"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo aplikacji"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potwierdź"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Spróbuj jeszcze raz"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Kliknij, by anulować uwierzytelnianie"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Sieci niedostępne"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Brak dostępnych sieci Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Włączam…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Przesyłanie ekranu"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Przesyłanie"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Przesyłam"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Urządzenie bez nazwy"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Brak dostępnych urządzeń"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardowy"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Średni"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Wysoki"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Urządzenia słuchowe"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Urządzenia słuchowe"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sparuj nowe urządzenie"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Dostosuj widżety"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacji z wyłączonym widżetem"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacji instalowanego widżetu"</string>
<string name="edit_widget" msgid="9030848101135393954">"Edytuj widżet"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string>
@@ -629,14 +626,10 @@
<string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Otwórz ustawienia sygnału wyjściowego"</string>
<string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Suwaki głośności są rozwinięte"</string>
<string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Suwaki głośności są zwinięte"</string>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Wycisz: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Wyłącz wyciszenie: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"wyciszono"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"wibracje"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Odtwarzam <xliff:g id="LABEL">%s</xliff:g> na"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Wyjścia dźwięku:"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Dzwonię na:"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 425fa65..da72fd5 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotipo do app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tentar novamente"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toque para cancelar a autenticação"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nenhuma rede Wi-Fi disponível"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ativando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transmissão de tela"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Transmitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sem nome"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone do app para um widget que está sendo instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Desativar o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Ativar o som de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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">"Onde o áudio vai tocar?"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 4453133..1d9a8da 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logótipo da app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tentar novamente"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toque para cancelar a autenticação."</string>
@@ -201,7 +203,7 @@
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Configure o Desbloqueio facial"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Para configurar o Desbloqueio facial novamente, o seu modelo de rosto atual vai ser eliminado.\n\nVai ter de configurar novamente esta funcionalidade para desbloquear o telemóvel com o rosto."</string>
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Não foi possível configurar o Desbloqueio facial. Aceda às Definições para tentar novamente."</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais."</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais"</string>
<string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Prima o ícone de desbloqueio para continuar"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"Rosto não reconhecido. Use a impressão digital."</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Não estão disponíveis redes Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"A ativar..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transm. ecrã"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Transmissão"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sem nome"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Sem dispositivos disponíveis"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sincronizar novo dispositivo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha premido para personalizar os widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone da app do widget desativado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone da app para um widget que está a ser instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Desative o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Reative o som de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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">"Áudio ouvido em:"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chamada em curso"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 425fa65..da72fd5 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="cancel" msgid="1089011503403416730">"Cancelar"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotipo do app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmar"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tentar novamente"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Toque para cancelar a autenticação"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nenhuma rede Wi-Fi disponível"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ativando…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transmissão de tela"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Transmitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sem nome"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ícone do app para um widget que está sendo instalado"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Desativar o som de %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Ativar o som de %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</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">"Onde o áudio vai tocar?"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 596349e..f0f5987 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Trimite"</string>
<string name="cancel" msgid="1089011503403416730">"Anulează"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Sigla aplicației"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Confirmă"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Încearcă din nou"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Atinge pentru a anula autentificarea"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nu sunt disponibile rețele"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nicio rețea Wi-Fi disponibilă"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Se activează..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Proiectarea ecranului"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Proiectează"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Se proiectează"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispozitiv nedenumit"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Niciun dispozitiv disponibil"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterie"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mediu"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Ridicat"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparate auditive"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparate auditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Asociază un nou dispozitiv"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizează widgeturile"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Pictograma aplicației pentru widgetul dezactivat"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Pictograma aplicației pentru un widget care se instalează"</string>
<string name="edit_widget" msgid="9030848101135393954">"Editează widgetul"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Dezactivează sunetul pentru %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Activează sunetul pentru %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"sunet dezactivat"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrații"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Apel în curs pe"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6fabeae..bb79bc2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Отправить"</string>
<string name="cancel" msgid="1089011503403416730">"Отмена"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Логотип приложения"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Подтвердить"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Повторить попытку"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Нажмите, чтобы отменить аутентификацию"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сети недоступны"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Не удалось найти доступные сети Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Включение…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Трансляция экрана"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Трансляция"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Передача изображения"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Безымянное устройство"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нет доступных устройств"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батарея"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим управления одной рукой"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контрастность"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартная"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средняя"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Высокая"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слуховые аппараты"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слуховые аппараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Подключить новое устройство"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Настроить виджеты"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок приложения для отключенного виджета"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок приложения для устанавливаемого виджета"</string>
<string name="edit_widget" msgid="9030848101135393954">"Изменить виджет"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Отключить звук аудиопотока \"%s\""</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Включить звук аудиопотока \"%s\""</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"без звука"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вибросигнал"</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_ongoing_call" msgid="208426888064112006">"Настройки вызова"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 238e6c8..ad801c2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"යවන්න"</string>
<string name="cancel" msgid="1089011503403416730">"අවලංගු කරන්න"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"යෙදුම් ලාංඡනය"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"තහවුරු කරන්න"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"නැවත උත්සාහ කරන්න"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"සත්යාපනය අවලංගු කිරීමට තට්ටු කරන්න"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ජාල නොමැත"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi ජාල ලබා ගත නොහැකිය"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ක්රියාත්මක කරමින්…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"තිර විකාශය"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"කාස්ට් කිරීම"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"නම් නොකළ උපාංගය"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"උපාංග නොතිබේ"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"බැටරිය"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"තනි අත් ප්රකාරය"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"අසමානතාව"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"සම්මත"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"මධ්යම"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"ඉහළ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ශ්රවණ උපාංග"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ශ්රවණ උපාංග"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"නව උපාංගය යුගල කරන්න"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"විජට්ටු අභිරුචි කරන්න"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"අබල කළ විජට් සඳහා යෙදුම් නිරූපකය"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"විජට්ටුවක් සඳහා ස්ථාපන කරනු ලබන යෙදුම් නිරූපකය"</string>
<string name="edit_widget" msgid="9030848101135393954">"විජට්ටු සංස්කරණ කරන්න"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s නිහඬ කරන්න"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s නිහඬ නොකරන්න"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"නිහඬයි"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"කම්පනය"</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_ongoing_call" msgid="208426888064112006">"ඇමතීම"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 825dba6..5631ab0 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Odoslať"</string>
<string name="cancel" msgid="1089011503403416730">"Zrušiť"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo aplikácie"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdiť"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Skúsiť znova"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Klepnutím zrušíte overenie"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Siete nie sú k dispozícii"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"K dispozícii nie sú žiadne siete Wi‑Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Zapína sa…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Prenos obrazovky"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Prenos"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Prenáša sa"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nepomenované zariadenie"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nie sú k dispozícii žiadne zariadenia"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batéria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednej ruky"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Štandardný"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Stredný"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoký"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovať nové zariadenie"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prispôsobiť miniaplikácie"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona deaktivovanej miniaplikácie"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona inštalovanej miniaplikácie"</string>
<string name="edit_widget" msgid="9030848101135393954">"Upraviť miniaplikáciu"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Vypnúť zvuk %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Zapnúť zvuk %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"zvuk je vypnutý"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrovať"</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á cez"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Volanie je zapnuté"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 82f2df7..a6b31c9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Pošlji"</string>
<string name="cancel" msgid="1089011503403416730">"Prekliči"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip aplikacije"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potrdite"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Poskusi znova"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Če želite preklicati preverjanje pristnosti, se dotaknite"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Omrežja niso na voljo"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Na voljo ni nobeno omrežje Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Vklapljanje …"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Predvajanje zaslona"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Predvajanje"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Predvajanje"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Neimenovana naprava"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Na voljo ni nobene naprave"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterija"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visok"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni pripomočki"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni pripomočki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Seznanitev nove naprave"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagajanje pripomočkov"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogočen pripomoček"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona aplikacije za nameščanje pripomočka"</string>
<string name="edit_widget" msgid="9030848101135393954">"Urejanje pripomočka"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Izklop zvoka za %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Vklop zvoka za %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"zvok je izklopljen"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibriranje"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Poteka klicanje"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index af2e3c7..acbf234 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Dërgo"</string>
<string name="cancel" msgid="1089011503403416730">"Anulo"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logoja e aplikacionit"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Konfirmo"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Provo përsëri"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Trokit për të anuluar vërtetimin"</string>
@@ -167,7 +169,7 @@
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Fytyra u njoh. Shtyp ikonën e shkyçjes për të vazhduar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"U vërtetua"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Anulo vërtetimin"</string>
- <string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Opsione të tjera…"</string>
+ <string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Opsione të tjera"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Përdor kodin PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Përdor motivin"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Përdor fjalëkalimin"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Rrjetet nuk ofrohen"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nuk ka rrjete Wi-Fi të disponueshme"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Po aktivizohet…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Transmetimi i ekranit"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmeto"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Po transmeton"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Pajisje e paemërtuar"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nuk ofrohet për përdorim asnjë pajisje"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Bateria"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modaliteti i përdorimit me një dorë"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasti"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mesatar"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"I lartë"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Pajisje ndihmëse për dëgjimin"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Pajisjet e dëgjimit"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Çifto pajisje të re"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizo miniaplikacionet"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona e aplikacionit për miniaplikacionin e çaktivizuar"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ikona e aplikacionit për një miniaplikacion që po instalohet"</string>
<string name="edit_widget" msgid="9030848101135393954">"Modifiko miniaplikacionin"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string>
@@ -619,7 +616,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Audioja hapësinore"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Joaktive"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"E fiksuar"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Monitorimi i lëvizjes së kokës"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Ndjekja e lëvizjeve të kokës"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Trokit për të ndryshuar modalitetin e ziles"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Vendos në heshtje: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Anulo vendosjen në heshtje: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"në heshtje"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"lësho dridhje"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Po luhet <xliff:g id="LABEL">%s</xliff:g> te"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"Do të luhet audio te"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Telefonatë aktive"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 42b979c..d21536b 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Пошаљи"</string>
<string name="cancel" msgid="1089011503403416730">"Откажи"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Логотип апликације"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Потврди"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Пробај поново"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Додирните да бисте отказали потврду идентитета"</string>
@@ -168,7 +170,7 @@
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Идентитет је потврђен"</string>
<string name="biometric_dialog_cancel_authentication" msgid="981316588773442637">"Откажите потврду идентитета"</string>
<string name="biometric_dialog_content_view_more_options_button" msgid="2663810393874865475">"Још опција"</string>
- <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користите PIN"</string>
+ <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користи PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користите шаблон"</string>
<string name="biometric_dialog_use_password" msgid="3445033859393474779">"Користите лозинку"</string>
<string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Погрешан PIN"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Мреже нису доступне"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Није доступна ниједна WiFi мрежа"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Укључује се..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Пребацивање екрана"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Пребацивање"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Пребацивање"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Неименовани уређај"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Није доступан ниједан уређај"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Батерија"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим једном руком"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандардно"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средње"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Високо"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Упари нови уређај"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Прилагоди виџете"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона апликације за онемогућен виџет"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Икона апликације за виџет који се инсталира"</string>
<string name="edit_widget" msgid="9030848101135393954">"Измени виџет"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Искључите звук за: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Укључите звук за: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"звук је искључен"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вибрација"</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_ongoing_call" msgid="208426888064112006">"Позив на уређају"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 29dca46..95c5e15 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Skicka"</string>
<string name="cancel" msgid="1089011503403416730">"Avbryt"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Appens logotyp"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Bekräfta"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Försök igen"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tryck för att avbryta autentiseringen"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Inga nätverk är tillgängliga"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Det finns inga tillgängliga wifi-nätverk"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Aktiverar …"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Casta skärmen"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Casta"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Castar"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Namnlös enhet"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Inga tillgängliga enheter"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batteri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medelhög"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hög"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörhjälpmedel"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörhjälpmedel"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parkoppla en ny enhet"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Anpassa widgetar"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon för inaktiverad widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Appikon för en widget som installeras"</string>
<string name="edit_widget" msgid="9030848101135393954">"Redigera widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string>
@@ -618,7 +615,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Bruskontroll"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Rumsligt ljud"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Av"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Statisk"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Statiskt"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Huvudspårning"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Tryck för att ändra ringsignalens läge"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Stäng av ljudet för %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Slå på ljudet för %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ljud av"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibration"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Samtal på"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9d5181e..fab95f0 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Tuma"</string>
<string name="cancel" msgid="1089011503403416730">"Ghairi"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Nembo ya programu"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Thibitisha"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Jaribu tena"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Gusa ili ughairi uthibitishaji"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mitandao haipatikani"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Hakuna mitandao ya Wi-Fi inayopatikana"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Inawasha..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Kutuma kwenye Skrini"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Tuma"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Inatuma"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Kifaa hakina jina"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Hakuna vifaa vilivyopatikana"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Betri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Hali ya kutumia kwa mkono mmoja"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Utofautishaji"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Kawaida"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Wastani"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Juu"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Vifaa vya kusikilizia"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Vifaa vya kusikilizia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Unganisha kifaa kipya"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Badilisha wijeti upendavyo"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Aikoni ya programu ya wijeti iliyozimwa"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Aikoni ya programu ya wijeti inayowekwa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Badilisha wijeti"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Zima sauti ya %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Rejesha sauti ya %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"sauti imezimwa"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"tetema"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Simu inaendelea"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a2f4ce5..d8e6892 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"அனுப்பு"</string>
<string name="cancel" msgid="1089011503403416730">"ரத்துசெய்"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ஆப்ஸ் லோகோ"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"உறுதிப்படுத்துக"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"மீண்டும் முயல்க"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"பயோமெட்ரிக் அடையாளத்தை ரத்துசெய்ய தட்டவும்"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"நெட்வொர்க்குகள் கிடைக்கவில்லை"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"வைஃபை நெட்வொர்க்குகள் இல்லை"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ஆன் செய்கிறது…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"திரை அலைபரப்பல்"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"அனுப்புகிறது"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"பெயரிடப்படாத சாதனம்"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"சாதனங்கள் இல்லை"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"பேட்டரி"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ஒற்றைக் கைப் பயன்முறை"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"ஒளி மாறுபாடு"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"இயல்புநிலை"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"நடுத்தரம்"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"அதிகம்"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"செவித்துணைக் கருவிகள்"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"செவித்துணைக் கருவிகள்"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"புதிய சாதனத்தை இணை"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"விட்ஜெட்களைப் பிரத்தியேகமாக்குங்கள்"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"முடக்கப்பட்ட விட்ஜெட்டுக்கான ஆப்ஸ் ஐகான்"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"நிறுவப்படும் விட்ஜெட்டுக்கான ஆப்ஸ் ஐகான்"</string>
<string name="edit_widget" msgid="9030848101135393954">"விட்ஜெட்டைத் திருத்து"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s ஒலியடக்கும்"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s ஒலி எழுப்பும்"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ஒலியடக்கப்பட்டது"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"அதிர்வுறும்"</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_ongoing_call" msgid="208426888064112006">"அழைப்பில் உள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 5b703a0..77c89c0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"పంపండి"</string>
<string name="cancel" msgid="1089011503403416730">"రద్దు చేయండి"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"యాప్ లోగో"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"నిర్ధారించండి"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"మళ్లీ ట్రై చేయండి"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ప్రామాణీకరణను రద్దు చేయడానికి నొక్కండి"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"నెట్వర్క్లు అందుబాటులో లేవు"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Wi-Fi నెట్వర్క్లు ఏవీ అందుబాటులో లేవు"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ఆన్ చేస్తోంది…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"స్క్రీన్ కాస్ట్"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"ప్రసారం"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"ప్రసారం చేస్తోంది"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"పేరులేని పరికరం"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"బ్యాటరీ"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"కాంట్రాస్ట్"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"స్టాండర్డ్"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"మధ్యస్థం"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"అధికం"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"విడ్జెట్లను అనుకూలంగా మార్చండి"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"డిజేబుల్ చేయబడిన విడ్జెట్ కోసం యాప్ చిహ్నం"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ఇన్స్టాల్ చేస్తున్న విడ్జెట్ కోసం యాప్ చిహ్నం"</string>
<string name="edit_widget" msgid="9030848101135393954">"విడ్జెట్ను ఎడిట్ చేయండి"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్ను జోడించండి"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%sను మ్యూట్ చేయండి"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%sను అన్మ్యూట్ చేయండి"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"మ్యూట్ చేయబడ్డాయి"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"వైబ్రేట్"</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_ongoing_call" msgid="208426888064112006">"కాల్ ప్రోగ్రెస్లో ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 73ca200..0800a26 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"ส่ง"</string>
<string name="cancel" msgid="1089011503403416730">"ยกเลิก"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"โลโก้แอป"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"ยืนยัน"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"ลองอีกครั้ง"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"แตะเพื่อยกเลิกการตรวจสอบสิทธิ์"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ใช้งานเครือข่ายไม่ได้"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"ไม่มีเครือข่าย Wi-Fi พร้อมใช้งาน"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"กำลังเปิด..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"การแคสต์หน้าจอ"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"แคสต์"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"กำลังส่ง"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"อุปกรณ์ที่ไม่มีชื่อ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ไม่มีอุปกรณ์ที่สามารถใช้ได้"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"แบตเตอรี่"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"โหมดมือเดียว"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"คอนทราสต์"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"มาตรฐาน"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ปานกลาง"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"สูง"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"จับคู่อุปกรณ์ใหม่"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ปรับแต่งวิดเจ็ต"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ไอคอนแอปสำหรับวิดเจ็ตที่ปิดใช้อยู่"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"ไอคอนแอปสำหรับวิดเจ็ตที่กำลังติดตั้ง"</string>
<string name="edit_widget" msgid="9030848101135393954">"แก้ไขวิดเจ็ต"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"ปิดเสียง %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"เปิดเสียง %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"ปิดเสียงอยู่"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"สั่น"</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_ongoing_call" msgid="208426888064112006">"กำลังโทรติดต่อ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0c616fa..a8cba0b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Ipadala"</string>
<string name="cancel" msgid="1089011503403416730">"Kanselahin"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Logo ng app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Kumpirmahin"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Subukang muli"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"I-tap para kanselahin ang pag-authenticate"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Hindi available ang mga network"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Walang available na mga Wi-Fi network"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ino-on…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Screen Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"I-cast"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Nagka-cast"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Walang pangalang device"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Walang available na mga device"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Baterya"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-hand mode"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Katamtaman"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Mataas"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Mga hearing device"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Mga hearing device"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Magpares ng bagong device"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"I-customize ang mga widget"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icon ng app para sa na-disable na widget"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Ini-install ang icon ng app para sa isang widget"</string>
<string name="edit_widget" msgid="9030848101135393954">"I-edit ang widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string>
@@ -629,14 +626,10 @@
<string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Pumunta sa mga setting ng output"</string>
<string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Na-expand ang mga slider ng volume"</string>
<string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Na-collapse ang mga slider ng volume"</string>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"I-mute ang %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"I-unmute ang %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"Na-mute"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"i-vibrate"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Nagpe-play ang <xliff:g id="LABEL">%s</xliff:g> sa"</string>
<string name="media_output_title_without_playing" msgid="3825663683169305013">"I-play ang audio sa"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Tumatawag sa"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6723c42..d3fceeb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Gönder"</string>
<string name="cancel" msgid="1089011503403416730">"İptal"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Uygulama logosu"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Onayla"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tekrar dene"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Kimlik doğrulama işlemini iptal etmek için dokunun"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Kullanılamayan ağlar"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Kullanılabilir kablosuz ağ yok"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Açılıyor…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekran Yayını"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Yayınla"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Yayınlanıyor"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Adsız cihaz"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Kullanılabilir cihaz yok"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Pil"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tek el modu"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksek"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"İşitme cihazları"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"İşitme cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz eşle"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widget\'ları özelleştir"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Devre dışı bırakılan widget\'ın uygulama simgesi"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Yüklenmeye devam eden bir widget\'ın uygulama simgesi"</string>
<string name="edit_widget" msgid="9030848101135393954">"Widget\'ı düzenle"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string>
@@ -619,7 +616,7 @@
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Üç Boyutlu Ses"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Kapalı"</string>
<string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Sabit"</string>
- <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Kafa Hareketi İzleme"</string>
+ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Baş Takibi"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"Telefon zili modunu değiştirmek için dokunun"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi kapat"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"%s sesini kapat"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"%s sesini aç"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"sesi kapatıldı"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"titreşim"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Şu cihaz aranıyor:"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 2659f9f..662031c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Надіслати"</string>
<string name="cancel" msgid="1089011503403416730">"Скасувати"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Логотип додатка"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Підтвердити"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Повторити спробу"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Натисніть, щоб скасувати автентифікацію"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Недоступні мережі"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Немає доступних мереж Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Увімкнення…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Трансляція екрана"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Трансляція"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Трансляція"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Пристрій без назви"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Немає пристроїв"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Акумулятор"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим керування однією рукою"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартний"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Середній"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Високий"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухові апарати"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Налаштувати віджети"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок додатка для вимкненого віджета"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Значок додатка для віджета, що встановлюється"</string>
<string name="edit_widget" msgid="9030848101135393954">"Редагувати віджет"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Вимкнути звук (%s)"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Увімкнути звук (%s)"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"вимкнено звук"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"вібросигнал"</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_ongoing_call" msgid="208426888064112006">"Триває виклик"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 2a7fda1..24a3eb0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"بھیجیں"</string>
<string name="cancel" msgid="1089011503403416730">"منسوخ کريں"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"ایپ لوگو"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"تصدیق کریں"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"دوبارہ کوشش کریں"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"تصدیق کو منسوخ کرنے کے لیے تھپتھپائیں"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"نیٹ ورکس دستیاب نہیں ہیں"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"کوئی WI-FI نیٹ ورک دستیاب نہیں"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"آن ہو رہا ہے…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"اسکرین کاسٹ کریں"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"کاسٹ کریں"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"کاسٹنگ"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"بغیر نام والا آلہ"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"کوئی آلات دستیاب نہیں ہیں"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"بیٹری"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ایک ہاتھ کی وضع"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"کنٹراسٹ"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"معیاری"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"زیادہ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعت کے آلات"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعت کے آلات"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"نئے آلے کا جوڑا بنائیں"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ویجیٹس کو حسب ضرورت بنائیں"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"غیر فعال ویجیٹ کے لئے ایپ آئیکن"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"انسٹال ہونے والے ویجیٹ کا ایپ آئیکن"</string>
<string name="edit_widget" msgid="9030848101135393954">"ویجیٹ میں ترمیم کریں"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string>
@@ -629,14 +626,14 @@
<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.format failed for translation -->
<!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
<skip />
+ <!-- String.format failed for translation -->
<!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
<skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"خاموش کردہ"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"وائبریٹ"</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_ongoing_call" msgid="208426888064112006">"کال کی جا رہی ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0d7709c..5cdff8b 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Yuborish"</string>
<string name="cancel" msgid="1089011503403416730">"Bekor qilish"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Ilova logotipi"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"OK"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Qayta urinish"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Tekshiruvni bekor qilish uchun bosing"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tarmoqqa ulanish imkonsiz"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Hech qanday Wi-Fi tarmog‘i mavjud emas"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Yoqilmoqda…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Ekran translatsiyasi"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Translatsiya"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Translatsiya qilinmoqda"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nomsiz qurilma"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Qurilmalar topilmadi"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Batareya"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ixcham rejim"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Oʻrtacha"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yuqori"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eshitish qurilmalari"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eshitish qurilmalari"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yangi qurilmani ulash"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidjetlarni moslashtirish"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Faolsizlantirilgan vidjet uchun ilova belgisi"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Oʻrnatilayotgan vidjet uchun ilova belgisi"</string>
<string name="edit_widget" msgid="9030848101135393954">"Vidjetni tahrirlash"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Sukut qilish: %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Sukutdan chiqarish: %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"sukutda"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"tebranish"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Chaqiruv yoniq"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 2ddcd6d..7c91916 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Gửi"</string>
<string name="cancel" msgid="1089011503403416730">"Hủy"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Biểu trưng của ứng dụng"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Xác nhận"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Thử lại"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Nhấn để hủy quá trình xác thực"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Không có mạng"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Không có mạng Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Đang bật…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Truyền màn hình"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Truyền"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Đang truyền"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Thiết bị không có tên"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Không có thiết bị nào"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Pin"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Chế độ một tay"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Độ tương phản"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Chuẩn"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vừa"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Cao"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Thiết bị trợ thính"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Thiết bị trợ thính"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Ghép nối thiết bị mới"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tuỳ chỉnh tiện ích"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Biểu tượng ứng dụng của tiện ích đã bị vô hiệu hoá"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Đang cài đặt biểu tượng ứng dụng của một tiện ích"</string>
<string name="edit_widget" msgid="9030848101135393954">"Chỉnh sửa tiện ích"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Tắt tiếng %s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Bật tiếng %s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"đã tắt tiếng"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"rung"</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 trên"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Đang gọi điện"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 64e37ce..dda17d4 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"发送"</string>
<string name="cancel" msgid="1089011503403416730">"取消"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"应用徽标"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"确认"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"重试"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"点按即可取消身份验证"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"没有可用的网络"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"没有 WLAN 网络"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"正在开启…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"屏幕投放"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"投放"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"正在投放"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"未命名设备"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"没有可用设备"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"电池"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"单手模式"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"对比度"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"标准"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助听装置"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助听装置"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"与新设备配对"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自定义微件"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用微件的应用图标"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"代表正在安装的微件的应用图标"</string>
<string name="edit_widget" msgid="9030848101135393954">"修改微件"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"将“%s”设为静音"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"将“%s”取消静音"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"已设为静音"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"振动"</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_ongoing_call" msgid="208426888064112006">"正在通话"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 714e479..f48d322 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"傳送"</string>
<string name="cancel" msgid="1089011503403416730">"取消"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"應用程式標誌"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"確認"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"請再試一次"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"輕按即可取消驗證"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"網絡無法使用"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"沒有可用的 Wi-Fi 網絡"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"正在開啟…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"螢幕投放"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"投放"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"正在放送"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"未命名的裝置"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"電池"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"對比"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用小工具的應用程式圖示"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"此應用程式圖示用來表示安裝中的小工具"</string>
<string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"將%s靜音"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"將%s取消靜音"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"已經靜音"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"震動"</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_ongoing_call" msgid="208426888064112006">"通話中"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 495a055..af1d915 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"傳送"</string>
<string name="cancel" msgid="1089011503403416730">"取消"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"應用程式標誌"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"確認"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"再試一次"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"輕觸即可取消驗證"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"沒有網路"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"沒有 Wi-Fi 網路"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"開啟中…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"螢幕投放"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"投放"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"投放"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"未命名的裝置"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"電池"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"對比"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"所停用小工具的應用程式圖示"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"這個應用程式圖示用來表示安裝中的小工具"</string>
<string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"將「%s」設為靜音"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"將「%s」取消靜音"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"已設為靜音"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"震動"</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_ongoing_call" msgid="208426888064112006">"通話中"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f5ee5a0..a4673db 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -153,6 +153,8 @@
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Thumela"</string>
<string name="cancel" msgid="1089011503403416730">"Khansela"</string>
<string name="biometric_dialog_logo" msgid="7681107853070774595">"Ilogo ye-app"</string>
+ <string-array name="biometric_dialog_package_names_for_logo_with_overrides">
+ </string-array>
<string name="biometric_dialog_confirm" msgid="2005978443007344895">"Qinisekisa"</string>
<string name="biometric_dialog_try_again" msgid="8575345628117768844">"Zama futhi"</string>
<string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Thepha ukuze ukhansele ukufakazela ubuqiniso"</string>
@@ -302,7 +304,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Amanethiwekhi awatholakali"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Awekho amanethiwekhi we-Wi-Fi atholakalayo"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Iyavula..."</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Linganisa isikrini"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"Abalingisi"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Ukusakaza"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Idivayisi engenalo igama"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ayikho idivayisi etholakalayo"</string>
@@ -364,10 +366,6 @@
<item msgid="8309220355268900335">"Ibhethri"</item>
</string-array>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Imodi yesandla esisodwa"</string>
- <string name="quick_settings_contrast_label" msgid="988087460210159123">"Ukugqama"</string>
- <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Okujwayelekile"</string>
- <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Okuphakathi"</string>
- <string name="quick_settings_contrast_high" msgid="656049259587494499">"Phezulu"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Izinsizakuzwa"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Izinsizakuzwa"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bhangqa idivayisi entsha"</string>
@@ -447,8 +445,7 @@
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string>
<string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Yenza ngokwezifiso amawijethi"</string>
<string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Isithonjana se-app sewijethi evaliwe"</string>
- <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) -->
- <skip />
+ <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"Isithonjana se-app sewijethi siyafakwa"</string>
<string name="edit_widget" msgid="9030848101135393954">"Hlela amawijethi"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string>
@@ -629,14 +626,10 @@
<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>
- <!-- no translation found for volume_panel_hint_mute (2153922288568199077) -->
- <skip />
- <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) -->
- <skip />
- <!-- no translation found for volume_panel_hint_muted (1124844870181285320) -->
- <skip />
- <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) -->
- <skip />
+ <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Thulisa i-%s"</string>
+ <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Susa ukuthula kwe-%s"</string>
+ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"kuthulisiwe"</string>
+ <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"dlidliza"</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="media_output_title_ongoing_call" msgid="208426888064112006">"Ifonela kokuthi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2ba72e3..638785402 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -720,6 +720,20 @@
<item>26</item> <!-- MOUTH_COVERING_DETECTED -->
</integer-array>
+ <!-- Which face help messages to surface when fingerprint is enrolled and device is unfolded.
+ Message ids correspond with the acquired ids in BiometricFaceConstants -->
+ <integer-array name="config_face_help_msgs_when_fingerprint_enrolled_unfolded">
+ <item>3</item> <!-- TOO_DARK -->
+ <item>4</item> <!-- TOO_CLOSE -->
+ <item>5</item> <!-- TOO_FAR -->
+ <item>6</item> <!-- TOO_HIGH -->
+ <item>7</item> <!-- TOO_LOW -->
+ <item>8</item> <!-- TOO_RIGHT -->
+ <item>9</item> <!-- TOO_LEFT -->
+ <item>25</item> <!-- DARK_GLASSES -->
+ <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
+ </integer-array>
+
<!-- Which device wake-ups will trigger passive auth. These values correspond with
PowerManager#WakeReason. -->
<integer-array name="config_face_auth_wake_up_triggers">
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9d0319c..02b74ce 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -449,8 +449,12 @@
<dimen name="overlay_preview_container_margin">8dp</dimen>
<dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
<dimen name="overlay_action_container_margin_bottom">6dp</dimen>
- <!-- minimum distance to the left, right or bottom edges. -->
+ <!--
+ minimum distance to the left, right or bottom edges. Keep in sync with
+ negative_overlay_action_container_minimum_edge_spacing. -->
<dimen name="overlay_action_container_minimum_edge_spacing">12dp</dimen>
+ <!-- Keep in sync with overlay_action_container_minimum_edge_spacing -->
+ <dimen name="negative_overlay_action_container_minimum_edge_spacing">-12dp</dimen>
<dimen name="overlay_bg_protection_height">242dp</dimen>
<dimen name="overlay_action_container_corner_radius">20dp</dimen>
<dimen name="overlay_action_container_padding_vertical">8dp</dimen>
@@ -913,10 +917,6 @@
obvious when corner radii differ.-->
<dimen name="communal_enforced_rounded_corner_max_radius">28dp</dimen>
- <!-- Width and height used to filter widgets displayed in the communal widget picker -->
- <dimen name="communal_widget_picker_desired_width">360dp</dimen>
- <dimen name="communal_widget_picker_desired_height">240dp</dimen>
-
<!-- The width/height of the unlock icon view on keyguard. -->
<dimen name="keyguard_lock_height">42dp</dimen>
<dimen name="keyguard_lock_padding">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8da8316f..abfdc2a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -214,6 +214,8 @@
<string name="screenshot_saving_title">Saving screenshot\u2026</string>
<!-- Informs the user that a screenshot is being saved. [CHAR LIMIT=50] -->
<string name="screenshot_saving_work_profile_title">Saving screenshot to work profile\u2026</string>
+ <!-- Informs the user that a screenshot is being saved to the private profile. [CHAR LIMIT=100] -->
+ <string name="screenshot_saving_private_profile">Saving screenshot to private</string>
<!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
<string name="screenshot_saved_title">Screenshot saved</string>
<!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
@@ -765,7 +767,7 @@
<!-- QuickSettings: Wifi secondary label shown when the wifi is being enabled [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_secondary_label_transient">Turning on…</string>
<!-- QuickSettings: Cast title [CHAR LIMIT=NONE] -->
- <string name="quick_settings_cast_title">Screen Cast</string>
+ <string name="quick_settings_cast_title">Cast</string>
<!-- QuickSettings: Cast detail panel, status text when casting [CHAR LIMIT=NONE] -->
<string name="quick_settings_casting">Casting</string>
<!-- QuickSettings: Cast detail panel, default device name [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 393a1aa..b8f71c1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -375,6 +375,12 @@
<item name="android:textColor">?androidprv:attr/materialColorPrimary</item>
</style>
+ <style name="AuthCredentialNegativeButtonStyle" parent="TextAppearance.Material3.LabelLarge">
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+ <item name="android:background">@color/transparent</item>
+ <item name="android:textColor">?androidprv:attr/materialColorPrimary</item>
+ </style>
+
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
<item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item>
@@ -1255,6 +1261,7 @@
<item name="android:lineHeight">32sp</item>
<item name="android:gravity">center</item>
<item name="android:textAlignment">center</item>
+ <item name="android:hyphenationFrequency">full</item>
</style>
<style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium">
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index e66261c..5458ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -240,7 +240,7 @@
private boolean mEditSizeEnable = false;
private boolean mSettingsPanelVisibility = false;
@VisibleForTesting
- WindowMagnificationSizePrefs mWindowMagnificationSizePrefs;
+ WindowMagnificationFrameSizePrefs mWindowMagnificationFrameSizePrefs;
@Nullable
private final MirrorWindowControl mMirrorWindowControl;
@@ -270,7 +270,7 @@
mSysUiState = sysUiState;
mScvhSupplier = scvhSupplier;
mConfiguration = new Configuration(context.getResources().getConfiguration());
- mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
+ mWindowMagnificationFrameSizePrefs = new WindowMagnificationFrameSizePrefs(mContext);
final Display display = mContext.getDisplay();
mDisplayId = mContext.getDisplayId();
@@ -457,7 +457,7 @@
if (!enable) {
// Keep the magnifier size when exiting edit mode
- mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(
+ mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(
new Size(mMagnificationFrame.width(), mMagnificationFrame.height()));
}
}
@@ -944,7 +944,7 @@
}
private void setMagnificationFrame(int width, int height, int centerX, int centerY) {
- mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(new Size(width, height));
+ mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(new Size(width, height));
// Sets the initial frame area for the mirror and place it to the given center on the
// display.
@@ -954,11 +954,11 @@
}
private Size restoreMagnificationWindowFrameSizeIfPossible() {
- if (!mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) {
+ if (!mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity()) {
return getDefaultMagnificationWindowFrameSize();
}
- return mWindowMagnificationSizePrefs.getSizeForCurrentDensity();
+ return mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity();
}
private Size getDefaultMagnificationWindowFrameSize() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
rename to packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
index a401f2a..e83e85e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
@@ -23,14 +23,14 @@
/**
* Class to handle SharedPreference for window magnification size.
*/
-final class WindowMagnificationSizePrefs {
+final class WindowMagnificationFrameSizePrefs {
private static final String WINDOW_MAGNIFICATION_PREFERENCES =
"window_magnification_preferences";
Context mContext;
SharedPreferences mWindowMagnificationSizePreferences;
- public WindowMagnificationSizePrefs(Context context) {
+ WindowMagnificationFrameSizePrefs(Context context) {
mContext = context;
mWindowMagnificationSizePreferences = mContext
.getSharedPreferences(WINDOW_MAGNIFICATION_PREFERENCES, Context.MODE_PRIVATE);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
index bf44fab..b33746c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
@@ -149,12 +149,7 @@
secureSettings
.observerFlow(userHandle.identifier, DISPLAY_AUTO_MODE_RAW_SETTING_NAME)
.onStart { emit(Unit) }
- .map {
- secureSettings.getIntForUser(
- DISPLAY_AUTO_MODE_RAW_SETTING_NAME,
- userHandle.identifier
- ) == NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET
- }
+ .map { isNightDisplayAutoModeRawSettingNotSet(userHandle.identifier) }
}
.distinctUntilChanged()
@@ -179,12 +174,19 @@
colorDisplayManager.nightDisplayCustomEndTime,
globalSettings.getString(IS_FORCE_AUTO_MODE_AVAILABLE_SETTING_NAME) ==
NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE &&
- secureSettings.getIntForUser(DISPLAY_AUTO_MODE_RAW_SETTING_NAME, user.identifier) ==
- NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET,
+ isNightDisplayAutoModeRawSettingNotSet(user.identifier),
locationController.isLocationEnabled,
)
}
+ private fun isNightDisplayAutoModeRawSettingNotSet(userId: Int): Boolean {
+ return secureSettings.getIntForUser(
+ DISPLAY_AUTO_MODE_RAW_SETTING_NAME,
+ NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET,
+ userId
+ ) == NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET
+ }
+
private companion object {
const val NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET = -1
const val NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE = "1"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 298c0f7..b75b292 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -362,7 +362,7 @@
mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId,
- biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
+ getRequestId(), biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
false /*onSwitchToCredential*/);
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
@@ -436,7 +436,7 @@
addCredentialView(true, false);
}
} else {
- mPromptSelectorInteractorProvider.get().resetPrompt();
+ mPromptSelectorInteractorProvider.get().resetPrompt(getRequestId());
}
}
@@ -884,7 +884,8 @@
final Runnable endActionRunnable = () -> {
setVisibility(View.INVISIBLE);
if (Flags.customBiometricPrompt() && constraintBp()) {
- mPromptSelectorInteractorProvider.get().resetPrompt();
+ // TODO(b/288175645): resetPrompt calls should be lifecycle aware
+ mPromptSelectorInteractorProvider.get().resetPrompt(getRequestId());
}
removeWindowIfAttached();
};
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 6b61adc..ba51d02 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -30,10 +30,10 @@
import com.android.systemui.biometrics.shared.model.toSensorStrength
import com.android.systemui.biometrics.shared.model.toSensorType
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.utils.coroutines.flow.conflatedCallbackFlow
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -41,6 +41,8 @@
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
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
@@ -111,9 +113,6 @@
initialValue = UNINITIALIZED_PROPS,
)
- override val propertiesInitialized: Flow<Boolean> =
- props.map { it != UNINITIALIZED_PROPS }.onStart { emit(props.value != UNINITIALIZED_PROPS) }
-
override val sensorId: Flow<Int> = props.map { it.sensorId }
override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
@@ -134,9 +133,25 @@
}
}
+ override val propertiesInitialized: Flow<Boolean> =
+ combine(
+ props
+ .map { it != UNINITIALIZED_PROPS }
+ .onStart { emit(props.value != UNINITIALIZED_PROPS) },
+ sensorId.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
+ sensorLocations
+ .map {}
+ .onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
+ sensorType.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
+ strength.map {}.onStart { if (props.value != UNINITIALIZED_PROPS) emit(Unit) },
+ ) { initialized, _, _, _, _ ->
+ initialized
+ }
+ .distinctUntilChanged()
+
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
- val UNINITIALIZED_PROPS =
+ private val UNINITIALIZED_PROPS =
FingerprintSensorPropertiesInternal(
-2 /* sensorId */,
SensorProperties.STRENGTH_CONVENIENCE,
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 58b238b..230b30b 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
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.data.repository
import android.hardware.biometrics.PromptInfo
+import android.util.Log
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
@@ -49,6 +50,9 @@
/** The user that the prompt is for. */
val userId: StateFlow<Int?>
+ /** The request that the prompt is for. */
+ val requestId: StateFlow<Long?>
+
/** The gatekeeper challenge, if one is associated with this prompt. */
val challenge: StateFlow<Long?>
@@ -69,13 +73,14 @@
fun setPrompt(
promptInfo: PromptInfo,
userId: Int,
+ requestId: Long,
gatekeeperChallenge: Long?,
kind: PromptKind,
opPackageName: String,
)
/** Unset the prompt info. */
- fun unsetPrompt()
+ fun unsetPrompt(requestId: Long)
}
@SysUISingleton
@@ -109,6 +114,9 @@
private val _userId: MutableStateFlow<Int?> = MutableStateFlow(null)
override val userId = _userId.asStateFlow()
+ private val _requestId: MutableStateFlow<Long?> = MutableStateFlow(null)
+ override val requestId = _requestId.asStateFlow()
+
private val _promptKind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None)
override val promptKind = _promptKind.asStateFlow()
@@ -132,23 +140,30 @@
override fun setPrompt(
promptInfo: PromptInfo,
userId: Int,
+ requestId: Long,
gatekeeperChallenge: Long?,
kind: PromptKind,
opPackageName: String,
) {
_promptKind.value = kind
_userId.value = userId
+ _requestId.value = requestId
_challenge.value = gatekeeperChallenge
_promptInfo.value = promptInfo
_opPackageName.value = opPackageName
}
- override fun unsetPrompt() {
- _promptInfo.value = null
- _userId.value = null
- _challenge.value = null
- _promptKind.value = PromptKind.None
- _opPackageName.value = null
+ override fun unsetPrompt(requestId: Long) {
+ if (requestId == _requestId.value) {
+ _promptInfo.value = null
+ _userId.value = null
+ _requestId.value = null
+ _challenge.value = null
+ _promptKind.value = PromptKind.None
+ _opPackageName.value = null
+ } else {
+ Log.w(TAG, "Ignoring unsetPrompt - requestId mismatch")
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index d5b450d..a74b0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -52,7 +52,7 @@
.map { it.isUdfps() }
.stateIn(
scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
+ started = SharingStarted.Eagerly,
initialValue = repository.sensorType.value.isUdfps(),
)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index 4ba780f..dc338d0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -86,6 +86,7 @@
fun setPrompt(
promptInfo: PromptInfo,
effectiveUserId: Int,
+ requestId: Long,
modalities: BiometricModalities,
challenge: Long,
opPackageName: String,
@@ -93,7 +94,7 @@
)
/** Unset the current authentication request. */
- fun resetPrompt()
+ fun resetPrompt(requestId: Long)
}
@SysUISingleton
@@ -161,6 +162,7 @@
setPrompt(
promptRepository.promptInfo.value!!,
promptRepository.userId.value!!,
+ promptRepository.requestId.value!!,
modalities,
promptRepository.challenge.value!!,
promptRepository.opPackageName.value!!,
@@ -171,6 +173,7 @@
override fun setPrompt(
promptInfo: PromptInfo,
effectiveUserId: Int,
+ requestId: Long,
modalities: BiometricModalities,
challenge: Long,
opPackageName: String,
@@ -198,13 +201,14 @@
promptRepository.setPrompt(
promptInfo = promptInfo,
userId = effectiveUserId,
+ requestId = requestId,
gatekeeperChallenge = challenge,
kind = kind,
opPackageName = opPackageName,
)
}
- override fun resetPrompt() {
- promptRepository.unsetPrompt()
+ override fun resetPrompt(requestId: Long) {
+ promptRepository.unsetPrompt(requestId)
}
}
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 13ea3f5..47174c0 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
@@ -321,6 +321,12 @@
lifecycleScope.launch {
viewModel.guidelineBounds.collect { bounds ->
+ val bottomInset =
+ windowManager.maximumWindowMetrics.windowInsets
+ .getInsets(WindowInsets.Type.navigationBars())
+ .bottom
+ mediumConstraintSet.setGuidelineEnd(R.id.bottomGuideline, bottomInset)
+
if (bounds.left >= 0) {
mediumConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left)
smallConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
index 9e836c3..fcc6992 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
@@ -17,9 +17,7 @@
package com.android.systemui.biometrics.ui.binder
-import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
-import android.graphics.drawable.Drawable
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
@@ -30,8 +28,8 @@
import com.android.systemui.biometrics.ui.viewmodel.PromptIconViewModel.AuthType
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
-import com.android.systemui.util.kotlin.Utils.Companion.toQuint
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import kotlinx.coroutines.flow.combine
@@ -63,16 +61,6 @@
}
var faceIcon: AnimatedVectorDrawable? = null
- val faceIconCallback =
- object : Animatable2.AnimationCallback() {
- override fun onAnimationStart(drawable: Drawable) {
- viewModel.onAnimationStart()
- }
-
- override fun onAnimationEnd(drawable: Drawable) {
- viewModel.onAnimationEnd()
- }
- }
if (!constraintBp()) {
launch {
@@ -138,19 +126,13 @@
combine(
viewModel.activeAuthType,
viewModel.shouldAnimateIconView,
- viewModel.shouldRepeatAnimation,
viewModel.showingError,
- ::toQuad
+ ::Triple
),
- ::toQuint
+ ::toQuad
)
- .collect {
- (
- iconAsset,
- activeAuthType,
- shouldAnimateIconView,
- shouldRepeatAnimation,
- showingError) ->
+ .collect { (iconAsset, activeAuthType, shouldAnimateIconView, showingError)
+ ->
if (iconAsset != -1) {
when (activeAuthType) {
AuthType.Fingerprint,
@@ -163,21 +145,27 @@
}
}
AuthType.Face -> {
- faceIcon?.apply {
- unregisterAnimationCallback(faceIconCallback)
- stop()
- }
- faceIcon =
- iconView.context.getDrawable(iconAsset)
- as AnimatedVectorDrawable
- faceIcon?.apply {
- iconView.setImageDrawable(this)
+ // TODO(b/318569643): Consolidate logic once all face auth
+ // assets are migrated from drawable to json
+ if (iconAsset == R.raw.face_dialog_authenticating) {
+ iconView.setAnimation(iconAsset)
+ iconView.frame = 0
+
if (shouldAnimateIconView) {
- forceAnimationOnUI()
- if (shouldRepeatAnimation) {
- registerAnimationCallback(faceIconCallback)
+ iconView.playAnimation()
+ iconView.loop(true)
+ }
+ } else {
+ faceIcon?.apply { stop() }
+ faceIcon =
+ iconView.context.getDrawable(iconAsset)
+ as AnimatedVectorDrawable
+ faceIcon?.apply {
+ iconView.setImageDrawable(this)
+ if (shouldAnimateIconView) {
+ forceAnimationOnUI()
+ start()
}
- start()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
index bde3e99..901d751 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
@@ -21,7 +21,6 @@
import android.annotation.RawRes
import android.content.res.Configuration
import android.graphics.Rect
-import android.hardware.face.Face
import android.util.RotationUtils
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
@@ -32,12 +31,10 @@
import com.android.systemui.util.kotlin.combine
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
/**
* Models UI of [BiometricPromptLayout.iconView] and [BiometricPromptLayout.biometric_icon_overlay]
@@ -58,11 +55,8 @@
}
/**
- * Indicates what auth type the UI currently displays.
- * Fingerprint-only auth -> Fingerprint
- * Face-only auth -> Face
- * Co-ex auth, implicit flow -> Face
- * Co-ex auth, explicit flow -> Coex
+ * Indicates what auth type the UI currently displays. Fingerprint-only auth -> Fingerprint
+ * Face-only auth -> Face Co-ex auth, implicit flow -> Face Co-ex auth, explicit flow -> Coex
*/
val activeAuthType: Flow<AuthType> =
combine(
@@ -119,35 +113,6 @@
_previousIconOverlayWasError.value = previousIconOverlayWasError
}
- /** Called when iconView begins animating. */
- fun onAnimationStart() {
- _animationEnded.value = false
- }
-
- /** Called when iconView ends animating. */
- fun onAnimationEnd() {
- _animationEnded.value = true
- }
-
- private val _animationEnded: MutableStateFlow<Boolean> = MutableStateFlow(false)
-
- /**
- * Whether a face iconView should pulse (i.e. while isAuthenticating and previous animation
- * ended).
- */
- val shouldPulseAnimation: Flow<Boolean> =
- combine(_animationEnded, promptViewModel.isAuthenticating) {
- animationEnded,
- isAuthenticating ->
- animationEnded && isAuthenticating
- }
- .distinctUntilChanged()
-
- private val _lastPulseLightToDark: MutableStateFlow<Boolean> = MutableStateFlow(false)
-
- /** Tracks whether a face iconView last pulsed light to dark (vs. dark to light) */
- val lastPulseLightToDark: Flow<Boolean> = _lastPulseLightToDark.asStateFlow()
-
val iconSize: Flow<Pair<Int, Int>> =
combine(
promptViewModel.position,
@@ -195,35 +160,22 @@
}
}
AuthType.Face ->
- shouldPulseAnimation.flatMapLatest { shouldPulseAnimation: Boolean ->
- if (shouldPulseAnimation) {
- val iconAsset =
- if (_lastPulseLightToDark.value) {
- R.drawable.face_dialog_pulse_dark_to_light
- } else {
- R.drawable.face_dialog_pulse_light_to_dark
- }
- _lastPulseLightToDark.value = !_lastPulseLightToDark.value
- flowOf(iconAsset)
- } else {
- combine(
- promptViewModel.isAuthenticated.distinctUntilChanged(),
- promptViewModel.isAuthenticating.distinctUntilChanged(),
- promptViewModel.isPendingConfirmation.distinctUntilChanged(),
- promptViewModel.showingError.distinctUntilChanged()
- ) {
- authState: PromptAuthState,
- isAuthenticating: Boolean,
- isPendingConfirmation: Boolean,
- showingError: Boolean ->
- getFaceIconViewAsset(
- authState,
- isAuthenticating,
- isPendingConfirmation,
- showingError
- )
- }
- }
+ combine(
+ promptViewModel.isAuthenticated.distinctUntilChanged(),
+ promptViewModel.isAuthenticating.distinctUntilChanged(),
+ promptViewModel.isPendingConfirmation.distinctUntilChanged(),
+ promptViewModel.showingError.distinctUntilChanged()
+ ) {
+ authState: PromptAuthState,
+ isAuthenticating: Boolean,
+ isPendingConfirmation: Boolean,
+ showingError: Boolean ->
+ getFaceIconViewAsset(
+ authState,
+ isAuthenticating,
+ isPendingConfirmation,
+ showingError
+ )
}
AuthType.Coex ->
combine(
@@ -327,8 +279,7 @@
} else if (authState.isAuthenticated) {
R.drawable.face_dialog_dark_to_checkmark
} else if (isAuthenticating) {
- _lastPulseLightToDark.value = false
- R.drawable.face_dialog_pulse_dark_to_light
+ R.raw.face_dialog_authenticating
} else if (showingError) {
R.drawable.face_dialog_dark_to_error
} else if (_previousIconWasError.value) {
@@ -703,16 +654,6 @@
}
}
- /** Whether the current BiometricPromptLayout.iconView asset animation should be repeated. */
- val shouldRepeatAnimation: Flow<Boolean> =
- activeAuthType.flatMapLatest { activeAuthType: AuthType ->
- when (activeAuthType) {
- AuthType.Fingerprint,
- AuthType.Coex -> flowOf(false)
- AuthType.Face -> promptViewModel.isAuthenticating.map { it }
- }
- }
-
/** Called on configuration changes */
fun onConfigurationChanged(newConfig: Configuration) {
displayStateInteractor.onConfigurationChanged(newConfig)
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
index 207f7db..f320057 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
@@ -221,7 +221,8 @@
(view) -> {
// TODO: b/321969740 - Take the userHandle as a parameter and pass it through.
// The package name is not sufficient to unambiguously identify an app.
- mMediaOutputDialogManager.createAndShow(mOutputPackageName, true, null, null);
+ mMediaOutputDialogManager.createAndShow(
+ mOutputPackageName, true, null, null, null);
dialog.dismiss();
});
cancelBtn.setOnClickListener((view) -> {
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 c0dc313..650852c 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
@@ -35,7 +35,6 @@
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
@@ -138,14 +137,6 @@
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
)
@@ -170,8 +161,6 @@
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/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 3462164..93f3793 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -69,6 +69,7 @@
import com.android.systemui.inputmethod.InputMethodModule;
import com.android.systemui.keyboard.KeyboardModule;
import com.android.systemui.keyevent.data.repository.KeyEventRepositoryModule;
+import com.android.systemui.keyguard.ui.composable.LockscreenContent;
import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule;
import com.android.systemui.log.dagger.LogModule;
@@ -364,6 +365,9 @@
@BindsOptionalOf
abstract FingerprintReEnrollNotification optionalFingerprintReEnrollNotification();
+ @BindsOptionalOf
+ abstract LockscreenContent optionalLockscreenContent();
+
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
index 846013c..9919f09 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
@@ -30,17 +30,20 @@
import com.android.systemui.deviceentry.shared.model.FingerprintLockoutMessage
import com.android.systemui.deviceentry.shared.model.FingerprintMessage
import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
+import com.android.systemui.keyguard.domain.interactor.DevicePostureInteractor
+import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.res.R
-import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -59,6 +62,7 @@
faceAuthInteractor: DeviceEntryFaceAuthInteractor,
private val biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor,
faceHelpMessageDeferralInteractor: FaceHelpMessageDeferralInteractor,
+ devicePostureInteractor: DevicePostureInteractor,
) {
private val faceHelp: Flow<HelpFaceAuthenticationStatus> =
faceAuthInteractor.authenticationStatus.filterIsInstance<HelpFaceAuthenticationStatus>()
@@ -71,9 +75,18 @@
* The acquisition message ids to show message when both fingerprint and face are enrolled and
* enabled for device entry.
*/
- private val coExFaceAcquisitionMsgIdsToShow: Set<Int> =
+ private val coExFaceAcquisitionMsgIdsToShowDefault: Set<Int> =
resources.getIntArray(R.array.config_face_help_msgs_when_fingerprint_enrolled).toSet()
+ /**
+ * The acquisition message ids to show message when both fingerprint and face are enrolled and
+ * enabled for device entry and the device is unfolded.
+ */
+ private val coExFaceAcquisitionMsgIdsToShowUnfolded: Set<Int> =
+ resources
+ .getIntArray(R.array.config_face_help_msgs_when_fingerprint_enrolled_unfolded)
+ .toSet()
+
private fun ErrorFingerprintAuthenticationStatus.shouldSuppressError(): Boolean {
return isCancellationError() || isPowerPressedError()
}
@@ -122,6 +135,17 @@
}
}
+ val coExFaceAcquisitionMsgIdsToShow: Flow<Set<Int>> =
+ devicePostureInteractor.posture.map { devicePosture ->
+ when (devicePosture) {
+ DevicePosture.OPENED -> coExFaceAcquisitionMsgIdsToShowUnfolded
+ DevicePosture.UNKNOWN, // Devices without posture support (non-foldable) use UNKNOWN
+ DevicePosture.CLOSED,
+ DevicePosture.HALF_OPENED,
+ DevicePosture.FLIPPED -> coExFaceAcquisitionMsgIdsToShowDefault
+ }
+ }
+
val fingerprintMessage: Flow<FingerprintMessage> =
merge(
fingerprintErrorMessage,
@@ -129,25 +153,38 @@
fingerprintHelpMessage,
)
+ private val filterConditionForFaceHelpMessages:
+ Flow<(HelpFaceAuthenticationStatus) -> Boolean> =
+ combine(
+ biometricSettingsInteractor.isFingerprintAuthEnrolledAndEnabled,
+ biometricSettingsInteractor.faceAuthCurrentlyAllowed,
+ ::Pair
+ )
+ .flatMapLatest { (fingerprintEnrolled, faceAuthCurrentlyAllowed) ->
+ if (fingerprintEnrolled && faceAuthCurrentlyAllowed) {
+ // Show only some face help messages if fingerprint is also enrolled
+ coExFaceAcquisitionMsgIdsToShow.map { msgIdsToShow ->
+ { helpStatus: HelpFaceAuthenticationStatus ->
+ msgIdsToShow.contains(helpStatus.msgId)
+ }
+ }
+ } else if (faceAuthCurrentlyAllowed) {
+ // Show all face help messages if only face is enrolled and currently allowed
+ flowOf { _: HelpFaceAuthenticationStatus -> true }
+ } else {
+ flowOf { _: HelpFaceAuthenticationStatus -> false }
+ }
+ }
+
private val faceHelpMessage: Flow<FaceMessage> =
faceHelp
.filterNot {
// Message deferred to potentially show at face timeout error instead
faceHelpMessageDeferralInteractor.shouldDefer(it.msgId)
}
- .sample(biometricSettingsInteractor.fingerprintAndFaceEnrolledAndEnabled, ::Pair)
- .filter { (faceAuthHelpStatus, fingerprintAndFaceEnrolledAndEnabled) ->
- if (fingerprintAndFaceEnrolledAndEnabled) {
- // Show only some face help messages if fingerprint is also enrolled
- coExFaceAcquisitionMsgIdsToShow.contains(faceAuthHelpStatus.msgId)
- } else {
- // Show all face help messages if only face is enrolled
- true
- }
- }
- .sample(biometricSettingsInteractor.faceAuthCurrentlyAllowed, ::toTriple)
- .filter { (_, _, faceAuthCurrentlyAllowed) -> faceAuthCurrentlyAllowed }
- .map { (status, _, _) -> FaceMessage(status.msg) }
+ .sample(filterConditionForFaceHelpMessages, ::Pair)
+ .filter { (helpMessage, filterCondition) -> filterCondition(helpMessage) }
+ .map { (status, _) -> FaceMessage(status.msg) }
private val faceFailureMessage: Flow<FaceMessage> =
faceFailure
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
index a32b2aa..6ca8eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
@@ -36,6 +36,9 @@
val authenticated: Flow<Boolean>
+ /** Whether bypass is enabled. If enabled, face unlock dismisses the lock screen. */
+ val isBypassEnabled: Flow<Boolean>
+
/** Can face auth be run right now */
fun canFaceAuthRun(): Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
index 80b52ed..6c6d730 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.deviceentry.domain.interactor
import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
+import com.android.systemui.biometrics.shared.model.SensorLocation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
@@ -58,4 +59,17 @@
flowOf(false)
}
}
+
+ /**
+ * Location of the under-display fingerprint sensor on the display. Null if the device does not
+ * support UDFPS.
+ */
+ val udfpsLocation: Flow<SensorLocation?> =
+ isUdfpsSupported.flatMapLatest {
+ if (it) {
+ fingerprintPropertyInteractor.sensorLocation
+ } else {
+ flowOf(null)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
index 6629f6e..9486798 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
@@ -22,6 +22,7 @@
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flowOf
/**
* Implementation of the interactor that noops all face auth operations.
@@ -35,6 +36,7 @@
override val detectionStatus: Flow<FaceDetectionStatus> = emptyFlow()
override val lockedOut: Flow<Boolean> = emptyFlow()
override val authenticated: Flow<Boolean> = emptyFlow()
+ override val isBypassEnabled: Flow<Boolean> = flowOf(false)
override fun canFaceAuthRun(): Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index 669cd94..87f3f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -286,6 +286,7 @@
override val detectionStatus = repository.detectionStatus
override val lockedOut: Flow<Boolean> = repository.isLockedOut
override val authenticated: Flow<Boolean> = repository.isAuthenticated
+ override val isBypassEnabled: Flow<Boolean> = repository.isBypassEnabled
private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) {
if (repository.isLockedOut.value) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
index ee3706a..a0b25b9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
@@ -32,6 +32,8 @@
public class KeyguardIndication {
@Nullable
private final CharSequence mMessage;
+ @Nullable
+ private final boolean mForceAccessibilityLiveRegionAssertive;
@NonNull
private final ColorStateList mTextColor;
@Nullable
@@ -49,13 +51,15 @@
Drawable icon,
View.OnClickListener onClickListener,
Drawable background,
- Long minVisibilityMillis) {
+ Long minVisibilityMillis,
+ Boolean foceAssertive) {
mMessage = message;
mTextColor = textColor;
mIcon = icon;
mOnClickListener = onClickListener;
mBackground = background;
mMinVisibilityMillis = minVisibilityMillis;
+ mForceAccessibilityLiveRegionAssertive = foceAssertive;
}
/**
@@ -101,6 +105,15 @@
return mMinVisibilityMillis;
}
+
+ /**
+ * Whether to force the accessibility live region to be assertive.
+ */
+ public boolean getForceAssertiveAccessibilityLiveRegion() {
+ return mForceAccessibilityLiveRegionAssertive;
+ }
+
+
@Override
public String toString() {
String str = "KeyguardIndication{";
@@ -109,6 +122,7 @@
if (mOnClickListener != null) str += " mOnClickListener=" + mOnClickListener;
if (mBackground != null) str += " mBackground=" + mBackground;
if (mMinVisibilityMillis != null) str += " mMinVisibilityMillis=" + mMinVisibilityMillis;
+ if (mForceAccessibilityLiveRegionAssertive) str += "mForceAccessibilityLiveRegionAssertive";
str += "}";
return str;
}
@@ -123,6 +137,7 @@
private ColorStateList mTextColor;
private Drawable mBackground;
private Long mMinVisibilityMillis;
+ private boolean mForceAccessibilityLiveRegionAssertive;
public Builder() { }
@@ -178,6 +193,14 @@
}
/**
+ * Optional. Can force the accessibility live region to be assertive for this message.
+ */
+ public Builder setForceAccessibilityLiveRegionAssertive() {
+ this.mForceAccessibilityLiveRegionAssertive = true;
+ return this;
+ }
+
+ /**
* Build the KeyguardIndication.
*/
public KeyguardIndication build() {
@@ -190,7 +213,7 @@
return new KeyguardIndication(
mMessage, mTextColor, mIcon, mOnClickListener, mBackground,
- mMinVisibilityMillis);
+ mMinVisibilityMillis, mForceAccessibilityLiveRegionAssertive);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 674c128..9cdba58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -68,6 +68,7 @@
import android.window.TransitionInfo;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.foldables.FoldGracePeriodProvider;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -84,20 +85,25 @@
import com.android.systemui.keyguard.ui.viewmodel.WindowManagerLockscreenVisibilityViewModel;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.power.shared.model.ScreenPowerState;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
import com.android.systemui.settings.DisplayTracker;
import com.android.wm.shell.shared.CounterRotator;
import com.android.wm.shell.shared.ShellTransitions;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.transition.Transitions;
+import dagger.Lazy;
+
+import kotlinx.coroutines.CoroutineScope;
+
import java.util.ArrayList;
import java.util.Map;
import java.util.WeakHashMap;
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineScope;
-
public class KeyguardService extends Service {
static final String TAG = "KeyguardService";
static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
@@ -109,6 +115,7 @@
private final ShellTransitions mShellTransitions;
private final DisplayTracker mDisplayTracker;
private final PowerInteractor mPowerInteractor;
+ private final Lazy<SceneInteractor> mSceneInteractorLazy;
private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
@@ -302,6 +309,13 @@
private final WindowManagerOcclusionManager mWmOcclusionManager;
+ private final Lazy<FoldGracePeriodProvider> mFoldGracePeriodProvider = new Lazy<>() {
+ @Override
+ public FoldGracePeriodProvider get() {
+ return new FoldGracePeriodProvider();
+ }
+ };
+
@Inject
public KeyguardService(
KeyguardViewMediator keyguardViewMediator,
@@ -316,7 +330,8 @@
@Application CoroutineScope scope,
FeatureFlags featureFlags,
PowerInteractor powerInteractor,
- WindowManagerOcclusionManager windowManagerOcclusionManager) {
+ WindowManagerOcclusionManager windowManagerOcclusionManager,
+ Lazy<SceneInteractor> sceneInteractorLazy) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
@@ -325,6 +340,7 @@
mDisplayTracker = displayTracker;
mFlags = featureFlags;
mPowerInteractor = powerInteractor;
+ mSceneInteractorLazy = sceneInteractorLazy;
if (KeyguardWmStateRefactor.isEnabled()) {
WindowManagerLockscreenVisibilityViewBinder.bind(
@@ -601,6 +617,11 @@
trace("showDismissibleKeyguard");
checkPermission();
mKeyguardViewMediator.showDismissibleKeyguard();
+
+ if (SceneContainerFlag.isEnabled() && mFoldGracePeriodProvider.get().isEnabled()) {
+ mSceneInteractorLazy.get().changeScene(
+ Scenes.Lockscreen, "KeyguardService.showDismissibleKeyguard");
+ }
}
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
index 956125c..a1e4af5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
@@ -51,10 +51,6 @@
) : KeyguardSmartspaceRepository {
private val _bcSmartspaceVisibility: MutableStateFlow<Int> = MutableStateFlow(View.GONE)
override val bcSmartspaceVisibility: StateFlow<Int> = _bcSmartspaceVisibility.asStateFlow()
- val defaultValue =
- context.resources.getBoolean(
- com.android.internal.R.bool.config_lockscreenWeatherEnabledByDefault
- )
override val isWeatherEnabled: StateFlow<Boolean> =
secureSettings
.observerFlow(
@@ -76,7 +72,7 @@
private fun getLockscreenWeatherEnabled(): Boolean {
return secureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED,
- if (defaultValue) 1 else 0,
+ 1,
userTracker.userId
) == 1
}
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 7655d7a..f488d3b 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
@@ -34,6 +34,7 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -42,6 +43,7 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.sync.Mutex
/**
* The source of truth for all keyguard transitions.
@@ -129,6 +131,7 @@
private var lastStep: TransitionStep = TransitionStep()
private var lastAnimator: ValueAnimator? = null
+ private val _currentTransitionMutex = Mutex()
private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
MutableStateFlow(
TransitionInfo(
@@ -146,6 +149,9 @@
*/
private var updateTransitionId: UUID? = null
+ // Only used in a test environment
+ var forceDelayForRaceConditionTest = false
+
init {
// Start with a FINISHED transition in OFF. KeyguardBootInteractor will transition from OFF
// to either GONE or LOCKSCREEN once we're booted up and can determine which state we should
@@ -162,9 +168,21 @@
override suspend fun startTransition(info: TransitionInfo): UUID? {
_currentTransitionInfo.value = info
+ Log.d(TAG, "(Internal) Setting current transition info: $info")
+
+ // There is no fairness guarantee with 'withContext', which means that transitions could
+ // be processed out of order. Use a Mutex to guarantee ordering.
+ _currentTransitionMutex.lock()
+
+ // Only used in a test environment
+ if (forceDelayForRaceConditionTest) {
+ delay(50L)
+ }
// Animators must be started on the main thread.
return withContext("$TAG#startTransition", mainDispatcher) {
+ _currentTransitionMutex.unlock()
+
if (lastStep.from == info.from && lastStep.to == info.to) {
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return@withContext null
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractor.kt
new file mode 100644
index 0000000..e48cddb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractor.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.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.DevicePostureRepository
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/** DevicePosture business logic. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DevicePostureInteractor
+@Inject
+constructor(devicePostureRepository: DevicePostureRepository) {
+ val posture = devicePostureRepository.currentDevicePosture
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
index 8ec831c..28d4ba96 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
@@ -20,7 +20,9 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.Edge
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.smartspace.SmartspaceState
import javax.inject.Inject
@@ -50,7 +52,10 @@
*/
val transitioningToGoneWithInWindowAnimation: StateFlow<Boolean> =
transitionInteractor
- .isInTransitionToState(KeyguardState.GONE)
+ .isInTransition(
+ edge = Edge.create(to = Scenes.Gone),
+ edgeWithoutSceneContainer = Edge.create(to = GONE)
+ )
.map { transitioningToGone -> transitioningToGone && isLauncherUnderneath() }
.stateIn(scope, SharingStarted.Eagerly, false)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index b1ef76e..7cee258 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -20,7 +20,6 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Context
-import android.util.Log
import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
@@ -43,7 +42,6 @@
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@SysUISingleton
@@ -80,15 +78,7 @@
private val refreshEvents: Flow<Unit> =
merge(
configurationInteractor.onAnyConfigurationChange,
- fingerprintPropertyInteractor.propertiesInitialized
- .filter { it }
- .map { Unit }
- .onEach {
- Log.d(
- "KeyguardBlueprintInteractor",
- "triggering refreshEvent from fpPropertiesInitialized"
- )
- },
+ fingerprintPropertyInteractor.propertiesInitialized.filter { it }.map {},
)
init {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 75c4d6f..cf6942e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -56,12 +56,6 @@
}
scope.launch {
- sharedNotificationContainerViewModel
- .getMaxNotifications { height, useExtraShelfSpace -> height.toInt() }
- .collect { logger.log(TAG, VERBOSE, "Notif: max height in px", it) }
- }
-
- scope.launch {
sharedNotificationContainerViewModel.isOnLockscreen.collect {
logger.log(TAG, VERBOSE, "Notif: isOnLockscreen", it)
}
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 c65dc30..2766b71 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
@@ -180,7 +180,7 @@
val fromScene =
when (edge) {
is Edge.StateToState -> edge.from?.mapToSceneContainerScene()
- is Edge.StateToScene -> edge.from.mapToSceneContainerScene()
+ is Edge.StateToScene -> edge.from?.mapToSceneContainerScene()
is Edge.SceneToState -> edge.from
}
@@ -188,7 +188,7 @@
when (edge) {
is Edge.StateToState -> edge.to?.mapToSceneContainerScene()
is Edge.StateToScene -> edge.to
- is Edge.SceneToState -> edge.to.mapToSceneContainerScene()
+ is Edge.SceneToState -> edge.to?.mapToSceneContainerScene()
}
fun SceneKey?.isLockscreenOrNull() = this == Scenes.Lockscreen || this == null
@@ -450,16 +450,6 @@
}
}
- /** Whether we're in a transition to the given [KeyguardState], but haven't yet completed it. */
- fun isInTransitionToState(
- state: KeyguardState,
- ): Flow<Boolean> {
- return transition(Edge.create(from = null, to = state))
- .mapLatest { it.transitionState.isTransitioning() }
- .onStart { emit(false) }
- .distinctUntilChanged()
- }
-
/**
* Whether we're in a transition to and from the given [KeyguardState]s, but haven't yet
* completed it.
@@ -469,23 +459,23 @@
*/
fun isInTransition(edge: Edge, edgeWithoutSceneContainer: Edge? = null): Flow<Boolean> {
return if (SceneContainerFlag.isEnabled) {
- transition(edge)
+ if (edge.isSceneWildcardEdge()) {
+ sceneInteractor.get().transitionState.map {
+ when (edge) {
+ is Edge.StateToState ->
+ throw IllegalStateException("Should not be reachable.")
+ is Edge.SceneToState -> it.isTransitioning(from = edge.from)
+ is Edge.StateToScene -> it.isTransitioning(to = edge.to)
+ }
+ }
+ } else {
+ transition(edge).mapLatest { it.transitionState.isTransitioning() }
+ }
} else {
- transition(edgeWithoutSceneContainer ?: edge)
+ transition(edgeWithoutSceneContainer ?: edge).mapLatest {
+ it.transitionState.isTransitioning()
+ }
}
- .mapLatest { it.transitionState.isTransitioning() }
- .onStart { emit(false) }
- .distinctUntilChanged()
- }
-
- /**
- * Whether we're in a transition out of the given [KeyguardState], but haven't yet completed it.
- */
- fun isInTransitionFromState(
- state: KeyguardState,
- ): Flow<Boolean> {
- return transition(Edge.create(from = state, to = null))
- .mapLatest { it.transitionState.isTransitioning() }
.onStart { emit(false) }
.distinctUntilChanged()
}
@@ -494,7 +484,7 @@
* Whether we're in a transition to a [KeyguardState] that matches the given predicate, but
* haven't yet completed it.
*
- * If you only care about a single state, instead use the optimized [isInTransitionToState].
+ * If you only care about a single state, instead use the optimized [isInTransition].
*/
fun isInTransitionToStateWhere(
stateMatcher: (KeyguardState) -> Boolean,
@@ -506,7 +496,7 @@
* Whether we're in a transition out of a [KeyguardState] that matches the given predicate, but
* haven't yet completed it.
*
- * If you only care about a single state, instead use the optimized [isInTransitionFromState].
+ * If you only care about a single state, instead use the optimized [isInTransition].
*/
fun isInTransitionFromStateWhere(
stateMatcher: (KeyguardState) -> Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index b2a24ca..323ceef 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -229,6 +229,7 @@
startTransitionTo(
toState = KeyguardState.OCCLUDED,
modeOnCanceled = TransitionModeOnCanceled.RESET,
+ ownerReason = "keyguardInteractor.onCameraLaunchDetected",
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 1e2db7c..8ba09bd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.keyguard.domain.interactor
-import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -26,8 +28,8 @@
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
-import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -48,7 +50,8 @@
fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
- sceneInteractor: SceneInteractor,
+ sceneInteractor: Lazy<SceneInteractor>,
+ deviceEntryInteractor: Lazy<DeviceEntryInteractor>,
) {
private val defaultSurfaceBehindVisibility =
transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -112,7 +115,7 @@
val usingKeyguardGoingAwayAnimation: Flow<Boolean> =
if (SceneContainerFlag.isEnabled) {
combine(
- sceneInteractor.transitionState,
+ sceneInteractor.get().transitionState,
surfaceBehindInteractor.isAnimatingSurface,
notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
) { transition, isAnimatingSurface, isLaunchAnimationRunning ->
@@ -130,7 +133,10 @@
.distinctUntilChanged()
} else {
combine(
- transitionInteractor.isInTransitionToState(KeyguardState.GONE),
+ transitionInteractor.isInTransition(
+ edge = Edge.create(to = Scenes.Gone),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
+ ),
transitionInteractor.finishedKeyguardState,
surfaceBehindInteractor.isAnimatingSurface,
notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
@@ -156,19 +162,7 @@
*/
val lockscreenVisibility: Flow<Boolean> =
if (SceneContainerFlag.isEnabled) {
- sceneInteractor.transitionState
- .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen))
- .map { (prevTransitionState, transitionState) ->
- val isReturningToGoneAfterCancellation =
- prevTransitionState.isTransitioning(from = Scenes.Gone) &&
- transitionState.isTransitioning(to = Scenes.Gone)
- val isNotOnGone =
- !transitionState.isTransitioning(from = Scenes.Gone) &&
- !transitionState.isIdle(Scenes.Gone)
-
- isNotOnGone && !isReturningToGoneAfterCancellation
- }
- .distinctUntilChanged()
+ deviceEntryInteractor.get().isDeviceEntered.map { !it }
} else {
transitionInteractor.currentKeyguardState
.sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
index 4f516f5..c1e8d22 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
@@ -23,11 +23,6 @@
/**
* Represents an edge either between two Keyguard Transition Framework states (KTF) or a KTF state
* and a scene container scene. Passing [null] in either [from] or [to] indicates a wildcard.
- *
- * Wildcards are not allowed for transitions involving a scene. Use [sceneInteractor] directly
- * instead. Reason: [TransitionStep]s are not emitted for every edge leading into/out of a scene.
- * For example: Lockscreen -> Gone would be emitted as LOCKSCREEN -> UNDEFINED but Bouncer -> Gone
- * would not emit anything.
*/
sealed class Edge {
@@ -59,17 +54,6 @@
Please remove or port this edge to scene container."""
.trimIndent(),
)
- } else if ((fromChanged && to == null) || (toChanged && from == null)) {
- Log.e(
- TAG,
- """
- The edge ${from?.name} => ${to?.name} was automatically converted to
- ${mappedFrom?.name} => ${mappedTo?.name}. Wildcards are not allowed together
- with UNDEFINED because it will only be tracking edges leading in and out of
- the Lockscreen scene but miss others. Please remove or port this edge."""
- .trimIndent(),
- Exception()
- )
} else if (fromChanged || toChanged) {
Log.w(
TAG,
@@ -90,23 +74,32 @@
}
}
+ fun isSceneWildcardEdge(): Boolean {
+ return when (this) {
+ is StateToState -> false
+ is SceneToState -> to == null
+ is StateToScene -> from == null
+ }
+ }
+
data class StateToState(val from: KeyguardState?, val to: KeyguardState?) : Edge() {
+
init {
check(!(from == null && to == null)) { "to and from can't both be null" }
}
}
- data class StateToScene(val from: KeyguardState, val to: SceneKey) : Edge()
+ data class StateToScene(val from: KeyguardState? = null, val to: SceneKey) : Edge()
- data class SceneToState(val from: SceneKey, val to: KeyguardState) : Edge()
+ data class SceneToState(val from: SceneKey, val to: KeyguardState? = null) : Edge()
companion object {
private const val TAG = "Edge"
fun create(from: KeyguardState? = null, to: KeyguardState? = null) = StateToState(from, to)
- fun create(from: KeyguardState, to: SceneKey) = StateToScene(from, to)
+ fun create(from: KeyguardState? = null, to: SceneKey) = StateToScene(from, to)
- fun create(from: SceneKey, to: KeyguardState) = SceneToState(from, to)
+ fun create(from: SceneKey, to: KeyguardState? = null) = SceneToState(from, to)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index 18022a9..6550937 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -188,23 +188,30 @@
view.repeatWhenAttached { alternateBouncerViewContainer ->
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch("$TAG#viewModel.registerForDismissGestures") {
- viewModel.registerForDismissGestures.collect { registerForDismissGestures ->
- if (registerForDismissGestures) {
- swipeUpAnywhereGestureHandler.addOnGestureDetectedCallback(swipeTag) { _
- ->
- alternateBouncerDependencies.powerInteractor.onUserTouch()
- viewModel.showPrimaryBouncer()
+ viewModel.registerForDismissGestures.collect { registerForDismissGestures ->
+ if (registerForDismissGestures) {
+ swipeUpAnywhereGestureHandler.addOnGestureDetectedCallback(
+ swipeTag
+ ) { _ ->
+ alternateBouncerDependencies.powerInteractor.onUserTouch()
+ viewModel.showPrimaryBouncer()
+ }
+ tapGestureDetector.addOnGestureDetectedCallback(tapTag) { _ ->
+ alternateBouncerDependencies.powerInteractor.onUserTouch()
+ viewModel.showPrimaryBouncer()
+ }
+ } else {
+ swipeUpAnywhereGestureHandler.removeOnGestureDetectedCallback(
+ swipeTag
+ )
+ tapGestureDetector.removeOnGestureDetectedCallback(tapTag)
}
- tapGestureDetector.addOnGestureDetectedCallback(tapTag) { _ ->
- alternateBouncerDependencies.powerInteractor.onUserTouch()
- viewModel.showPrimaryBouncer()
- }
- } else {
- swipeUpAnywhereGestureHandler.removeOnGestureDetectedCallback(swipeTag)
- tapGestureDetector.removeOnGestureDetectedCallback(tapTag)
}
}
- }
+ .invokeOnCompletion {
+ swipeUpAnywhereGestureHandler.removeOnGestureDetectedCallback(swipeTag)
+ tapGestureDetector.removeOnGestureDetectedCallback(tapTag)
+ }
launch("$TAG#viewModel.scrimAlpha") {
viewModel.scrimAlpha.collect { scrim.viewAlpha = it }
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 c846cbe..f2821a0 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
@@ -37,7 +37,6 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.clocks.AodClockBurnInModel
import com.android.systemui.plugins.clocks.ClockController
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
object KeyguardClockViewBinder {
@@ -113,24 +112,17 @@
launch {
if (!MigrateClocksToBlueprint.isEnabled) return@launch
- combine(
- rootViewModel.translationX,
- rootViewModel.translationY,
- rootViewModel.scale,
- ::Triple
- )
- .collect { (translationX, translationY, scale) ->
- viewModel.currentClock.value
- ?.largeClock
- ?.layout
- ?.applyAodBurnIn(
- AodClockBurnInModel(
- translationX = translationX.value!!,
- translationY = translationY,
- scale = scale.scale
- )
+ rootViewModel.burnInModel.collect { burnInModel ->
+ viewModel.currentClock.value?.let {
+ it.largeClock.layout.applyAodBurnIn(
+ AodClockBurnInModel(
+ translationX = burnInModel.translationX.toFloat(),
+ translationY = burnInModel.translationY.toFloat(),
+ scale = burnInModel.scale
)
+ )
}
+ }
}
}
}
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 bda5be4..fb1853f 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
@@ -631,7 +631,7 @@
// color will need to use wallpaper's extracted color and consider if the
// wallpaper's color is dark or light.
val style = themeStyle ?: fetchThemeStyleFromSetting().also { themeStyle = it }
- val wallpaperColorScheme = ColorScheme(colors, darkTheme = false, style)
+ val wallpaperColorScheme = ColorScheme(colors, false, style)
val lightClockColor = wallpaperColorScheme.accent1.s100
val darkClockColor = wallpaperColorScheme.accent2.s600
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 29041d1..0b8376a 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
@@ -21,6 +21,7 @@
import android.graphics.Point
import android.graphics.Rect
import android.util.DisplayMetrics
+import android.util.Log
import android.view.View
import android.view.WindowManager
import androidx.annotation.VisibleForTesting
@@ -116,6 +117,10 @@
override fun applyConstraints(constraintSet: ConstraintSet) {
val isUdfpsSupported =
if (DeviceEntryUdfpsRefactor.isEnabled) {
+ Log.d(
+ "DefaultDeviceEntrySection",
+ "isUdfpsSupported=${deviceEntryIconViewModel.get().isUdfpsSupported.value}"
+ )
deviceEntryIconViewModel.get().isUdfpsSupported.value
} else {
authController.isUdfpsSupported
@@ -138,8 +143,24 @@
val iconRadiusPx = (defaultDensity * 36).toInt()
if (isUdfpsSupported) {
- authController.udfpsLocation?.let { udfpsLocation ->
- centerIcon(udfpsLocation, authController.udfpsRadius, constraintSet)
+ if (DeviceEntryUdfpsRefactor.isEnabled) {
+ deviceEntryIconViewModel.get().udfpsLocation.value?.let { udfpsLocation ->
+ Log.d(
+ "DeviceEntrySection",
+ "udfpsLocation=$udfpsLocation" +
+ " unusedAuthController=${authController.udfpsLocation}"
+ )
+ centerIcon(
+ Point(udfpsLocation.centerX.toInt(), udfpsLocation.centerY.toInt()),
+ udfpsLocation.radius,
+ constraintSet
+ )
+ }
+ } else {
+ authController.udfpsLocation?.let { udfpsLocation ->
+ Log.d("DeviceEntrySection", "udfpsLocation=$udfpsLocation")
+ centerIcon(udfpsLocation, authController.udfpsRadius, constraintSet)
+ }
}
} else {
centerIcon(
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 1e5f5a7..acaa15e 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
@@ -25,6 +25,10 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -40,28 +44,57 @@
goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
keyguardInteractor: KeyguardInteractor,
+ sceneInteractor: SceneInteractor,
) {
/** The alpha level for the entire lockscreen while in AOD. */
val alpha: Flow<Float> =
- combineTransform(
- keyguardTransitionInteractor.transitions,
- goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
- goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
- keyguardInteractor.keyguardAlpha.onStart { emit(1f) },
- ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha ->
- if (step.to == GONE) {
- // When transitioning to GONE, only emit a value when complete as other
- // transitions may be controlling the alpha fade
- if (step.value == 1f) {
+ if (SceneContainerFlag.isEnabled) {
+ combineTransform(
+ keyguardTransitionInteractor.transitions,
+ sceneInteractor.transitionState,
+ goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
+ goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
+ keyguardInteractor.keyguardAlpha.onStart { emit(1f) },
+ ) { step, sceneTransitionState, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha ->
+ if (sceneTransitionState.isIdle(Scenes.Gone)) {
emit(0f)
+ } else if (
+ step.from == UNDEFINED &&
+ step.to == AOD &&
+ sceneTransitionState.isTransitioning(Scenes.Gone, Scenes.Lockscreen)
+ ) {
+ emit(goneToAodAlpha)
+ } else if (
+ step.from == UNDEFINED &&
+ step.to == DOZING &&
+ sceneTransitionState.isTransitioning(Scenes.Gone, Scenes.Lockscreen)
+ ) {
+ emit(goneToDozingAlpha)
+ } else if (!MigrateClocksToBlueprint.isEnabled) {
+ emit(keyguardAlpha)
}
- } else if (step.from == GONE && step.to == AOD) {
- emit(goneToAodAlpha)
- } else if (step.from == GONE && step.to == DOZING) {
- emit(goneToDozingAlpha)
- } else if (!MigrateClocksToBlueprint.isEnabled) {
- emit(keyguardAlpha)
+ }
+ } else {
+ combineTransform(
+ keyguardTransitionInteractor.transitions,
+ goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
+ goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
+ keyguardInteractor.keyguardAlpha.onStart { emit(1f) },
+ ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha ->
+ if (step.to == GONE) {
+ // When transitioning to GONE, only emit a value when complete as other
+ // transitions may be controlling the alpha fade
+ if (step.value == 1f) {
+ emit(0f)
+ }
+ } else if (step.from == GONE && step.to == AOD) {
+ emit(goneToAodAlpha)
+ } else if (step.from == GONE && step.to == DOZING) {
+ emit(goneToDozingAlpha)
+ } else if (!MigrateClocksToBlueprint.isEnabled) {
+ emit(keyguardAlpha)
+ }
}
}
}
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 ae83c9e..fa43ec2 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
@@ -20,6 +20,7 @@
import android.animation.IntEvaluator
import com.android.keyguard.KeyguardViewController
import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import com.android.systemui.biometrics.shared.model.SensorLocation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -73,6 +74,12 @@
@Application private val scope: CoroutineScope,
) {
val isUdfpsSupported: StateFlow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
+ val udfpsLocation: StateFlow<SensorLocation?> =
+ deviceEntryUdfpsInteractor.udfpsLocation.stateIn(
+ scope = scope,
+ started = SharingStarted.Eagerly,
+ initialValue = null,
+ )
private val intEvaluator = IntEvaluator()
private val floatEvaluator = FloatEvaluator()
private val showingAlternateBouncer: Flow<Boolean> =
@@ -200,19 +207,24 @@
.distinctUntilChanged()
private val isUnlocked: Flow<Boolean> =
- keyguardInteractor.isKeyguardDismissible.flatMapLatest { isUnlocked ->
- if (!isUnlocked) {
- flowOf(false)
+ if (SceneContainerFlag.isEnabled) {
+ deviceEntryInteractor.isUnlocked
} else {
- flow {
- // delay in case device ends up transitioning away from the lock screen;
- // we don't want to animate to the unlocked icon and just let the
- // icon fade with the transition to GONE
- delay(UNLOCKED_DELAY_MS)
- emit(true)
+ keyguardInteractor.isKeyguardDismissible
+ }
+ .flatMapLatest { isUnlocked ->
+ if (!isUnlocked) {
+ flowOf(false)
+ } else {
+ flow {
+ // delay in case device ends up transitioning away from the lock screen;
+ // we don't want to animate to the unlocked icon and just let the
+ // icon fade with the transition to GONE
+ delay(UNLOCKED_DELAY_MS)
+ emit(true)
+ }
}
}
- }
val iconType: Flow<DeviceEntryIconView.IconType> =
combine(
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 f405b9d..aaec69f 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
@@ -58,6 +58,7 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -117,7 +118,8 @@
private val shadeInteractor: ShadeInteractor,
) {
private var burnInJob: Job? = null
- internal val burnInModel = MutableStateFlow(BurnInModel())
+ private val _burnInModel = MutableStateFlow(BurnInModel())
+ val burnInModel = _burnInModel.asStateFlow()
val burnInLayerVisibility: Flow<Int> =
keyguardTransitionInteractor.startedKeyguardState
@@ -140,8 +142,8 @@
combine(
keyguardTransitionInteractor.isFinishedInState(LOCKSCREEN).onStart { emit(false) },
anyOf(
- keyguardTransitionInteractor.isInTransitionToState(LOCKSCREEN),
- keyguardTransitionInteractor.isInTransitionFromState(LOCKSCREEN),
+ keyguardTransitionInteractor.isInTransition(Edge.create(to = LOCKSCREEN)),
+ keyguardTransitionInteractor.isInTransition(Edge.create(from = LOCKSCREEN)),
),
) { onLockscreen, transitioningToOrFromLockscreen ->
onLockscreen || transitioningToOrFromLockscreen
@@ -279,7 +281,7 @@
burnInJob =
scope.launch("$TAG#aodBurnInViewModel") {
- aodBurnInViewModel.movement(params).collect { burnInModel.value = it }
+ aodBurnInViewModel.movement(params).collect { _burnInModel.value = it }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index c98f3b0..b33eaa2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -18,7 +18,6 @@
import android.content.res.Resources
import com.android.internal.annotations.VisibleForTesting
-import com.android.keyguard.KeyguardClockSwitch.SMALL
import com.android.systemui.biometrics.AuthController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -48,7 +47,7 @@
val longPress: KeyguardLongPressViewModel,
val shadeInteractor: ShadeInteractor,
@Application private val applicationScope: CoroutineScope,
- private val unfoldTransitionInteractor: UnfoldTransitionInteractor,
+ unfoldTransitionInteractor: UnfoldTransitionInteractor,
) {
@VisibleForTesting val clockSize = clockInteractor.clockSize
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 043fbfa..486d4d4 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
@@ -102,7 +102,8 @@
return
}
val controller = data.token?.let { controllerFactory.create(it) }
- val localMediaManager = localMediaManagerFactory.create(data.packageName)
+ val localMediaManager =
+ localMediaManagerFactory.create(data.packageName, controller?.sessionToken)
val muteAwaitConnectionManager =
muteAwaitConnectionManagerFactory.create(localMediaManager)
entry = Entry(key, oldKey, controller, localMediaManager, muteAwaitConnectionManager)
@@ -224,9 +225,9 @@
}
@WorkerThread
- override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
- val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
- val newPlaybackVolumeControlId = info?.volumeControlId
+ override fun onAudioInfoChanged(info: MediaController.PlaybackInfo) {
+ val newPlaybackType = info.playbackType
+ val newPlaybackVolumeControlId = info.volumeControlId
if (
newPlaybackType == playbackType &&
newPlaybackVolumeControlId == playbackVolumeControlId
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
index 1a0f582..3f75938 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
@@ -155,11 +155,16 @@
return false
}
- fun startMediaOutputDialog(expandable: Expandable, packageName: String) {
+ fun startMediaOutputDialog(
+ expandable: Expandable,
+ packageName: String,
+ token: MediaSession.Token? = null
+ ) {
mediaOutputDialogManager.createAndShowWithController(
packageName,
true,
- expandable.dialogController()
+ expandable.dialogController(),
+ token = token,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 0bc3c439..5ec4f88 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -743,7 +743,8 @@
mPackageName,
/* aboveStatusBar */ true,
mMediaViewHolder.getSeamlessButton(),
- UserHandle.getUserHandleForUid(mUid));
+ UserHandle.getUserHandleForUid(mUid),
+ mToken);
}
} else {
mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
@@ -775,7 +776,8 @@
mPackageName,
/* aboveStatusBar */ true,
mMediaViewHolder.getSeamlessButton(),
- UserHandle.getUserHandleForUid(mUid));
+ UserHandle.getUserHandleForUid(mUid),
+ mToken);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
index 3b09f41..c97221e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
@@ -107,7 +107,7 @@
return try {
// Set up media source app's logo.
val icon = applicationContext.packageManager.getApplicationIcon(packageName)
- ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme = true, style)
+ ColorScheme(WallpaperColors.fromDrawable(icon), true, style)
} catch (e: PackageManager.NameNotFoundException) {
Log.w(tag, "Fail to get media app info", e)
null
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
index 1944f07..099991d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
@@ -231,12 +231,20 @@
)
} else {
logger.logOpenOutputSwitcher(model.uid, model.packageName, model.instanceId)
- interactor.startMediaOutputDialog(expandable, model.packageName)
+ interactor.startMediaOutputDialog(
+ expandable,
+ model.packageName,
+ model.token
+ )
}
} else {
logger.logOpenOutputSwitcher(model.uid, model.packageName, model.instanceId)
device?.intent?.let { interactor.startDeviceIntent(it) }
- ?: interactor.startMediaOutputDialog(expandable, model.packageName)
+ ?: interactor.startMediaOutputDialog(
+ expandable,
+ model.packageName,
+ model.token
+ )
}
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/LocalMediaManagerFactory.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/LocalMediaManagerFactory.kt
index ff8e903b..0a717ad 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/LocalMediaManagerFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/LocalMediaManagerFactory.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media.controls.util
import android.content.Context
+import android.media.session.MediaSession
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.media.InfoMediaManager
import com.android.settingslib.media.LocalMediaManager
@@ -30,10 +31,16 @@
private val localBluetoothManager: LocalBluetoothManager?
) {
/** Creates a [LocalMediaManager] for the given package. */
- fun create(packageName: String?): LocalMediaManager {
+ fun create(packageName: String?, token: MediaSession.Token? = null): LocalMediaManager {
// TODO: b/321969740 - Populate the userHandle parameter in InfoMediaManager. The user
// handle is necessary to disambiguate the same package running on different users.
- return InfoMediaManager.createInstance(context, packageName, null, localBluetoothManager)
+ return InfoMediaManager.createInstance(
+ context,
+ packageName,
+ null,
+ localBluetoothManager,
+ token
+ )
.run { LocalMediaManager(context, localBluetoothManager, this, packageName) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 6a6eba1..1e7bc0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -54,5 +54,6 @@
fun isSceneContainerEnabled() = SceneContainerFlag.isEnabled
/** Check whether to use media refactor code */
- fun isMediaControlsRefactorEnabled() = MediaControlsRefactorFlag.isEnabled
+ fun isMediaControlsRefactorEnabled() =
+ MediaControlsRefactorFlag.isEnabled && SceneContainerFlag.isEnabled
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
index 06267e2..6ef9ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
@@ -40,7 +40,12 @@
// TODO: b/321969740 - Populate the userHandle parameter. The user handle is necessary to
// disambiguate the same package running on different users.
- val controller = mediaOutputControllerFactory.create(packageName, /* userHandle= */ null)
+ val controller =
+ mediaOutputControllerFactory.create(
+ packageName,
+ /* userHandle= */ null,
+ /* token */ null,
+ )
val dialog =
MediaOutputBroadcastDialog(context, aboveStatusBar, broadcastSender, controller)
mediaOutputBroadcastDialog = dialog
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index d6ca320..c2cfdbe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -78,6 +78,7 @@
import com.android.settingslib.media.InfoMediaManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.media.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.animation.DialogTransitionAnimator;
@@ -141,6 +142,7 @@
private final KeyguardManager mKeyGuardManager;
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
+ private final MediaSession.Token mToken;
@VisibleForTesting
boolean mIsRefreshing = false;
@@ -179,6 +181,7 @@
Context context,
@Assisted String packageName,
@Assisted @Nullable UserHandle userHandle,
+ @Assisted @Nullable MediaSession.Token token,
MediaSessionManager mediaSessionManager,
@Nullable LocalBluetoothManager lbm,
ActivityStarter starter,
@@ -202,8 +205,9 @@
mKeyGuardManager = keyGuardManager;
mFeatureFlags = featureFlags;
mUserTracker = userTracker;
+ mToken = token;
InfoMediaManager imm =
- InfoMediaManager.createInstance(mContext, packageName, userHandle, lbm);
+ InfoMediaManager.createInstance(mContext, packageName, userHandle, lbm, token);
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mDialogTransitionAnimator = dialogTransitionAnimator;
@@ -235,7 +239,8 @@
@AssistedFactory
public interface Factory {
/** Construct a MediaOutputController */
- MediaOutputController create(String packageName, UserHandle userHandle);
+ MediaOutputController create(
+ String packageName, UserHandle userHandle, MediaSession.Token token);
}
protected void start(@NonNull Callback cb) {
@@ -297,23 +302,28 @@
}
private MediaController getMediaController() {
- for (NotificationEntry entry : mNotifCollection.getAllNotifs()) {
- final Notification notification = entry.getSbn().getNotification();
- if (notification.isMediaNotification()
- && TextUtils.equals(entry.getSbn().getPackageName(), mPackageName)) {
- MediaSession.Token token = notification.extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION,
- MediaSession.Token.class);
- return new MediaController(mContext, token);
+ if (mToken != null && Flags.usePlaybackInfoForRoutingControls()) {
+ return new MediaController(mContext, mToken);
+ } else {
+ for (NotificationEntry entry : mNotifCollection.getAllNotifs()) {
+ final Notification notification = entry.getSbn().getNotification();
+ if (notification.isMediaNotification()
+ && TextUtils.equals(entry.getSbn().getPackageName(), mPackageName)) {
+ MediaSession.Token token =
+ notification.extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class);
+ return new MediaController(mContext, token);
+ }
}
- }
- for (MediaController controller : mMediaSessionManager.getActiveSessionsForUser(null,
- mUserTracker.getUserHandle())) {
- if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
- return controller;
+ for (MediaController controller :
+ mMediaSessionManager.getActiveSessionsForUser(
+ null, mUserTracker.getUserHandle())) {
+ if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
+ return controller;
+ }
}
+ return null;
}
- return null;
}
@Override
@@ -869,10 +879,6 @@
mMetricLogger.logInteractionUnmute(device);
}
- String getPackageName() {
- return mPackageName;
- }
-
boolean hasAdjustVolumeUserRestriction() {
if (RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_ADJUST_VOLUME, UserHandle.myUserId()) != null) {
@@ -955,6 +961,7 @@
mContext,
mPackageName,
mUserHandle,
+ mToken,
mMediaSessionManager,
mLocalBluetoothManager,
mActivityStarter,
@@ -1060,7 +1067,7 @@
boolean isBroadcastSupported() {
LocalBluetoothLeBroadcast broadcast =
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
- return broadcast != null ? true : false;
+ return broadcast != null;
}
boolean isBluetoothLeBroadcastEnabled() {
@@ -1194,13 +1201,6 @@
assistant.unregisterServiceCallBack(callback);
}
- private boolean isPlayBackInfoLocal() {
- return mMediaController != null
- && mMediaController.getPlaybackInfo() != null
- && mMediaController.getPlaybackInfo().getPlaybackType()
- == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
- }
-
boolean isPlaying() {
if (mMediaController == null) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
index 04d1492..ee816942 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media.dialog
import android.content.Context
+import android.media.session.MediaSession
import android.os.UserHandle
import android.view.View
import com.android.internal.jank.InteractionJankMonitor
@@ -49,7 +50,8 @@
packageName: String,
aboveStatusBar: Boolean,
view: View? = null,
- userHandle: UserHandle? = null
+ userHandle: UserHandle? = null,
+ token: MediaSession.Token? = null
) {
createAndShowWithController(
packageName,
@@ -65,6 +67,7 @@
)
},
userHandle = userHandle,
+ token = token,
)
}
@@ -77,6 +80,7 @@
aboveStatusBar: Boolean,
controller: DialogTransitionAnimator.Controller?,
userHandle: UserHandle? = null,
+ token: MediaSession.Token? = null,
) {
createAndShow(
packageName,
@@ -84,6 +88,7 @@
dialogTransitionAnimatorController = controller,
includePlaybackAndAppMetadata = true,
userHandle = userHandle,
+ token = token,
)
}
@@ -108,11 +113,12 @@
dialogTransitionAnimatorController: DialogTransitionAnimator.Controller?,
includePlaybackAndAppMetadata: Boolean = true,
userHandle: UserHandle? = null,
+ token: MediaSession.Token? = null,
) {
// Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
- val controller = mediaOutputControllerFactory.create(packageName, userHandle)
+ val controller = mediaOutputControllerFactory.create(packageName, userHandle, token)
val mediaOutputDialog =
MediaOutputDialog(
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
index 9cc2888..846460e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
@@ -56,7 +56,11 @@
public void showMediaOutputSwitcher(String packageName, UserHandle userHandle) {
if (!TextUtils.isEmpty(packageName)) {
mMediaOutputDialogManager.createAndShow(
- packageName, /* aboveStatusBar= */ false, /* view= */ null, userHandle);
+ packageName,
+ /* aboveStatusBar= */ false,
+ /* view= */ null,
+ userHandle,
+ /* token */ null);
} else {
Log.e(TAG, "Unable to launch media output dialog. Package name is empty.");
}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index a144dc2..c8e896d 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -84,7 +84,9 @@
SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it.scene != Scenes.Gone },
SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to
{
- it.scene == Scenes.NotificationsShade || it.scene == Scenes.Shade
+ it.scene == Scenes.Lockscreen ||
+ it.scene == Scenes.NotificationsShade ||
+ it.scene == Scenes.Shade
},
SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
{
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
index 2cc3985..d161c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -29,14 +29,17 @@
import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import com.android.systemui.qs.panels.shared.model.StretchedGridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
+import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout
import com.android.systemui.qs.panels.ui.compose.StretchedGridLayout
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet
+import javax.inject.Named
@Module
interface PanelsModule {
@@ -50,6 +53,8 @@
impl: NoopGridConsistencyInteractor
): GridTypeConsistencyInteractor
+ @Binds @Named("Default") fun bindDefaultGridLayout(impl: PartitionedGridLayout): GridLayout
+
companion object {
@Provides
@SysUISingleton
@@ -73,6 +78,14 @@
}
@Provides
+ @IntoSet
+ fun providePartitionedGridLayout(
+ gridLayout: PartitionedGridLayout
+ ): Pair<GridLayoutType, GridLayout> {
+ return Pair(PartitionedGridLayoutType, gridLayout)
+ }
+
+ @Provides
fun provideGridLayoutMap(
entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridLayout>>
): Map<GridLayoutType, GridLayout> {
@@ -103,6 +116,14 @@
}
@Provides
+ @IntoSet
+ fun providePartitionedGridConsistencyInteractor(
+ consistencyInteractor: NoopGridConsistencyInteractor
+ ): Pair<GridLayoutType, GridTypeConsistencyInteractor> {
+ return Pair(PartitionedGridLayoutType, consistencyInteractor)
+ }
+
+ @Provides
fun provideGridConsistencyInteractorMap(
entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridTypeConsistencyInteractor>>
): Map<GridLayoutType, GridTypeConsistencyInteractor> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
index 31795d5..44d8688 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.shared.model.GridLayoutType
-import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -31,7 +31,8 @@
@SysUISingleton
class GridLayoutTypeRepositoryImpl @Inject constructor() : GridLayoutTypeRepository {
- private val _layout: MutableStateFlow<GridLayoutType> = MutableStateFlow(InfiniteGridLayoutType)
+ private val _layout: MutableStateFlow<GridLayoutType> =
+ MutableStateFlow(PartitionedGridLayoutType)
override val layout = _layout.asStateFlow()
override fun setLayout(type: GridLayoutType) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
index 501730a..9550ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
@@ -31,3 +31,6 @@
* spaces.
*/
data object StretchedGridLayoutType : GridLayoutType
+
+/** Grid type grouping large tiles on top and icon tiles at the bottom. */
+data object PartitionedGridLayoutType : GridLayoutType
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
new file mode 100644
index 0000000..8d0b386
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
@@ -0,0 +1,252 @@
+/*
+ * 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.panels.ui.compose
+
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.GridItemSpan
+import androidx.compose.foundation.lazy.grid.LazyGridScope
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.modifiers.background
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor
+import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor
+import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+@SysUISingleton
+class PartitionedGridLayout
+@Inject
+constructor(
+ private val iconTilesInteractor: IconTilesInteractor,
+ private val gridSizeInteractor: InfiniteGridSizeInteractor,
+) : GridLayout {
+ @Composable
+ override fun TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+ DisposableEffect(tiles) {
+ val token = Any()
+ tiles.forEach { it.startListening(token) }
+ onDispose { tiles.forEach { it.stopListening(token) } }
+ }
+ val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+ val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
+ val tileHeight = dimensionResource(id = R.dimen.qs_tile_height)
+ val (smallTiles, largeTiles) = tiles.partition { iconTilesSpecs.contains(it.spec) }
+
+ TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
+ // Large tiles
+ items(largeTiles.size, span = { GridItemSpan(2) }) { index ->
+ Tile(
+ tile = largeTiles[index],
+ iconOnly = false,
+ modifier = Modifier.height(tileHeight)
+ )
+ }
+ fillUpRow(nTiles = largeTiles.size, columns = columns / 2)
+
+ // Small tiles
+ items(smallTiles.size) { index ->
+ Tile(
+ tile = smallTiles[index],
+ iconOnly = true,
+ modifier = Modifier.height(tileHeight)
+ )
+ }
+ }
+ }
+
+ @Composable
+ override fun EditTileGrid(
+ tiles: List<EditTileViewModel>,
+ modifier: Modifier,
+ onAddTile: (TileSpec, Int) -> Unit,
+ onRemoveTile: (TileSpec) -> Unit
+ ) {
+ val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+ val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
+
+ val (currentTiles, otherTiles) = tiles.partition { it.isCurrent }
+ val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
+ onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
+ }
+ val isIconOnly: (TileSpec) -> Boolean =
+ remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } }
+ val tileHeight = dimensionResource(id = R.dimen.qs_tile_height)
+ val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical)
+
+ Column(
+ verticalArrangement = Arrangement.spacedBy(tilePadding),
+ modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState())
+ ) {
+ CurrentTiles(
+ tiles = currentTiles,
+ tileHeight = tileHeight,
+ tilePadding = tilePadding,
+ onRemoveTile = onRemoveTile,
+ isIconOnly = isIconOnly,
+ columns = columns,
+ )
+ AvailableTiles(
+ tiles = otherTiles,
+ tileHeight = tileHeight,
+ tilePadding = tilePadding,
+ addTileToEnd = addTileToEnd,
+ isIconOnly = isIconOnly,
+ columns = columns,
+ )
+ }
+ }
+
+ @Composable
+ private fun CurrentTiles(
+ tiles: List<EditTileViewModel>,
+ tileHeight: Dp,
+ tilePadding: Dp,
+ onRemoveTile: (TileSpec) -> Unit,
+ isIconOnly: (TileSpec) -> Boolean,
+ columns: Int,
+ ) {
+ val (smallTiles, largeTiles) = tiles.partition { isIconOnly(it.tileSpec) }
+
+ val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding)
+ val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding)
+
+ CurrentTilesContainer {
+ TileLazyGrid(
+ columns = GridCells.Fixed(columns),
+ modifier = Modifier.height(largeGridHeight),
+ ) {
+ editTiles(largeTiles, ClickAction.REMOVE, onRemoveTile, { false }, true)
+ }
+ }
+ CurrentTilesContainer {
+ TileLazyGrid(
+ columns = GridCells.Fixed(columns),
+ modifier = Modifier.height(smallGridHeight),
+ ) {
+ editTiles(smallTiles, ClickAction.REMOVE, onRemoveTile, { true }, true)
+ }
+ }
+ }
+
+ @Composable
+ private fun AvailableTiles(
+ tiles: List<EditTileViewModel>,
+ tileHeight: Dp,
+ tilePadding: Dp,
+ addTileToEnd: (TileSpec) -> Unit,
+ isIconOnly: (TileSpec) -> Boolean,
+ columns: Int,
+ ) {
+ val (tilesStock, tilesCustom) = tiles.partition { it.appName == null }
+ val (smallTiles, largeTiles) = tilesStock.partition { isIconOnly(it.tileSpec) }
+
+ val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding)
+ val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding)
+ val largeGridHeightCustom =
+ gridHeight(tilesCustom.size, tileHeight, columns / 2, tilePadding)
+
+ // Add up the height of all three grids and add padding in between
+ val gridHeight =
+ largeGridHeight + smallGridHeight + largeGridHeightCustom + (tilePadding * 2)
+
+ AvailableTilesContainer {
+ TileLazyGrid(
+ columns = GridCells.Fixed(columns),
+ modifier = Modifier.height(gridHeight),
+ ) {
+ // Large tiles
+ editTiles(largeTiles, ClickAction.ADD, addTileToEnd, isIconOnly)
+ fillUpRow(nTiles = largeTiles.size, columns = columns / 2)
+
+ // Small tiles
+ editTiles(smallTiles, ClickAction.ADD, addTileToEnd, isIconOnly)
+ fillUpRow(nTiles = smallTiles.size, columns = columns)
+
+ // Custom tiles, all large
+ editTiles(tilesCustom, ClickAction.ADD, addTileToEnd, isIconOnly)
+ }
+ }
+ }
+
+ @Composable
+ private fun CurrentTilesContainer(content: @Composable () -> Unit) {
+ Box(
+ Modifier.fillMaxWidth()
+ .border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.onBackground,
+ shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+ )
+ .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
+ ) {
+ content()
+ }
+ }
+
+ @Composable
+ private fun AvailableTilesContainer(content: @Composable () -> Unit) {
+ Box(
+ Modifier.fillMaxWidth()
+ .background(
+ color = MaterialTheme.colorScheme.surfaceVariant,
+ alpha = { 1f },
+ shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+ )
+ .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
+ ) {
+ content()
+ }
+ }
+
+ private fun gridHeight(nTiles: Int, tileHeight: Dp, columns: Int, padding: Dp): Dp {
+ val rows = (nTiles + columns - 1) / columns
+ return ((tileHeight + padding) * rows) - padding
+ }
+
+ /** Fill up the rest of the row if it's not complete. */
+ private fun LazyGridScope.fillUpRow(nTiles: Int, columns: Int) {
+ if (nTiles % columns != 0) {
+ item(span = { GridItemSpan(maxCurrentLineSpan) }) { Spacer(Modifier) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index eb45110..e8c65a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -208,7 +208,7 @@
}
}
-private fun LazyGridScope.editTiles(
+fun LazyGridScope.editTiles(
tiles: List<EditTileViewModel>,
clickAction: ClickAction,
onClick: (TileSpec) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
index 69f50a7..5b4186c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
@@ -22,12 +22,12 @@
import com.android.systemui.qs.panels.domain.interactor.GridLayoutTypeInteractor
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor.Companion.POSITION_AT_END
import com.android.systemui.qs.pipeline.domain.interactor.MinimumTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -47,7 +47,7 @@
private val editTilesListInteractor: EditTilesListInteractor,
private val currentTilesInteractor: CurrentTilesInteractor,
private val minTilesInteractor: MinimumTilesInteractor,
- private val defaultGridLayout: InfiniteGridLayout,
+ @Named("Default") private val defaultGridLayout: GridLayout,
@Application private val applicationScope: CoroutineScope,
gridLayoutTypeInteractor: GridLayoutTypeInteractor,
gridLayoutMap: Map<GridLayoutType, @JvmSuppressWildcards GridLayout>,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
index 5eee691..127ecb2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
@@ -21,9 +21,9 @@
import com.android.systemui.qs.panels.domain.interactor.GridLayoutTypeInteractor
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -41,7 +41,7 @@
gridLayoutTypeInteractor: GridLayoutTypeInteractor,
gridLayoutMap: Map<GridLayoutType, @JvmSuppressWildcards GridLayout>,
tilesInteractor: CurrentTilesInteractor,
- defaultGridLayout: InfiniteGridLayout,
+ @Named("Default") defaultGridLayout: GridLayout,
@Application private val applicationScope: CoroutineScope
) {
val gridLayout: StateFlow<GridLayout> =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 4fd0df4..c6dfdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -148,7 +148,8 @@
*/
protected var showRippleEffect = true
- private lateinit var qsTileBackground: LayerDrawable
+ private lateinit var qsTileBackground: RippleDrawable
+ private lateinit var qsTileFocusBackground: Drawable
private lateinit var backgroundDrawable: LayerDrawable
private lateinit var backgroundBaseDrawable: Drawable
private lateinit var backgroundOverlayDrawable: Drawable
@@ -313,10 +314,11 @@
private fun createTileBackground(): Drawable {
qsTileBackground = if (Flags.qsTileFocusState()) {
- mContext.getDrawable(R.drawable.qs_tile_background_flagged) as LayerDrawable
+ mContext.getDrawable(R.drawable.qs_tile_background_flagged) as RippleDrawable
} else {
mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
}
+ qsTileFocusBackground = mContext.getDrawable(R.drawable.qs_tile_focused_background)!!
backgroundDrawable =
qsTileBackground.findDrawableByLayerId(R.id.background) as LayerDrawable
backgroundBaseDrawable =
@@ -332,6 +334,17 @@
updateHeight()
}
+ override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
+ if (Flags.qsTileFocusState()) {
+ if (gainFocus) {
+ qsTileFocusBackground.setBounds(0, 0, width, height)
+ overlay.add(qsTileFocusBackground)
+ } else {
+ overlay.clear()
+ }
+ }
+ }
private fun updateHeight() {
// TODO(b/332900989): Find a more robust way of resetting the tile if not reset by the
// launch animation.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractor.kt
index 85d2e3b..597825c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileDataInteractor.kt
@@ -17,70 +17,25 @@
package com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor
import android.os.UserHandle
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow
-import com.android.systemui.dagger.qualifiers.Background
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.screenrecord.domain.model.ScreenRecordTileModel
-import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import javax.inject.Inject
-import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.onStart
-/** Observes screen record state changes providing the [ScreenRecordTileModel]. */
+/** Observes screen record state changes providing the [ScreenRecordModel]. */
class ScreenRecordTileDataInteractor
@Inject
constructor(
- @Background private val bgCoroutineContext: CoroutineContext,
- private val recordingController: RecordingController,
-) : QSTileDataInteractor<ScreenRecordTileModel> {
+ private val screenRecordRepository: ScreenRecordRepository,
+) : QSTileDataInteractor<ScreenRecordModel> {
override fun tileData(
user: UserHandle,
triggers: Flow<DataUpdateTrigger>
- ): Flow<ScreenRecordTileModel> =
- ConflatedCallbackFlow.conflatedCallbackFlow {
- val callback =
- object : RecordingController.RecordingStateChangeCallback {
- override fun onRecordingStart() {
- trySend(ScreenRecordTileModel.Recording)
- }
- override fun onRecordingEnd() {
- trySend(ScreenRecordTileModel.DoingNothing)
- }
- override fun onCountdown(millisUntilFinished: Long) {
- trySend(ScreenRecordTileModel.Starting(millisUntilFinished))
- }
- override fun onCountdownEnd() {
- if (
- !recordingController.isRecording && !recordingController.isStarting
- ) {
- // The tile was in Starting state and got canceled before recording
- trySend(ScreenRecordTileModel.DoingNothing)
- }
- }
- }
- recordingController.addCallback(callback)
- awaitClose { recordingController.removeCallback(callback) }
- }
- .onStart { emit(generateModel()) }
- .distinctUntilChanged()
- .flowOn(bgCoroutineContext)
+ ): Flow<ScreenRecordModel> = screenRecordRepository.screenRecordState
override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
-
- private fun generateModel(): ScreenRecordTileModel {
- if (recordingController.isRecording) {
- return ScreenRecordTileModel.Recording
- } else if (recordingController.isStarting) {
- return ScreenRecordTileModel.Starting(0)
- } else {
- return ScreenRecordTileModel.DoingNothing
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
index 79766d6..79720c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
@@ -32,9 +32,9 @@
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
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.screenrecord.domain.model.ScreenRecordTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -55,19 +55,19 @@
private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
private val featureFlags: FeatureFlagsClassic,
private val activityStarter: ActivityStarter,
-) : QSTileUserActionInteractor<ScreenRecordTileModel> {
- override suspend fun handleInput(input: QSTileInput<ScreenRecordTileModel>): Unit =
+) : QSTileUserActionInteractor<ScreenRecordModel> {
+ override suspend fun handleInput(input: QSTileInput<ScreenRecordModel>): Unit =
with(input) {
when (action) {
is QSTileUserAction.Click -> {
when (data) {
- is ScreenRecordTileModel.Starting -> {
+ is ScreenRecordModel.Starting -> {
Log.d(TAG, "Cancelling countdown")
withContext(backgroundContext) { recordingController.cancelCountdown() }
}
- is ScreenRecordTileModel.Recording ->
+ is ScreenRecordModel.Recording ->
withContext(backgroundContext) { recordingController.stopRecording() }
- is ScreenRecordTileModel.DoingNothing ->
+ is ScreenRecordModel.DoingNothing ->
withContext(mainContext) {
showPrompt(action.expandable, user.identifier)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt
index c09b0e3..b58774b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt
@@ -21,26 +21,26 @@
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.screenrecord.domain.model.ScreenRecordTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import javax.inject.Inject
-/** Maps [ScreenRecordTileModel] to [QSTileState]. */
+/** Maps [ScreenRecordModel] to [QSTileState]. */
class ScreenRecordTileMapper
@Inject
constructor(
@Main private val resources: Resources,
private val theme: Resources.Theme,
-) : QSTileDataToStateMapper<ScreenRecordTileModel> {
- override fun map(config: QSTileConfig, data: ScreenRecordTileModel): QSTileState =
+) : QSTileDataToStateMapper<ScreenRecordModel> {
+ override fun map(config: QSTileConfig, data: ScreenRecordModel): QSTileState =
QSTileState.build(resources, theme, config.uiConfig) {
label = resources.getString(R.string.quick_settings_screen_record_label)
supportedActions = setOf(QSTileState.UserAction.CLICK)
when (data) {
- is ScreenRecordTileModel.Recording -> {
+ is ScreenRecordModel.Recording -> {
activationState = QSTileState.ActivationState.ACTIVE
val loadedIcon =
Icon.Loaded(
@@ -51,7 +51,7 @@
sideViewIcon = QSTileState.SideViewIcon.None
secondaryLabel = resources.getString(R.string.quick_settings_screen_record_stop)
}
- is ScreenRecordTileModel.Starting -> {
+ is ScreenRecordModel.Starting -> {
activationState = QSTileState.ActivationState.ACTIVE
val loadedIcon =
Icon.Loaded(
@@ -63,7 +63,7 @@
sideViewIcon = QSTileState.SideViewIcon.None
secondaryLabel = String.format("%d...", countDown)
}
- is ScreenRecordTileModel.DoingNothing -> {
+ is ScreenRecordModel.DoingNothing -> {
activationState = QSTileState.ActivationState.INACTIVE
val loadedIcon =
Icon.Loaded(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index 63acbb0..fb872d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -127,28 +127,28 @@
val isVisible: Boolean
val expansion: Float
- val squishiness: Float
+ val squishiness: () -> Float
data object CLOSED : State {
override val isVisible = false
override val expansion = 0f
- override val squishiness = 1f
+ override val squishiness = { 1f }
}
/** State for expanding between QQS and QS */
data class Expanding(override val expansion: Float) : State {
override val isVisible = true
- override val squishiness = 1f
+ override val squishiness = { 1f }
}
/** State for appearing QQS from Lockscreen or Gone */
- data class UnsquishingQQS(override val squishiness: Float) : State {
+ data class UnsquishingQQS(override val squishiness: () -> Float) : State {
override val isVisible = true
override val expansion = 0f
}
/** State for appearing QS from Lockscreen or Gone, used in Split shade */
- data class UnsquishingQS(override val squishiness: Float) : State {
+ data class UnsquishingQS(override val squishiness: () -> Float) : State {
override val isVisible = true
override val expansion = 1f
}
@@ -370,7 +370,7 @@
setQsVisible(state.isVisible)
setExpanded(state.isVisible && state.expansion > 0f)
setListening(state.isVisible)
- setQsExpansion(state.expansion, 1f, 0f, state.squishiness)
+ setQsExpansion(state.expansion, 1f, 0f, state.squishiness())
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 0d0f6e0..b1700e3 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -315,9 +315,17 @@
return false
}
- check(to != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked) {
- "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
- " change was: $loggingReason"
+ val inMidTransitionFromGone =
+ (transitionState.value as? ObservableTransitionState.Transition)?.fromScene ==
+ Scenes.Gone
+ val isChangeAllowed =
+ to != Scenes.Gone ||
+ inMidTransitionFromGone ||
+ deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked
+ check(isChangeAllowed) {
+ "Cannot change to the Gone scene while the device is locked and not currently" +
+ " transitioning from Gone. Current transition state is ${transitionState.value}." +
+ " Logging reason for scene change was: $loggingReason"
}
return from != to
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 3ce12dd..0304e73 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,6 +45,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.scene.data.model.asIterable
import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
@@ -365,6 +366,29 @@
private fun handlePowerState() {
applicationScope.launch {
+ powerInteractor.detailedWakefulness.collect { wakefulness ->
+ // Detect a double-tap-power-button gesture that was started while the device was
+ // still awake.
+ if (wakefulness.isAsleep()) return@collect
+ if (!wakefulness.powerButtonLaunchGestureTriggered) return@collect
+ if (wakefulness.lastSleepReason != WakeSleepReason.POWER_BUTTON) return@collect
+
+ // If we're mid-transition from Gone to Lockscreen due to the first power button
+ // press, then return to Gone.
+ val transition: ObservableTransitionState.Transition =
+ sceneInteractor.transitionState.value as? ObservableTransitionState.Transition
+ ?: return@collect
+ if (
+ transition.fromScene == Scenes.Gone && transition.toScene == Scenes.Lockscreen
+ ) {
+ switchToScene(
+ targetSceneKey = Scenes.Gone,
+ loggingReason = "double-tap power gesture",
+ )
+ }
+ }
+ }
+ applicationScope.launch {
powerInteractor.isAsleep.collect { isAsleep ->
if (isAsleep) {
switchToScene(
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt
index 8c675e3..8a60aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt
@@ -23,12 +23,14 @@
import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
import com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor.ScreenRecordTileDataInteractor
import com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor.ScreenRecordTileUserActionInteractor
-import com.android.systemui.qs.tiles.impl.screenrecord.domain.model.ScreenRecordTileModel
import com.android.systemui.qs.tiles.impl.screenrecord.domain.ui.ScreenRecordTileMapper
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -37,6 +39,9 @@
@Module
interface ScreenRecordModule {
+
+ @Binds fun bindScreenRecordRepository(impl: ScreenRecordRepositoryImpl): ScreenRecordRepository
+
/** Inject ScreenRecordTile into tileMap in QSModule */
@Binds
@IntoMap
@@ -65,7 +70,7 @@
@IntoMap
@StringKey(SCREEN_RECORD_TILE_SPEC)
fun provideScreenRecordTileViewModel(
- factory: QSTileViewModelFactory.Static<ScreenRecordTileModel>,
+ factory: QSTileViewModelFactory.Static<ScreenRecordModel>,
mapper: ScreenRecordTileMapper,
stateInteractor: ScreenRecordTileDataInteractor,
userActionInteractor: ScreenRecordTileUserActionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/model/ScreenRecordModel.kt
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/src/com/android/systemui/screenrecord/data/model/ScreenRecordModel.kt
index 26b0b01..b225444 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/model/ScreenRecordModel.kt
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.screenrecord.data.model
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
+/** Data model for the current state of screen recording. */
+sealed interface ScreenRecordModel {
+ /** There's an active screen recording happening. */
+ data object Recording : ScreenRecordModel
+
+ /** A screen recording will begin in [millisUntilStarted] ms. */
+ data class Starting(val millisUntilStarted: Long) : ScreenRecordModel
+
+ /** There's nothing related to screen recording happening. */
+ data object DoingNothing : ScreenRecordModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
new file mode 100644
index 0000000..d59d220
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.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.screenrecord.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+
+/**
+ * Repository storing information about the state of screen recording.
+ *
+ * Mostly a wrapper around [RecordingController] so that new screen-recording-related code can use
+ * recommended architecture.
+ */
+interface ScreenRecordRepository {
+ /** The current screen recording state. Note that this is a cold flow. */
+ val screenRecordState: Flow<ScreenRecordModel>
+}
+
+@SysUISingleton
+class ScreenRecordRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ private val recordingController: RecordingController,
+) : ScreenRecordRepository {
+
+ override val screenRecordState: Flow<ScreenRecordModel> =
+ conflatedCallbackFlow {
+ val callback =
+ object : RecordingController.RecordingStateChangeCallback {
+ override fun onRecordingStart() {
+ trySend(ScreenRecordModel.Recording)
+ }
+
+ override fun onRecordingEnd() {
+ trySend(ScreenRecordModel.DoingNothing)
+ }
+
+ override fun onCountdown(millisUntilFinished: Long) {
+ trySend(ScreenRecordModel.Starting(millisUntilFinished))
+ }
+
+ override fun onCountdownEnd() {
+ if (
+ !recordingController.isRecording && !recordingController.isStarting
+ ) {
+ // The recording was in Starting state but got canceled before
+ // actually starting
+ trySend(ScreenRecordModel.DoingNothing)
+ }
+ }
+ }
+ recordingController.addCallback(callback)
+ awaitClose { recordingController.removeCallback(callback) }
+ }
+ .onStart { emit(generateModel()) }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+
+ private fun generateModel(): ScreenRecordModel {
+ return if (recordingController.isRecording) {
+ ScreenRecordModel.Recording
+ } else if (recordingController.isStarting) {
+ ScreenRecordModel.Starting(0)
+ } else {
+ ScreenRecordModel.DoingNothing
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/AnnouncementResolver.kt b/packages/SystemUI/src/com/android/systemui/screenshot/AnnouncementResolver.kt
new file mode 100644
index 0000000..746f0f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/AnnouncementResolver.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.screenshot
+
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.screenshot.data.model.ProfileType
+import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
+import com.android.systemui.screenshot.resources.Messages
+import java.util.function.Consumer
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/** Logic for determining the announcement that a screenshot has been taken (for accessibility). */
+class AnnouncementResolver
+@Inject
+constructor(
+ private val messages: Messages,
+ private val profileTypes: ProfileTypeRepository,
+ @Application private val mainScope: CoroutineScope,
+) {
+
+ suspend fun getScreenshotAnnouncement(userId: Int): String =
+ when (profileTypes.getProfileType(userId)) {
+ ProfileType.PRIVATE -> messages.savingToPrivateProfileAnnouncement
+ ProfileType.WORK -> messages.savingToWorkProfileAnnouncement
+ else -> messages.savingScreenshotAnnouncement
+ }
+
+ fun getScreenshotAnnouncement(userId: Int, announceCallback: Consumer<String>) {
+ mainScope.launch { announceCallback.accept(getScreenshotAnnouncement(userId)) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java
index 12bff49..6ff1535 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java
@@ -89,9 +89,12 @@
// ActivityTaskManager interaction here is synchronous, so call off the main thread.
mSystemInteractionExecutor.execute(() -> {
try {
- mActivityTaskManager.requestAssistDataForTask(
+ boolean success = mActivityTaskManager.requestAssistDataForTask(
new AssistDataReceiver(callback, this), taskId, mPackageName,
mAttributionTag);
+ if (!success) {
+ callback.onAssistContentAvailable(null);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Requesting assist content failed for task: " + taskId, e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 9ad6d0f..4c60090 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.screenshotPrivateProfileAccessibilityAnnouncementFix;
import static com.android.systemui.Flags.screenshotShelfUi2;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
@@ -58,6 +59,7 @@
import android.view.Display;
import android.view.ScrollCaptureResponse;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
@@ -217,6 +219,7 @@
private final AssistContentRequester mAssistContentRequester;
private final MessageContainerController mMessageContainerController;
+ private final AnnouncementResolver mAnnouncementResolver;
private Bitmap mScreenBitmap;
private SaveImageInBackgroundTask mSaveInBgTask;
private boolean mScreenshotTakenInPortrait;
@@ -268,6 +271,7 @@
AssistContentRequester assistContentRequester,
MessageContainerController messageContainerController,
Provider<ScreenshotSoundController> screenshotSoundController,
+ AnnouncementResolver announcementResolver,
@Assisted Display display,
@Assisted boolean showUIOnExternalDisplay
) {
@@ -297,6 +301,7 @@
mUserManager = userManager;
mMessageContainerController = messageContainerController;
mAssistContentRequester = assistContentRequester;
+ mAnnouncementResolver = announcementResolver;
mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId());
@@ -460,12 +465,20 @@
void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
withWindowAttached(() -> {
- if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
- mViewProxy.announceForAccessibility(mContext.getResources().getString(
- R.string.screenshot_saving_work_profile_title));
+ if (screenshotPrivateProfileAccessibilityAnnouncementFix()) {
+ mAnnouncementResolver.getScreenshotAnnouncement(
+ screenshot.getUserHandle().getIdentifier(),
+ announcement -> {
+ mViewProxy.announceForAccessibility(announcement);
+ });
} else {
- mViewProxy.announceForAccessibility(
- mContext.getResources().getString(R.string.screenshot_saving_title));
+ if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
+ mViewProxy.announceForAccessibility(mContext.getResources().getString(
+ R.string.screenshot_saving_work_profile_title));
+ } else {
+ mViewProxy.announceForAccessibility(
+ mContext.getResources().getString(R.string.screenshot_saving_title));
+ }
}
});
@@ -699,6 +712,12 @@
mBlockAttach = true;
mWindowManager.addView(decorView, mWindowLayoutParams);
decorView.requestApplyInsets();
+
+ if (screenshotShelfUi2()) {
+ ViewGroup layout = decorView.requireViewById(android.R.id.content);
+ layout.setClipChildren(false);
+ layout.setClipToPadding(false);
+ }
}
void removeWindow() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/resources/Messages.kt b/packages/SystemUI/src/com/android/systemui/screenshot/resources/Messages.kt
new file mode 100644
index 0000000..fb10168
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/resources/Messages.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.resources
+
+import android.content.Context
+import androidx.annotation.OpenForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** String values from resources, for easy injection. */
+@OpenForTesting
+@SysUISingleton
+open class Messages @Inject constructor(private val context: Context) {
+ open val savingScreenshotAnnouncement by lazy {
+ requireNotNull(context.resources.getString(R.string.screenshot_saving_title))
+ }
+
+ open val savingToWorkProfileAnnouncement by lazy {
+ requireNotNull(context.resources.getString(R.string.screenshot_saving_work_profile_title))
+ }
+
+ open val savingToPrivateProfileAnnouncement by lazy {
+ requireNotNull(context.resources.getString(R.string.screenshot_saving_private_profile))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 6bb30c7..3826b50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -253,6 +253,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -449,6 +450,9 @@
private final ShadeHeadsUpTrackerImpl mShadeHeadsUpTracker = new ShadeHeadsUpTrackerImpl();
private final ShadeFoldAnimatorImpl mShadeFoldAnimator = new ShadeFoldAnimatorImpl();
+ @VisibleForTesting
+ Set<Animator> mTestSetOfAnimatorsUsed;
+
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
@@ -4149,6 +4153,8 @@
}
private void setAnimator(ValueAnimator animator) {
+ // TODO(b/341163515): Should we clean up the old animator?
+ registerAnimatorForTest(animator);
mHeightAnimator = animator;
if (animator == null && mPanelUpdateWhenAnimatorEnds) {
mPanelUpdateWhenAnimatorEnds = false;
@@ -4193,6 +4199,7 @@
private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
float startExpansion = mOverExpansion;
ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
+ registerAnimatorForTest(animator);
animator.addUpdateListener(
animation -> {
if (overshootAmount > 0.0f
@@ -4210,6 +4217,12 @@
return animator;
}
+ private void registerAnimatorForTest(Animator animator) {
+ if (mTestSetOfAnimatorsUsed != null && animator != null) {
+ mTestSetOfAnimatorsUsed.add(animator);
+ }
+ }
+
/** Update the visibility of {@link NotificationPanelView} if necessary. */
private void updateVisibility() {
mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 3eb4389..f67d0c1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -196,7 +196,7 @@
.getInteger(R.integer.config_keyguardRefreshRate);
float actualPreferredRefreshRate = -1;
if (desiredPreferredRefreshRate > -1) {
- for (Display.Mode displayMode : context.getDisplay().getSupportedModes()) {
+ for (Display.Mode displayMode : context.getDisplay().getSystemSupportedModes()) {
if (Math.abs(displayMode.getRefreshRate() - desiredPreferredRefreshRate) <= .1) {
actualPreferredRefreshRate = displayMode.getRefreshRate();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 9dc19b1..daea977 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -181,11 +181,8 @@
/**
* Returns true if heads up should be visible.
- *
- * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
- * [KeyguardStatusBarViewController] and remove this method.
*/
- @Deprecated("deprecated in Flexiglass.") fun shouldHeadsUpBeVisible(): Boolean
+ @Deprecated("deprecated by SceneContainerFlag.isEnabled.") fun shouldHeadsUpBeVisible(): Boolean
/** Return the fraction of the shade that's expanded, when in lockscreen. */
@Deprecated("deprecated by SceneContainerFlag.isEnabled") val lockscreenShadeDragProgress: Float
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 0de3c10..18407cc 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
@@ -38,6 +38,9 @@
/** Whether the Shade is fully expanded. */
val isShadeFullyExpanded: Flow<Boolean>
+ /** Whether the Shade is fully collapsed. */
+ val isShadeFullyCollapsed: Flow<Boolean>
+
/**
* Whether the user is expanding or collapsing either the shade or quick settings with user
* input (i.e. dragging a pointer). This will be true even if the user's input gesture had ended
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 883ef97..bb4baa3 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
@@ -38,6 +38,7 @@
override val anyExpansion: StateFlow<Float> = inactiveFlowFloat
override val isAnyFullyExpanded: StateFlow<Boolean> = inactiveFlowBoolean
override val isShadeFullyExpanded: Flow<Boolean> = inactiveFlowBoolean
+ override val isShadeFullyCollapsed: Flow<Boolean> = inactiveFlowBoolean
override val isAnyExpanded: StateFlow<Boolean> = inactiveFlowBoolean
override val isUserInteractingWithShade: Flow<Boolean> = inactiveFlowBoolean
override val isUserInteractingWithQs: Flow<Boolean> = inactiveFlowBoolean
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 0b45c08..4014512 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -21,6 +21,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
@@ -74,6 +75,9 @@
override val isShadeFullyExpanded: Flow<Boolean> =
baseShadeInteractor.shadeExpansion.map { it >= 1f }.distinctUntilChanged()
+ override val isShadeFullyCollapsed: Flow<Boolean> =
+ baseShadeInteractor.shadeExpansion.map { it <= 0f }.distinctUntilChanged()
+
override val isUserInteracting: StateFlow<Boolean> =
combine(isUserInteractingWithShade, isUserInteractingWithQs) { shade, qs -> shade || qs }
.distinctUntilChanged()
@@ -82,7 +86,7 @@
override val isShadeTouchable: Flow<Boolean> =
combine(
powerInteractor.isAsleep,
- keyguardTransitionInteractor.isInTransitionToState(KeyguardState.AOD),
+ keyguardTransitionInteractor.isInTransition(Edge.create(to = KeyguardState.AOD)),
keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },
) { isAsleep, goingToSleep, isPulsing ->
when {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2446473..8d8a36a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -97,6 +97,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
@@ -120,7 +121,6 @@
import java.io.PrintWriter;
import java.text.NumberFormat;
-import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
@@ -182,6 +182,7 @@
private BroadcastReceiver mBroadcastReceiver;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private KeyguardInteractor mKeyguardInteractor;
+ private final BiometricMessageInteractor mBiometricMessageInteractor;
private String mPersistentUnlockMessage;
private String mAlignmentIndication;
private boolean mForceIsDismissible;
@@ -212,7 +213,7 @@
private boolean mBatteryPresent = true;
protected long mChargingTimeRemaining;
private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn;
- private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
+ private Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
private boolean mInited;
@@ -230,6 +231,10 @@
mIsActiveDreamLockscreenHosted = isLockscreenHosted;
updateDeviceEntryIndication(false);
};
+ @VisibleForTesting
+ final Consumer<Set<Integer>> mCoExAcquisitionMsgIdsToShowCallback =
+ (Set<Integer> coExFaceAcquisitionMsgIdsToShow) -> mCoExFaceAcquisitionMsgIdsToShow =
+ coExFaceAcquisitionMsgIdsToShow;
private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
@Override
public void onScreenTurnedOn() {
@@ -289,7 +294,8 @@
BouncerMessageInteractor bouncerMessageInteractor,
FeatureFlags flags,
IndicationHelper indicationHelper,
- KeyguardInteractor keyguardInteractor
+ KeyguardInteractor keyguardInteractor,
+ BiometricMessageInteractor biometricMessageInteractor
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -318,14 +324,9 @@
mFeatureFlags = flags;
mIndicationHelper = indicationHelper;
mKeyguardInteractor = keyguardInteractor;
+ mBiometricMessageInteractor = biometricMessageInteractor;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral.create();
- mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
- int[] msgIds = context.getResources().getIntArray(
- com.android.systemui.res.R.array.config_face_help_msgs_when_fingerprint_enrolled);
- for (int msgId : msgIds) {
- mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
- }
mHandler = new Handler(mainLooper) {
@Override
@@ -372,7 +373,7 @@
mIndicationArea = indicationArea;
mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text);
mLockScreenIndicationView = indicationArea.findViewById(
- R.id.keyguard_indication_text_bottom);
+ R.id.keyguard_indication_text_bottom);
mInitialTextColorState = mTopIndicationView != null
? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
if (mRotateTextViewController != null) {
@@ -404,6 +405,10 @@
collectFlow(mIndicationArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
mIsActiveDreamLockscreenHostedCallback);
}
+
+ collectFlow(mIndicationArea,
+ mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow(),
+ mCoExAcquisitionMsgIdsToShowCallback);
}
/**
@@ -633,6 +638,7 @@
INDICATION_TYPE_BIOMETRIC_MESSAGE,
new KeyguardIndication.Builder()
.setMessage(mBiometricMessage)
+ .setForceAccessibilityLiveRegionAssertive()
.setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
.setTextColor(mInitialTextColorState)
.build(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
new file mode 100644
index 0000000..e85df0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.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.chips.call.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for the ongoing phone call chip shown in the status bar. */
+@SysUISingleton
+open class CallChipInteractor @Inject constructor() : OngoingActivityChipInteractor {
+ // TODO(b/332662551): Implement this flow.
+ override val chip: StateFlow<OngoingActivityChipModel> =
+ MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
new file mode 100644
index 0000000..70362c8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.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.statusbar.chips.domain.interactor
+
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interface for an interactor that knows the state of a single type of ongoing activity chip. */
+interface OngoingActivityChipInteractor {
+ /** A flow modeling the chip that should be shown. */
+ val chip: StateFlow<OngoingActivityChipModel>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
new file mode 100644
index 0000000..6f16969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.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.chips.screenrecord.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for the screen recording chip shown in the status bar. */
+@SysUISingleton
+open class ScreenRecordChipInteractor @Inject constructor() : OngoingActivityChipInteractor {
+ // TODO(b/332662551): Implement this flow.
+ override val chip: StateFlow<OngoingActivityChipModel> =
+ MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
new file mode 100644
index 0000000..e63713b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -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.systemui.statusbar.chips.ui.model
+
+import android.view.View
+import com.android.systemui.common.shared.model.Icon
+
+/** Model representing the display of an ongoing activity as a chip in the status bar. */
+sealed class OngoingActivityChipModel {
+ /** This chip shouldn't be shown. */
+ data object Hidden : OngoingActivityChipModel()
+
+ /** This chip should be shown with the given information. */
+ data class Shown(
+ /** The icon to show on the chip. */
+ val icon: Icon,
+ /**
+ * The time this event started, used to show the timer.
+ *
+ * This time should be relative to
+ * [com.android.systemui.util.time.SystemClock.elapsedRealtime], *not*
+ * [com.android.systemui.util.time.SystemClock.currentTimeMillis] because the
+ * [ChipChronometer] is based off of elapsed realtime. See
+ * [android.widget.Chronometer.setBase].
+ */
+ val startTimeMs: Long,
+ /** Listener method to invoke when this chip is clicked. */
+ val onClickListener: View.OnClickListener,
+ ) : OngoingActivityChipModel()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
new file mode 100644
index 0000000..47b2b03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.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.statusbar.chips.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * View model deciding which ongoing activity chip to show in the status bar.
+ *
+ * There may be multiple ongoing activities at the same time, but we can only ever show one chip at
+ * any one time (for now). This class decides which ongoing activity to show if there are multiple.
+ */
+@SysUISingleton
+class OngoingActivityChipsViewModel
+@Inject
+constructor(
+ @Application scope: CoroutineScope,
+ screenRecordChipInteractor: ScreenRecordChipInteractor,
+ callChipInteractor: CallChipInteractor,
+) {
+
+ /**
+ * A flow modeling the chip that should be shown in the status bar after accounting for possibly
+ * multiple ongoing activities.
+ *
+ * [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment] is responsible for
+ * actually displaying the chip.
+ */
+ val chip: StateFlow<OngoingActivityChipModel> =
+ combine(screenRecordChipInteractor.chip, callChipInteractor.chip) { screenRecord, call ->
+ // This `when` statement shows the priority order of the chips
+ when {
+ screenRecord is OngoingActivityChipModel.Shown -> screenRecord
+ else -> call
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 446a0d7..455c964 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -310,11 +310,9 @@
fun isWeatherEnabled(): Boolean {
execution.assertIsMainThread()
- val defaultValue = context.getResources().getBoolean(
- com.android.internal.R.bool.config_lockscreenWeatherEnabledByDefault)
val showWeather = secureSettings.getIntForUser(
LOCK_SCREEN_WEATHER_ENABLED,
- if (defaultValue) 1 else 0,
+ 1,
userTracker.userId) == 1
return showWeather
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index bd9383d..2f293e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -22,11 +22,13 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.util.DeviceConfigProxy
import com.android.systemui.util.Utils
@@ -53,6 +55,18 @@
}
fun getNotificationBuckets(): IntArray {
+ if (PriorityPeopleSection.isEnabled) {
+ // We don't need this list to be adaptive, it can be the superset of all features.
+ return intArrayOf(
+ BUCKET_MEDIA_CONTROLS,
+ BUCKET_HEADS_UP,
+ BUCKET_FOREGROUND_SERVICE,
+ BUCKET_PRIORITY_PEOPLE,
+ BUCKET_PEOPLE,
+ BUCKET_ALERTING,
+ BUCKET_SILENT,
+ )
+ }
return when {
isFilteringEnabled() && isMediaControlsEnabled() ->
intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
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 98b52ed..4a6553f 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
@@ -18,6 +18,10 @@
package com.android.systemui.statusbar.notification.domain.interactor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
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
@@ -29,13 +33,21 @@
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-class HeadsUpNotificationInteractor @Inject constructor(private val repository: HeadsUpRepository) {
+class HeadsUpNotificationInteractor
+@Inject
+constructor(
+ private val headsUpRepository: HeadsUpRepository,
+ private val faceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
+ private val shadeInteractor: ShadeInteractor,
+) {
- val topHeadsUpRow: Flow<HeadsUpRowKey?> = repository.topHeadsUpRow
+ val topHeadsUpRow: Flow<HeadsUpRowKey?> = headsUpRepository.topHeadsUpRow
/** Set of currently pinned top-level heads up rows to be displayed. */
val pinnedHeadsUpRows: Flow<Set<HeadsUpRowKey>> =
- repository.activeHeadsUpRows.flatMapLatest { repositories ->
+ headsUpRepository.activeHeadsUpRows.flatMapLatest { repositories ->
if (repositories.isNotEmpty()) {
val toCombine: List<Flow<Pair<HeadsUpRowRepository, Boolean>>> =
repositories.map { repo -> repo.isPinned.map { isPinned -> repo to isPinned } }
@@ -50,7 +62,7 @@
/** Are there any pinned heads up rows to display? */
val hasPinnedRows: Flow<Boolean> =
- repository.activeHeadsUpRows.flatMapLatest { rows ->
+ headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
if (rows.isNotEmpty()) {
combine(rows.map { it.isPinned }) { pins -> pins.any { it } }
} else {
@@ -60,15 +72,38 @@
}
val isHeadsUpOrAnimatingAway: Flow<Boolean> =
- combine(hasPinnedRows, repository.isHeadsUpAnimatingAway) { hasPinnedRows, animatingAway ->
+ combine(hasPinnedRows, headsUpRepository.isHeadsUpAnimatingAway) {
+ hasPinnedRows,
+ animatingAway ->
hasPinnedRows || animatingAway
}
+ private val canShowHeadsUp: Flow<Boolean> =
+ combine(
+ faceAuthInteractor.isBypassEnabled,
+ shadeInteractor.isShadeFullyCollapsed,
+ keyguardTransitionInteractor.currentKeyguardState,
+ notificationsKeyguardInteractor.areNotificationsFullyHidden,
+ ) { isBypassEnabled, isShadeCollapsed, keyguardState, areNotificationsHidden ->
+ val isOnLockScreen = keyguardState == KeyguardState.LOCKSCREEN
+ when {
+ areNotificationsHidden -> false // don't show when notification are hidden
+ !isShadeCollapsed -> false // don't show when the shade is expanded
+ isOnLockScreen -> isBypassEnabled // on the lock screen only show for bypass
+ else -> true // show otherwise
+ }
+ }
+
+ val showHeadsUpStatusBar: Flow<Boolean> =
+ combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
+ hasPinnedRows && canShowHeadsUp
+ }
+
fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
HeadsUpRowInteractor(key as HeadsUpRowRepository)
fun elementKeyFor(key: HeadsUpRowKey) = (key as HeadsUpRowRepository).elementKey
fun setHeadsUpAnimatingAway(animatingAway: Boolean) {
- repository.setHeadsUpAnimatingAway(animatingAway)
+ headsUpRepository.setHeadsUpAnimatingAway(animatingAway)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index a901c5f..87f11f13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.interruption
+import android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST
import android.app.Notification
import android.app.Notification.BubbleMetadata
import android.app.Notification.CATEGORY_EVENT
@@ -23,6 +24,8 @@
import android.app.Notification.VISIBILITY_PRIVATE
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.database.ContentObserver
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
@@ -234,6 +237,7 @@
private val avalancheProvider: AvalancheProvider,
private val systemClock: SystemClock,
private val systemSettings: SystemSettings,
+ private val packageManager: PackageManager,
) :
VisualInterruptionFilter(
types = setOf(PEEK, PULSE),
@@ -249,6 +253,7 @@
ALLOW_CATEGORY_EVENT,
ALLOW_FSI_WITH_PERMISSION_ON,
ALLOW_COLORIZED,
+ ALLOW_EMERGENCY,
SUPPRESS
}
@@ -299,13 +304,20 @@
if (entry.sbn.notification.isColorized) {
return State.ALLOW_COLORIZED
}
+ if (entry.sbn.notification.isColorized) {
+ return State.ALLOW_COLORIZED
+ }
+ if (
+ packageManager.checkPermission(RECEIVE_EMERGENCY_BROADCAST, entry.sbn.packageName) ==
+ PERMISSION_GRANTED
+ ) {
+ return State.ALLOW_EMERGENCY
+ }
return State.SUPPRESS
}
private fun isCooldownEnabled(): Boolean {
- return systemSettings.getInt(
- Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
- /* def */ 1
- ) == 1
+ return systemSettings.getInt(Settings.System.NOTIFICATION_COOLDOWN_ENABLED, /* def */ 1) ==
+ 1
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index e6d97c2..f68e194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.interruption
+import android.content.pm.PackageManager
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
import android.os.PowerManager
@@ -63,7 +64,8 @@
private val uiEventLogger: UiEventLogger,
private val userTracker: UserTracker,
private val avalancheProvider: AvalancheProvider,
- private val systemSettings: SystemSettings
+ private val systemSettings: SystemSettings,
+ private val packageManager: PackageManager
) : VisualInterruptionDecisionProvider {
init {
@@ -172,7 +174,9 @@
addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider))
if (NotificationAvalancheSuppression.isEnabled) {
- addFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings))
+ addFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ )
avalancheProvider.register()
}
started = true
@@ -232,14 +236,17 @@
private fun makeLoggablePeekDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(PEEK)
- ?: checkFilters(PEEK, entry) ?: checkSuppressInterruptions(entry)
- ?: checkSuppressAwakeInterruptions(entry) ?: checkSuppressAwakeHeadsUp(entry)
- ?: LoggableDecision.unsuppressed
+ ?: checkFilters(PEEK, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: checkSuppressAwakeInterruptions(entry)
+ ?: checkSuppressAwakeHeadsUp(entry)
+ ?: LoggableDecision.unsuppressed
private fun makeLoggablePulseDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(PULSE)
- ?: checkFilters(PULSE, entry) ?: checkSuppressInterruptions(entry)
- ?: LoggableDecision.unsuppressed
+ ?: checkFilters(PULSE, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: LoggableDecision.unsuppressed
override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision =
traceSection("VisualInterruptionDecisionProviderImpl#makeAndLogBubbleDecision") {
@@ -252,8 +259,10 @@
private fun makeLoggableBubbleDecision(entry: NotificationEntry): LoggableDecision =
checkConditions(BUBBLE)
- ?: checkFilters(BUBBLE, entry) ?: checkSuppressInterruptions(entry)
- ?: checkSuppressAwakeInterruptions(entry) ?: LoggableDecision.unsuppressed
+ ?: checkFilters(BUBBLE, entry)
+ ?: checkSuppressInterruptions(entry)
+ ?: checkSuppressAwakeInterruptions(entry)
+ ?: LoggableDecision.unsuppressed
private fun logDecision(
type: VisualInterruptionType,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt
index 133d3e7..b42b2b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt
@@ -30,7 +30,7 @@
viewFlipper: ViewFlipper,
viewModel: NotificationViewFlipperViewModel,
): DisposableHandle {
- if (viewFlipper.isAutoStart) {
+ if (!viewFlipper.isAutoStart) {
// If the ViewFlipper is not set to AutoStart, the pause binding is meaningless
return DisposableHandle {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactMessagingTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactMessagingTemplateViewWrapper.kt
index bb40b56..20f04f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactMessagingTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactMessagingTemplateViewWrapper.kt
@@ -32,6 +32,12 @@
private var conversationIconView: CachingIconView? = null
private var expandBtn: View? = null
+ private var titleView: View? = null
+ private var headerTextSecondary: View? = null
+ private var subText: View? = null
+ private var facePileTop: View? = null
+ private var facePileBottom: View? = null
+ private var facePileBottomBg: View? = null
override fun onContentUpdated(row: ExpandableNotificationRow?) {
resolveViews()
super.onContentUpdated(row)
@@ -39,6 +45,14 @@
private fun resolveViews() {
conversationIconView = compactMessagingView.requireViewById(R.id.conversation_icon)
+ titleView = compactMessagingView.findViewById(R.id.title)
+ headerTextSecondary = compactMessagingView.findViewById(R.id.header_text_secondary)
+ subText = compactMessagingView.findViewById(R.id.header_text)
+ facePileTop = compactMessagingView.findViewById(R.id.conversation_face_pile_top)
+ facePileBottom = compactMessagingView.findViewById(R.id.conversation_face_pile_bottom)
+ facePileBottomBg =
+ compactMessagingView.findViewById(R.id.conversation_face_pile_bottom_background)
+
expandBtn = compactMessagingView.requireViewById(R.id.expand_button)
}
@@ -47,6 +61,12 @@
addViewsTransformingToSimilar(
conversationIconView,
+ titleView,
+ headerTextSecondary,
+ subText,
+ facePileTop,
+ facePileBottom,
+ facePileBottomBg,
expandBtn,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationViewFlipperPausing.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationViewFlipperPausing.kt
index cea6a2b..4454444 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationViewFlipperPausing.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationViewFlipperPausing.kt
@@ -24,7 +24,7 @@
@Suppress("NOTHING_TO_INLINE")
object NotificationViewFlipperPausing {
/** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_NOTIFICATION_VIEW_FLIPPER_PAUSING
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_VIEW_FLIPPER_PAUSING_V2
/** A token used for dependency declaration */
val token: FlagToken
@@ -33,7 +33,7 @@
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.notificationViewFlipperPausing()
+ get() = Flags.notificationViewFlipperPausingV2()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 2d0395a..5a433a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -16,17 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.notification.row.ExpandableView;
/**
@@ -35,165 +24,18 @@
*/
public class NotificationSection {
private @PriorityBucket final int mBucket;
- private final View mOwningView;
- private final Rect mBounds = new Rect();
- private final Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
- private final Rect mStartAnimationRect = new Rect();
- private final Rect mEndAnimationRect = new Rect();
- private ObjectAnimator mTopAnimator = null;
- private ObjectAnimator mBottomAnimator = null;
private ExpandableView mFirstVisibleChild;
private ExpandableView mLastVisibleChild;
- NotificationSection(View owningView, @PriorityBucket int bucket) {
- mOwningView = owningView;
+ NotificationSection(@PriorityBucket int bucket) {
mBucket = bucket;
}
- public void cancelAnimators() {
- if (mBottomAnimator != null) {
- mBottomAnimator.cancel();
- }
- if (mTopAnimator != null) {
- mTopAnimator.cancel();
- }
- }
-
- public Rect getCurrentBounds() {
- return mCurrentBounds;
- }
-
- public Rect getBounds() {
- return mBounds;
- }
-
- public boolean didBoundsChange() {
- return !mCurrentBounds.equals(mBounds);
- }
-
- public boolean areBoundsAnimating() {
- return mBottomAnimator != null || mTopAnimator != null;
- }
-
@PriorityBucket
public int getBucket() {
return mBucket;
}
- public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) {
- // Left and right bounds are always applied immediately.
- mCurrentBounds.left = mBounds.left;
- mCurrentBounds.right = mBounds.right;
- startBottomAnimation(animateBottom);
- startTopAnimation(animateTop);
- }
-
-
- private void startTopAnimation(boolean animate) {
- int previousEndValue = mEndAnimationRect.top;
- int newEndValue = mBounds.top;
- ObjectAnimator previousAnimator = mTopAnimator;
- if (previousAnimator != null && previousEndValue == newEndValue) {
- return;
- }
- if (!animate) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- int previousStartValue = mStartAnimationRect.top;
- PropertyValuesHolder[] values = previousAnimator.getValues();
- values[0].setIntValues(previousStartValue, newEndValue);
- mStartAnimationRect.top = previousStartValue;
- mEndAnimationRect.top = newEndValue;
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- setBackgroundTop(newEndValue);
- return;
- }
- }
- if (previousAnimator != null) {
- previousAnimator.cancel();
- }
- ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
- mCurrentBounds.top, newEndValue);
- Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
- animator.setInterpolator(interpolator);
- animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mStartAnimationRect.top = -1;
- mEndAnimationRect.top = -1;
- mTopAnimator = null;
- }
- });
- animator.start();
- mStartAnimationRect.top = mCurrentBounds.top;
- mEndAnimationRect.top = newEndValue;
- mTopAnimator = animator;
- }
-
- private void startBottomAnimation(boolean animate) {
- int previousStartValue = mStartAnimationRect.bottom;
- int previousEndValue = mEndAnimationRect.bottom;
- int newEndValue = mBounds.bottom;
- ObjectAnimator previousAnimator = mBottomAnimator;
- if (previousAnimator != null && previousEndValue == newEndValue) {
- return;
- }
- if (!animate) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- values[0].setIntValues(previousStartValue, newEndValue);
- mStartAnimationRect.bottom = previousStartValue;
- mEndAnimationRect.bottom = newEndValue;
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- setBackgroundBottom(newEndValue);
- return;
- }
- }
- if (previousAnimator != null) {
- previousAnimator.cancel();
- }
- ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
- mCurrentBounds.bottom, newEndValue);
- Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
- animator.setInterpolator(interpolator);
- animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mStartAnimationRect.bottom = -1;
- mEndAnimationRect.bottom = -1;
- mBottomAnimator = null;
- }
- });
- animator.start();
- mStartAnimationRect.bottom = mCurrentBounds.bottom;
- mEndAnimationRect.bottom = newEndValue;
- mBottomAnimator = animator;
- }
-
- private void setBackgroundTop(int top) {
- mCurrentBounds.top = top;
- mOwningView.invalidate();
- }
-
- private void setBackgroundBottom(int bottom) {
- mCurrentBounds.bottom = bottom;
- mOwningView.invalidate();
- }
public ExpandableView getFirstVisibleChild() {
return mFirstVisibleChild;
@@ -215,91 +57,4 @@
return changed;
}
- public void resetCurrentBounds() {
- mCurrentBounds.set(mBounds);
- }
-
- /**
- * Returns true if {@code top} is equal to the top of this section (if not currently animating)
- * or where the top of this section will be when animation completes.
- */
- public boolean isTargetTop(int top) {
- return (mTopAnimator == null && mCurrentBounds.top == top)
- || (mTopAnimator != null && mEndAnimationRect.top == top);
- }
-
- /**
- * Returns true if {@code bottom} is equal to the bottom of this section (if not currently
- * animating) or where the bottom of this section will be when animation completes.
- */
- public boolean isTargetBottom(int bottom) {
- return (mBottomAnimator == null && mCurrentBounds.bottom == bottom)
- || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom);
- }
-
- /**
- * Update the bounds of this section based on it's views
- *
- * @param minTopPosition the minimum position that the top needs to have
- * @param minBottomPosition the minimum position that the bottom needs to have
- * @return the position of the new bottom
- */
- public int updateBounds(int minTopPosition, int minBottomPosition,
- boolean shiftBackgroundWithFirst) {
- int top = minTopPosition;
- int bottom = minTopPosition;
- ExpandableView firstView = getFirstVisibleChild();
- if (firstView != null) {
- // Round Y up to avoid seeing the background during animation
- int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
- // TODO: look into the already animating part
- int newTop;
- if (isTargetTop(finalTranslationY)) {
- // we're ending up at the same location as we are now, let's just skip the
- // animation
- newTop = finalTranslationY;
- } else {
- newTop = (int) Math.ceil(firstView.getTranslationY());
- }
- top = Math.max(newTop, top);
- if (firstView.showingPulsing()) {
- // If we're pulsing, the notification can actually go below!
- bottom = Math.max(bottom, finalTranslationY
- + ExpandableViewState.getFinalActualHeight(firstView));
- if (shiftBackgroundWithFirst) {
- mBounds.left += Math.max(firstView.getTranslation(), 0);
- mBounds.right += Math.min(firstView.getTranslation(), 0);
- }
- }
- }
- ExpandableView lastView = getLastVisibleChild();
- if (lastView != null) {
- float finalTranslationY = ViewState.getFinalTranslationY(lastView);
- int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
- // Round Y down to avoid seeing the background during animation
- int finalBottom = (int) Math.floor(
- finalTranslationY + finalHeight - lastView.getClipBottomAmount());
- int newBottom;
- if (isTargetBottom(finalBottom)) {
- // we're ending up at the same location as we are now, lets just skip the animation
- newBottom = finalBottom;
- } else {
- newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
- - lastView.getClipBottomAmount());
- // The background can never be lower than the end of the last view
- minBottomPosition = (int) Math.min(
- lastView.getTranslationY() + lastView.getActualHeight(),
- minBottomPosition);
- }
- bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition));
- }
- bottom = Math.max(top, bottom);
- mBounds.top = top;
- mBounds.bottom = bottom;
- return bottom;
- }
-
- public boolean needsBackground() {
- return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index d269eda..3400ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -40,7 +40,9 @@
*
* TODO: Move remaining sections logic from NSSL into this class.
*/
-class NotificationSectionsManager @Inject internal constructor(
+class NotificationSectionsManager
+@Inject
+internal constructor(
private val configurationController: ConfigurationController,
private val keyguardMediaController: KeyguardMediaController,
private val sectionsFeatureManager: NotificationSectionsFeatureManager,
@@ -52,11 +54,12 @@
@SilentHeader private val silentHeaderController: SectionHeaderController
) : SectionProvider {
- private val configurationListener = object : ConfigurationController.ConfigurationListener {
- override fun onLocaleListChanged() {
- reinflateViews()
+ private val configurationListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onLocaleListChanged() {
+ reinflateViews()
+ }
}
- }
private lateinit var parent: NotificationStackScrollLayout
private var initialized = false
@@ -81,7 +84,7 @@
val mediaControlsView: MediaContainerView?
get() = mediaContainerController.mediaContainerView
- /** Must be called before use. */
+ /** Must be called before use. */
fun initialize(parent: NotificationStackScrollLayout) {
check(!initialized) { "NotificationSectionsManager already initialized" }
initialized = true
@@ -91,13 +94,12 @@
}
fun createSectionsForBuckets(): Array<NotificationSection> =
- sectionsFeatureManager.getNotificationBuckets()
- .map { NotificationSection(parent, it) }
- .toTypedArray()
+ sectionsFeatureManager
+ .getNotificationBuckets()
+ .map { NotificationSection(it) }
+ .toTypedArray()
- /**
- * Reinflates the entire notification header, including all decoration views.
- */
+ /** Reinflates the entire notification header, including all decoration views. */
fun reinflateViews() {
silentHeaderController.reinflateView(parent)
alertingHeaderController.reinflateView(parent)
@@ -108,44 +110,44 @@
}
override fun beginsSection(view: View, previous: View?): Boolean =
- view === silentHeaderView ||
+ view === silentHeaderView ||
view === mediaControlsView ||
view === peopleHeaderView ||
view === alertingHeaderView ||
view === incomingHeaderView ||
getBucket(view) != getBucket(previous)
- private fun getBucket(view: View?): Int? = when {
- view === silentHeaderView -> BUCKET_SILENT
- view === incomingHeaderView -> BUCKET_HEADS_UP
- view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
- view === peopleHeaderView -> BUCKET_PEOPLE
- view === alertingHeaderView -> BUCKET_ALERTING
- view is ExpandableNotificationRow -> view.entry.bucket
- else -> null
- }
+ private fun getBucket(view: View?): Int? =
+ when {
+ view === silentHeaderView -> BUCKET_SILENT
+ view === incomingHeaderView -> BUCKET_HEADS_UP
+ view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
+ view === peopleHeaderView -> BUCKET_PEOPLE
+ view === alertingHeaderView -> BUCKET_ALERTING
+ view is ExpandableNotificationRow -> view.entry.bucket
+ else -> null
+ }
private sealed class SectionBounds {
- data class Many(
- val first: ExpandableView,
- val last: ExpandableView
- ) : SectionBounds()
+ data class Many(val first: ExpandableView, val last: ExpandableView) : SectionBounds()
data class One(val lone: ExpandableView) : SectionBounds()
object None : SectionBounds()
- fun addNotif(notif: ExpandableView): SectionBounds = when (this) {
- is None -> One(notif)
- is One -> Many(lone, notif)
- is Many -> copy(last = notif)
- }
+ fun addNotif(notif: ExpandableView): SectionBounds =
+ when (this) {
+ is None -> One(notif)
+ is One -> Many(lone, notif)
+ is Many -> copy(last = notif)
+ }
- fun updateSection(section: NotificationSection): Boolean = when (this) {
- is None -> section.setFirstAndLastVisibleChildren(null, null)
- is One -> section.setFirstAndLastVisibleChildren(lone, lone)
- is Many -> section.setFirstAndLastVisibleChildren(first, last)
- }
+ fun updateSection(section: NotificationSection): Boolean =
+ when (this) {
+ is None -> section.setFirstAndLastVisibleChildren(null, null)
+ is One -> section.setFirstAndLastVisibleChildren(lone, lone)
+ is Many -> section.setFirstAndLastVisibleChildren(first, last)
+ }
private fun NotificationSection.setFirstAndLastVisibleChildren(
first: ExpandableView?,
@@ -167,17 +169,19 @@
children: List<ExpandableView>
): Boolean {
// Create mapping of bucket to section
- val sectionBounds = children.asSequence()
+ val sectionBounds =
+ children
+ .asSequence()
// Group children by bucket
.groupingBy {
getBucket(it)
- ?: throw IllegalArgumentException("Cannot find section bucket for view")
+ ?: throw IllegalArgumentException("Cannot find section bucket for view")
}
// Combine each bucket into a SectionBoundary
.foldToSparseArray(
- SectionBounds.None,
- size = sections.size,
- operation = SectionBounds::addNotif
+ SectionBounds.None,
+ size = sections.size,
+ operation = SectionBounds::addNotif
)
// Build a set of the old first/last Views of the sections
@@ -185,11 +189,12 @@
val oldLastChildren = sections.mapNotNull { it.lastVisibleChild }.toSet().toMutableSet()
// Update each section with the associated boundary, tracking if there was a change
- val changed = sections.fold(false) { changed, section ->
- val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
- val isSectionChanged = bounds.updateSection(section)
- isSectionChanged || changed
- }
+ val changed =
+ sections.fold(false) { changed, section ->
+ val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
+ val isSectionChanged = bounds.updateSection(section)
+ isSectionChanged || changed
+ }
val newFirstChildren = sections.mapNotNull { it.firstVisibleChild }
val newLastChildren = sections.mapNotNull { it.lastVisibleChild }
@@ -229,16 +234,18 @@
private fun logSections(sections: Array<NotificationSection>) {
for (i in sections.indices) {
val s = sections[i]
- val fs = when (val first = s.firstVisibleChild) {
- null -> "(null)"
- is ExpandableNotificationRow -> first.entry.key
- else -> Integer.toHexString(System.identityHashCode(first))
- }
- val ls = when (val last = s.lastVisibleChild) {
- null -> "(null)"
- is ExpandableNotificationRow -> last.entry.key
- else -> Integer.toHexString(System.identityHashCode(last))
- }
+ val fs =
+ when (val first = s.firstVisibleChild) {
+ null -> "(null)"
+ is ExpandableNotificationRow -> first.entry.key
+ else -> Integer.toHexString(System.identityHashCode(first))
+ }
+ val ls =
+ when (val last = s.lastVisibleChild) {
+ null -> "(null)"
+ is ExpandableNotificationRow -> last.entry.key
+ else -> Integer.toHexString(System.identityHashCode(last))
+ }
Log.d(TAG, "updateSections: f=$fs s=$i")
Log.d(TAG, "updateSections: l=$ls s=$i")
}
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 17b54c8..a9d7cc0 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
@@ -2974,7 +2974,7 @@
private void updateFirstAndLastBackgroundViews() {
ExpandableView lastChild = getLastChildWithBackground();
- boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsForAllSections(
+ mSectionsManager.updateFirstAndLastViewsForAllSections(
mSections, getChildrenWithBackground());
mAmbientState.setLastVisibleBackgroundChild(lastChild);
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 c1c63cd..6a3055f 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,6 +23,7 @@
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.confineNotificationTouchToViewWidth;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener;
@@ -597,7 +598,7 @@
ev.getY(),
true /* requireMinHeight */,
false /* ignoreDecors */,
- true /* ignoreWidth */);
+ !confineNotificationTouchToViewWidth() /* ignoreWidth */);
if (child instanceof ExpandableNotificationRow row) {
ExpandableNotificationRow parent = row.getNotificationParent();
if (parent != null && parent.areChildrenExpanded()
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 0fcfc4b..f9efc07 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
@@ -400,6 +400,8 @@
*/
public boolean isCyclingOut(ExpandableNotificationRow row, AmbientState ambientState) {
if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ if (row.getEntry() == null) return false;
+ if (row.getEntry().getKey() == null) return false;
String cyclingOutKey = ambientState.getAvalanchePreviousHunKey();
return row.getEntry().getKey().equals(cyclingOutKey);
}
@@ -409,6 +411,8 @@
*/
public boolean isCyclingIn(ExpandableNotificationRow row, AmbientState ambientState) {
if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ if (row.getEntry() == null) return false;
+ if (row.getEntry().getKey() == null) return false;
String cyclingInKey = ambientState.getAvalancheShowingHunKey();
return row.getEntry().getKey().equals(cyclingInKey);
}
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 3a89630..b54f9c4 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
@@ -18,7 +18,6 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
-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
@@ -59,7 +58,6 @@
activeNotificationsInteractor: ActiveNotificationsInteractor,
notificationStackInteractor: NotificationStackInteractor,
private val headsUpNotificationInteractor: HeadsUpNotificationInteractor,
- keyguardInteractor: KeyguardInteractor,
remoteInputInteractor: RemoteInputInteractor,
seenNotificationsInteractor: SeenNotificationsInteractor,
shadeInteractor: ShadeInteractor,
@@ -277,11 +275,12 @@
if (NotificationsHeadsUpRefactor.isUnexpectedlyInLegacyMode()) {
flowOf(false)
} else {
- combine(keyguardInteractor.isKeyguardShowing, shadeInteractor.isShadeFullyExpanded) {
- (isKeyguardShowing, isShadeFullyExpanded) ->
- // TODO(b/325936094) use isShadeFullyCollapsed instead
- !isKeyguardShowing && !isShadeFullyExpanded
- }
+ combine(
+ notificationStackInteractor.isShowingOnLockscreen,
+ shadeInteractor.isShadeFullyCollapsed
+ ) { (isKeyguardShowing, isShadeFullyCollapsed) ->
+ !isKeyguardShowing && isShadeFullyCollapsed
+ }
.dumpWhileCollecting("headsUpAnimationsEnabled")
}
}
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 3393321..6dfaec9 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
@@ -249,8 +249,14 @@
state == GLANCEABLE_HUB
},
anyOf(
- keyguardTransitionInteractor.isInTransitionToState(GLANCEABLE_HUB),
- keyguardTransitionInteractor.isInTransitionFromState(GLANCEABLE_HUB),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(to = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(to = GLANCEABLE_HUB)
+ ),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(from = GLANCEABLE_HUB)
+ ),
),
) { isOnGlanceableHub, transitioningToOrFromHub ->
isOnGlanceableHub || transitioningToOrFromHub
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 4c3c7d5..11feb97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -354,6 +354,7 @@
* since the headsUp manager might not have notified us yet of the state change.
*
* @return if the heads up status bar view should be shown
+ * @deprecated use HeadsUpNotificationInteractor.showHeadsUpStatusBar instead.
*/
public boolean shouldBeVisible() {
boolean notificationsShown = !mWakeUpCoordinator.getNotificationsFullyHidden();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index c4e0f31..16e9c71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -219,6 +219,7 @@
}
private void setNextIndication() {
+ boolean forceAssertiveAccessibilityLiveRegion = false;
if (mKeyguardIndicationInfo != null) {
// First, update the style.
// If a background is set on the text, we don't want shadow on the text
@@ -239,8 +240,16 @@
}
}
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
+ forceAssertiveAccessibilityLiveRegion =
+ mKeyguardIndicationInfo.getForceAssertiveAccessibilityLiveRegion();
+ }
+ if (!forceAssertiveAccessibilityLiveRegion) {
+ setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_NONE);
}
setText(mMessage);
+ if (forceAssertiveAccessibilityLiveRegion) {
+ setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
+ }
if (mAlwaysAnnounceText) {
announceForAccessibility(mMessage);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 2b26e3f..f767262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -660,10 +660,14 @@
* whether heads up is visible.
*/
public void updateForHeadsUp() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
+ // [KeyguardStatusBarViewBinder] handles visibility changes due to heads up states.
+ return;
+ }
updateForHeadsUp(true);
}
- // TODO(b/328579846) bind the StatusBar visibility to heads up events
+ @VisibleForTesting
void updateForHeadsUp(boolean animate) {
boolean showingKeyguardHeadsUp =
isKeyguardShowing() && mShadeViewStateProvider.shouldHeadsUpBeVisible();
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 fa88be5..5bbc3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -655,13 +655,8 @@
* device state and touch handling. The bouncer MUST have been notified that it is about to
* show if any subsequent events are to be handled.
*/
- if (beginShowingBouncer(event)) {
- if (SceneContainerFlag.isEnabled()) {
- mSceneInteractorLazy.get().changeScene(
- Scenes.Bouncer, "StatusBarKeyguardViewManager.onPanelExpansionChanged");
- } else {
- mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
- }
+ if (!SceneContainerFlag.isEnabled() && beginShowingBouncer(event)) {
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
}
if (!primaryBouncerIsOrWillBeShowing()) {
@@ -695,11 +690,6 @@
public void show(Bundle options) {
Trace.beginSection("StatusBarKeyguardViewManager#show");
mNotificationShadeWindowController.setKeyguardShowing(true);
- if (SceneContainerFlag.isEnabled()) {
- // TODO(b/336581871): add sceneState?
- mSceneInteractorLazy.get().changeScene(
- Scenes.Lockscreen, "StatusBarKeyguardViewManager.show");
- }
mKeyguardStateController.notifyKeyguardState(true, mKeyguardStateController.isOccluded());
reset(true /* hideBouncerWhenShowing */);
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index a858fb0..97f9e06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -134,6 +135,8 @@
private final CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger;
private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
private final OngoingCallController mOngoingCallController;
+ // TODO(b/332662551): Use this view model to show the ongoing activity chips.
+ private final OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mLocationPublisher;
private final NotificationIconAreaController mNotificationIconAreaController;
@@ -217,6 +220,7 @@
public CollapsedStatusBarFragment(
StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
OngoingCallController ongoingCallController,
+ OngoingActivityChipsViewModel ongoingActivityChipsViewModel,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
@@ -242,6 +246,7 @@
DemoModeController demoModeController) {
mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
mOngoingCallController = ongoingCallController;
+ mOngoingActivityChipsViewModel = ongoingActivityChipsViewModel;
mAnimationScheduler = animationScheduler;
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
@@ -548,6 +553,7 @@
private StatusBarVisibilityModel calculateInternalModel(
StatusBarVisibilityModel externalModel) {
+ // TODO(b/328393714) use HeadsUpNotificationInteractor.showHeadsUpStatusBar instead.
boolean headsUpVisible =
mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
index 5da01e2..3e01180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt
@@ -22,6 +22,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import javax.inject.Inject
@@ -46,6 +47,7 @@
@Inject
constructor(
@Application scope: CoroutineScope,
+ headsUpNotificationInteractor: HeadsUpNotificationInteractor,
keyguardInteractor: KeyguardInteractor,
keyguardStatusBarInteractor: KeyguardStatusBarInteractor,
batteryController: BatteryController,
@@ -55,8 +57,9 @@
combine(
keyguardInteractor.isDozing,
keyguardInteractor.statusBarState,
- ) { isDozing, statusBarState ->
- !isDozing && statusBarState == StatusBarState.KEYGUARD
+ headsUpNotificationInteractor.showHeadsUpStatusBar,
+ ) { isDozing, statusBarState, showHeadsUpStatusBar ->
+ !isDozing && statusBarState == StatusBarState.KEYGUARD && !showHeadsUpStatusBar
}
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
diff --git a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
deleted file mode 100644
index efeb2f9..0000000
--- a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
+++ /dev/null
@@ -1,322 +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.theme;
-
-import com.google.ux.material.libmonet.dynamiccolor.ContrastCurve;
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
-import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
-import com.google.ux.material.libmonet.dynamiccolor.ToneDeltaPair;
-import com.google.ux.material.libmonet.dynamiccolor.TonePolarity;
-
-class CustomDynamicColors {
- private final MaterialDynamicColors mMdc;
-
- CustomDynamicColors(boolean isExtendedFidelity) {
- this.mMdc = new MaterialDynamicColors(isExtendedFidelity);
- }
-
- // CLOCK COLORS
-
- public DynamicColor widgetBackground() {
- return new DynamicColor(
- /* name= */ "widget_background",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 20.0 : 95.0,
- /* isBackground= */ true,
- /* background= */ null,
- /* secondBackground= */ null,
- /* contrastCurve= */ null,
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor clockHour() {
- return new DynamicColor(
- /* name= */ "clock_hour",
- /* palette= */ (s) -> s.secondaryPalette,
- /* tone= */ (s) -> s.isDark ? 30.0 : 60.0,
- /* isBackground= */ false,
- /* background= */ (s) -> widgetBackground(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 4.0, 5.0, 15.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(clockHour(), clockMinute(), 10.0, TonePolarity.DARKER,
- false));
- }
-
- public DynamicColor clockMinute() {
- return new DynamicColor(
- /* name= */ "clock_minute",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
- /* isBackground= */ false,
- /* background= */ (s) -> widgetBackground(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 6.5, 10.0, 15.0),
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor clockSecond() {
- return new DynamicColor(
- /* name= */ "clock_second",
- /* palette= */ (s) -> s.tertiaryPalette,
- /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
- /* isBackground= */ false,
- /* background= */ (s) -> widgetBackground(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor weatherTemp() {
- return new DynamicColor(
- /* name= */ "clock_second",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 55.0 : 80.0,
- /* isBackground= */ false,
- /* background= */ (s) -> widgetBackground(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
- /* toneDeltaPair= */ null);
- }
-
- // THEME APP ICONS
-
- public DynamicColor themeApp() {
- return new DynamicColor(
- /* name= */ "theme_app",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 90.0 : 30.0, // Adjusted values
- /* isBackground= */ true,
- /* background= */ null,
- /* secondBackground= */ null,
- /* contrastCurve= */ null,
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor onThemeApp() {
- return new DynamicColor(
- /* name= */ "on_theme_app",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, // Adjusted values
- /* isBackground= */ false,
- /* background= */ (s) -> themeApp(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 10.0),
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor themeAppRing() {
- return new DynamicColor(
- /* name= */ "theme_app_ring",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> 70.0,
- /* isBackground= */ true,
- /* background= */ null,
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor themeNotif() {
- return new DynamicColor(
- /* name= */ "theme_notif",
- /* palette= */ (s) -> s.tertiaryPalette,
- /* tone= */ (s) -> s.isDark ? 80.0 : 90.0,
- /* isBackground= */ false,
- /* background= */ (s) -> themeAppRing(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(themeNotif(), themeAppRing(), 10.0, TonePolarity.NEARER,
- false));
- }
-
- // SUPER G COLORS
-
- public DynamicColor brandA() {
- return new DynamicColor(
- /* name= */ "brand_a",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 40.0 : 80.0,
- /* isBackground= */ true,
- /* background= */ (s) -> mMdc.surfaceContainerLow(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 17.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(brandA(), brandB(), 10.0, TonePolarity.NEARER, false));
- }
-
- public DynamicColor brandB() {
- return new DynamicColor(
- /* name= */ "brand_b",
- /* palette= */ (s) -> s.secondaryPalette,
- /* tone= */ (s) -> s.isDark ? 70.0 : 98.0,
- /* isBackground= */ true,
- /* background= */ (s) -> mMdc.surfaceContainerLow(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 3.0, 6.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(brandB(), brandC(), 10.0, TonePolarity.NEARER, false));
- }
-
- public DynamicColor brandC() {
- return new DynamicColor(
- /* name= */ "brand_c",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> s.isDark ? 50.0 : 60.0,
- /* isBackground= */ false,
- /* background= */ (s) -> mMdc.surfaceContainerLow(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 9.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(brandC(), brandD(), 10.0, TonePolarity.NEARER, false));
- }
-
- public DynamicColor brandD() {
- return new DynamicColor(
- /* name= */ "brand_d",
- /* palette= */ (s) -> s.tertiaryPalette,
- /* tone= */ (s) -> s.isDark ? 59.0 : 90.0,
- /* isBackground= */ false,
- /* background= */ (s) -> mMdc.surfaceContainerLow(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 13.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(brandD(), brandA(), 10.0, TonePolarity.NEARER, false));
- }
-
- // QUICK SETTING TIILES
-
- public DynamicColor underSurface() {
- return new DynamicColor(
- /* name= */ "under_surface",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> 0.0,
- /* isBackground= */ true,
- /* background= */ null,
- /* secondBackground= */ null,
- /* contrastCurve= */ null,
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor shadeActive() {
- return new DynamicColor(
- /* name= */ "shade_active",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> 90.0,
- /* isBackground= */ false,
- /* background= */ (s) -> underSurface(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.5, 7.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(shadeActive(), shadeInactive(), 30.0, TonePolarity.LIGHTER,
- false));
- }
-
- public DynamicColor onShadeActive() {
- return new DynamicColor(
- /* name= */ "on_shade_active",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> 10.0,
- /* isBackground= */ false,
- /* background= */ (s) -> shadeActive(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(onShadeActive(), onShadeActiveVariant(), 20.0,
- TonePolarity.NEARER, false));
- }
-
- public DynamicColor onShadeActiveVariant() {
- return new DynamicColor(
- /* name= */ "on_shade_active_variant",
- /* palette= */ (s) -> s.primaryPalette,
- /* tone= */ (s) -> 30.0,
- /* isBackground= */ false,
- /* background= */ (s) -> shadeActive(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(onShadeActiveVariant(), onShadeActive(), 20.0,
- TonePolarity.NEARER, false));
- }
-
- public DynamicColor shadeInactive() {
- return new DynamicColor(
- /* name= */ "shade_inactive",
- /* palette= */ (s) -> s.neutralPalette,
- /* tone= */ (s) -> 20.0,
- /* isBackground= */ true,
- /* background= */ (s) -> underSurface(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
- /* toneDeltaPair= */(s) -> new ToneDeltaPair(shadeInactive(), shadeDisabled(), 15.0,
- TonePolarity.LIGHTER, false));
- }
-
- public DynamicColor onShadeInactive() {
- return new DynamicColor(
- /* name= */ "on_shade_inactive",
- /* palette= */ (s) -> s.neutralVariantPalette,
- /* tone= */ (s) -> 90.0,
- /* isBackground= */ true,
- /* background= */ (s) -> shadeInactive(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(onShadeInactive(), onShadeInactiveVariant(), 10.0,
- TonePolarity.NEARER, false));
- }
-
- public DynamicColor onShadeInactiveVariant() {
- return new DynamicColor(
- /* name= */ "on_shade_inactive_variant",
- /* palette= */ (s) -> s.neutralVariantPalette,
- /* tone= */ (s) -> 80.0,
- /* isBackground= */ false,
- /* background= */ (s) -> shadeInactive(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
- /* toneDeltaPair= */
- (s) -> new ToneDeltaPair(onShadeInactiveVariant(), onShadeInactive(), 10.0,
- TonePolarity.NEARER, false));
- }
-
- public DynamicColor shadeDisabled() {
- return new DynamicColor(
- /* name= */ "shade_disabled",
- /* palette= */ (s) -> s.neutralPalette,
- /* tone= */ (s) -> 4.0,
- /* isBackground= */ false,
- /* background= */ (s) -> underSurface(),
- /* secondBackground= */ null,
- /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
- /* toneDeltaPair= */ null);
- }
-
- public DynamicColor overviewBackground() {
- return new DynamicColor(
- /* name= */ "overview_background",
- /* palette= */ (s) -> s.neutralVariantPalette,
- /* tone= */ (s) -> s.isDark ? 80.0 : 35.0,
- /* isBackground= */ true,
- /* background= */ null,
- /* secondBackground= */ null,
- /* contrastCurve= */null,
- /* toneDeltaPair= */ null);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
deleted file mode 100644
index 3518759..0000000
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ /dev/null
@@ -1,135 +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.theme
-
-import android.util.Pair
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
-import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors
-
-class DynamicColors {
- companion object {
- @JvmStatic
- fun allDynamicColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
- val mdc = MaterialDynamicColors(isExtendedFidelity)
- return arrayListOf(
- Pair.create("primary_container", mdc.primaryContainer()),
- Pair.create("on_primary_container", mdc.onPrimaryContainer()),
- Pair.create("primary", mdc.primary()),
- Pair.create("on_primary", mdc.onPrimary()),
- Pair.create("secondary_container", mdc.secondaryContainer()),
- Pair.create("on_secondary_container", mdc.onSecondaryContainer()),
- Pair.create("secondary", mdc.secondary()),
- Pair.create("on_secondary", mdc.onSecondary()),
- Pair.create("tertiary_container", mdc.tertiaryContainer()),
- Pair.create("on_tertiary_container", mdc.onTertiaryContainer()),
- Pair.create("tertiary", mdc.tertiary()),
- Pair.create("on_tertiary", mdc.onTertiary()),
- Pair.create("background", mdc.background()),
- Pair.create("on_background", mdc.onBackground()),
- Pair.create("surface", mdc.surface()),
- Pair.create("on_surface", mdc.onSurface()),
- Pair.create("surface_container_low", mdc.surfaceContainerLow()),
- Pair.create("surface_container_lowest", mdc.surfaceContainerLowest()),
- Pair.create("surface_container", mdc.surfaceContainer()),
- Pair.create("surface_container_high", mdc.surfaceContainerHigh()),
- Pair.create("surface_container_highest", mdc.surfaceContainerHighest()),
- Pair.create("surface_bright", mdc.surfaceBright()),
- Pair.create("surface_dim", mdc.surfaceDim()),
- Pair.create("surface_variant", mdc.surfaceVariant()),
- Pair.create("on_surface_variant", mdc.onSurfaceVariant()),
- Pair.create("outline", mdc.outline()),
- Pair.create("outline_variant", mdc.outlineVariant()),
- Pair.create("error", mdc.error()),
- Pair.create("on_error", mdc.onError()),
- Pair.create("error_container", mdc.errorContainer()),
- Pair.create("on_error_container", mdc.onErrorContainer()),
- Pair.create("control_activated", mdc.controlActivated()),
- Pair.create("control_normal", mdc.controlNormal()),
- Pair.create("control_highlight", mdc.controlHighlight()),
- Pair.create("text_primary_inverse", mdc.textPrimaryInverse()),
- Pair.create(
- "text_secondary_and_tertiary_inverse",
- mdc.textSecondaryAndTertiaryInverse()
- ),
- Pair.create(
- "text_primary_inverse_disable_only",
- mdc.textPrimaryInverseDisableOnly()
- ),
- Pair.create(
- "text_secondary_and_tertiary_inverse_disabled",
- mdc.textSecondaryAndTertiaryInverseDisabled()
- ),
- Pair.create("text_hint_inverse", mdc.textHintInverse()),
- Pair.create("palette_key_color_primary", mdc.primaryPaletteKeyColor()),
- Pair.create("palette_key_color_secondary", mdc.secondaryPaletteKeyColor()),
- Pair.create("palette_key_color_tertiary", mdc.tertiaryPaletteKeyColor()),
- Pair.create("palette_key_color_neutral", mdc.neutralPaletteKeyColor()),
- Pair.create(
- "palette_key_color_neutral_variant",
- mdc.neutralVariantPaletteKeyColor()
- ),
- )
- }
-
- @JvmStatic
- fun getFixedColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
- val mdc = MaterialDynamicColors(isExtendedFidelity)
- return arrayListOf(
- Pair.create("primary_fixed", mdc.primaryFixed()),
- Pair.create("primary_fixed_dim", mdc.primaryFixedDim()),
- Pair.create("on_primary_fixed", mdc.onPrimaryFixed()),
- Pair.create("on_primary_fixed_variant", mdc.onPrimaryFixedVariant()),
- Pair.create("secondary_fixed", mdc.secondaryFixed()),
- Pair.create("secondary_fixed_dim", mdc.secondaryFixedDim()),
- Pair.create("on_secondary_fixed", mdc.onSecondaryFixed()),
- Pair.create("on_secondary_fixed_variant", mdc.onSecondaryFixedVariant()),
- Pair.create("tertiary_fixed", mdc.tertiaryFixed()),
- Pair.create("tertiary_fixed_dim", mdc.tertiaryFixedDim()),
- Pair.create("on_tertiary_fixed", mdc.onTertiaryFixed()),
- Pair.create("on_tertiary_fixed_variant", mdc.onTertiaryFixedVariant()),
- )
- }
-
- @JvmStatic
- fun getCustomColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
- val customMdc = CustomDynamicColors(isExtendedFidelity)
- return arrayListOf(
- Pair.create("widget_background", customMdc.widgetBackground()),
- Pair.create("clock_hour", customMdc.clockHour()),
- Pair.create("clock_minute", customMdc.clockMinute()),
- Pair.create("clock_second", customMdc.weatherTemp()),
- Pair.create("theme_app", customMdc.themeApp()),
- Pair.create("on_theme_app", customMdc.onThemeApp()),
- Pair.create("theme_app_ring", customMdc.themeAppRing()),
- Pair.create("on_theme_app_ring", customMdc.themeNotif()),
- Pair.create("brand_a", customMdc.brandA()),
- Pair.create("brand_b", customMdc.brandB()),
- Pair.create("brand_c", customMdc.brandC()),
- Pair.create("brand_d", customMdc.brandD()),
- Pair.create("under_surface", customMdc.underSurface()),
- Pair.create("shade_active", customMdc.shadeActive()),
- Pair.create("on_shade_active", customMdc.onShadeActive()),
- Pair.create("on_shade_active_variant", customMdc.onShadeActiveVariant()),
- Pair.create("shade_inactive", customMdc.shadeInactive()),
- Pair.create("on_shade_inactive", customMdc.onShadeInactive()),
- Pair.create("on_shade_inactive_variant", customMdc.onShadeInactiveVariant()),
- Pair.create("shade_disabled", customMdc.shadeDisabled()),
- Pair.create("overview_background", customMdc.overviewBackground())
- )
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index d256c4a..7494649 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -77,6 +77,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.monet.ColorScheme;
+import com.android.systemui.monet.DynamicColors;
import com.android.systemui.monet.Style;
import com.android.systemui.monet.TonalPalette;
import com.android.systemui.settings.UserTracker;
@@ -623,7 +624,7 @@
TonalPalette tonalPalette) {
String resourcePrefix = "android:color/system_" + name;
- tonalPalette.getAllShadesMapped().forEach((key, value) -> {
+ tonalPalette.allShadesMapped.forEach((key, value) -> {
String resourceName = resourcePrefix + "_" + key;
int colorValue = ColorUtils.setAlphaComponent(value, 0xFF);
overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
@@ -634,7 +635,7 @@
protected FabricatedOverlay createDynamicOverlay() {
FabricatedOverlay overlay = newFabricatedOverlay("dynamic");
//Themed Colors
- assignColorsToOverlay(overlay, DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled),
+ assignColorsToOverlay(overlay, DynamicColors.getAllDynamicColorsMapped(mIsFidelityEnabled),
false);
// Fixed Colors
assignColorsToOverlay(overlay, DynamicColors.getFixedColorsMapped(mIsFidelityEnabled),
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
index ca5ea3b..135edfc 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
@@ -32,6 +32,7 @@
import android.view.SurfaceSession
import android.view.WindowManager
import android.view.WindowlessWindowManager
+import androidx.annotation.WorkerThread
import com.android.app.tracing.traceSection
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -235,8 +236,10 @@
}
private inner class RotationWatcher : RotationChangeProvider.RotationListener {
+ @WorkerThread
override fun onRotationChanged(newRotation: Int) {
traceSection("$TAG#onRotationChanged") {
+ ensureInBackground()
if (currentRotation != newRotation) {
currentRotation = newRotation
scrimView?.revealEffect = lightRevealEffectFactory(currentRotation)
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
index a88be06..405b57a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
@@ -28,6 +28,8 @@
fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
Quad(a, bcd.first, bcd.second, bcd.third)
+ fun <A, B, C, D> toQuad(abc: Triple<A, B, C>, d: D) =
+ Quad(abc.first, abc.second, abc.third, d)
fun <A, B, C, D, E> toQuint(a: A, b: B, c: C, d: D, e: E) = Quint(a, b, c, d, e)
fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
deleted file mode 100644
index aeed78a..0000000
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.util.settings;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.provider.Settings;
-
-/**
- * Used to interact with mainly with Settings.Global, but can also be used for Settings.System
- * and Settings.Secure. To use the per-user System and Secure settings, {@link UserSettingsProxy}
- * must be used instead.
- * <p>
- * This interface can be implemented to give instance method (instead of static method) versions
- * of Settings.Global. It can be injected into class constructors and then faked or mocked as needed
- * in tests.
- * <p>
- * You can ask for {@link GlobalSettings} to be injected as needed.
- * <p>
- * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
- * normally found on {@link ContentResolver} instances, unifying setting related actions in one
- * place.
- */
-public interface SettingsProxy {
-
- /**
- * Returns the {@link ContentResolver} this instance was constructed with.
- */
- ContentResolver getContentResolver();
-
- /**
- * Construct the content URI for a particular name/value pair,
- * useful for monitoring changes with a ContentObserver.
- * @param name to look up in the table
- * @return the corresponding content URI, or null if not present
- */
- Uri getUriFor(String name);
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
- * <p>
- * Implicitly calls {@link #getUriFor(String)} on the passed in name.
- */
- default void registerContentObserver(String name, ContentObserver settingsObserver) {
- registerContentObserver(getUriFor(name), settingsObserver);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
- */
- default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
- registerContentObserver(uri, false, settingsObserver);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
- * <p>
- * Implicitly calls {@link #getUriFor(String)} on the passed in name.
- */
- default void registerContentObserver(String name, boolean notifyForDescendants,
- ContentObserver settingsObserver) {
- registerContentObserver(getUriFor(name), notifyForDescendants, settingsObserver);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
- */
- default void registerContentObserver(Uri uri, boolean notifyForDescendants,
- ContentObserver settingsObserver) {
- getContentResolver().registerContentObserver(
- uri, notifyForDescendants, settingsObserver);
- }
-
- /** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
- default void unregisterContentObserver(ContentObserver settingsObserver) {
- getContentResolver().unregisterContentObserver(settingsObserver);
- }
-
- /**
- * Look up a name in the database.
- * @param name to look up in the table
- * @return the corresponding value, or null if not present
- */
- @Nullable
- String getString(String name);
-
- /**
- * Store a name/value pair into the database.
- * @param name to store
- * @param value to associate with the name
- * @return true if the value was set, false on database errors
- */
- boolean putString(String name, String value);
-
- /**
- * Store a name/value pair into the database.
- * <p>
- * The method takes an optional tag to associate with the setting
- * which can be used to clear only settings made by your package and
- * associated with this tag by passing the tag to {@link
- * #resetToDefaults(String)}. Anyone can override
- * the current tag. Also if another package changes the setting
- * then the tag will be set to the one specified in the set call
- * which can be null. Also any of the settings setters that do not
- * take a tag as an argument effectively clears the tag.
- * </p><p>
- * For example, if you set settings A and B with tags T1 and T2 and
- * another app changes setting A (potentially to the same value), it
- * can assign to it a tag T3 (note that now the package that changed
- * the setting is not yours). Now if you reset your changes for T1 and
- * T2 only setting B will be reset and A not (as it was changed by
- * another package) but since A did not change you are in the desired
- * initial state. Now if the other app changes the value of A (assuming
- * you registered an observer in the beginning) you would detect that
- * the setting was changed by another app and handle this appropriately
- * (ignore, set back to some value, etc).
- * </p><p>
- * Also the method takes an argument whether to make the value the
- * default for this setting. If the system already specified a default
- * value, then the one passed in here will <strong>not</strong>
- * be set as the default.
- * </p>
- *
- * @param name to store.
- * @param value to associate with the name.
- * @param tag to associate with the setting.
- * @param makeDefault whether to make the value the default one.
- * @return true if the value was set, false on database errors.
- *
- * @see #resetToDefaults(String)
- *
- */
- boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag,
- boolean makeDefault);
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as an integer. Note that internally setting values are always
- * stored as strings; this function converts the string to an integer
- * for you. The default value will be returned if the setting is
- * not defined or not an integer.
- *
- * @param name The name of the setting to retrieve.
- * @param def Value to return if the setting is not defined.
- *
- * @return The setting's current value, or 'def' if it is not defined
- * or not a valid integer.
- */
- default int getInt(String name, int def) {
- String v = getString(name);
- try {
- return v != null ? Integer.parseInt(v) : def;
- } catch (NumberFormatException e) {
- return def;
- }
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as an integer. Note that internally setting values are always
- * stored as strings; this function converts the string to an integer
- * for you.
- * <p>
- * This version does not take a default value. If the setting has not
- * been set, or the string value is not a number,
- * it throws {@link Settings.SettingNotFoundException}.
- *
- * @param name The name of the setting to retrieve.
- *
- * @throws Settings.SettingNotFoundException Thrown if a setting by the given
- * name can't be found or the setting value is not an integer.
- *
- * @return The setting's current value.
- */
- default int getInt(String name)
- throws Settings.SettingNotFoundException {
- String v = getString(name);
- try {
- return Integer.parseInt(v);
- } catch (NumberFormatException e) {
- throw new Settings.SettingNotFoundException(name);
- }
- }
-
- /**
- * Convenience function for updating a single settings value as an
- * integer. This will either create a new entry in the table if the
- * given name does not exist, or modify the value of the existing row
- * with that name. Note that internally setting values are always
- * stored as strings, so this function converts the given value to a
- * string before storing it.
- *
- * @param name The name of the setting to modify.
- * @param value The new value for the setting.
- * @return true if the value was set, false on database errors
- */
- default boolean putInt(String name, int value) {
- return putString(name, Integer.toString(value));
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a boolean. Note that internally setting values are always
- * stored as strings; this function converts the string to a boolean
- * for you. The default value will be returned if the setting is
- * not defined or not a boolean.
- *
- * @param name The name of the setting to retrieve.
- * @param def Value to return if the setting is not defined.
- *
- * @return The setting's current value, or 'def' if it is not defined
- * or not a valid boolean.
- */
- default boolean getBool(String name, boolean def) {
- return getInt(name, def ? 1 : 0) != 0;
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a boolean. Note that internally setting values are always
- * stored as strings; this function converts the string to a boolean
- * for you.
- * <p>
- * This version does not take a default value. If the setting has not
- * been set, or the string value is not a number,
- * it throws {@link Settings.SettingNotFoundException}.
- *
- * @param name The name of the setting to retrieve.
- *
- * @throws Settings.SettingNotFoundException Thrown if a setting by the given
- * name can't be found or the setting value is not a boolean.
- *
- * @return The setting's current value.
- */
- default boolean getBool(String name)
- throws Settings.SettingNotFoundException {
- return getInt(name) != 0;
- }
-
- /**
- * Convenience function for updating a single settings value as a
- * boolean. This will either create a new entry in the table if the
- * given name does not exist, or modify the value of the existing row
- * with that name. Note that internally setting values are always
- * stored as strings, so this function converts the given value to a
- * string before storing it.
- *
- * @param name The name of the setting to modify.
- * @param value The new value for the setting.
- * @return true if the value was set, false on database errors
- */
- default boolean putBool(String name, boolean value) {
- return putInt(name, value ? 1 : 0);
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a {@code long}. Note that internally setting values are always
- * stored as strings; this function converts the string to a {@code long}
- * for you. The default value will be returned if the setting is
- * not defined or not a {@code long}.
- *
- * @param name The name of the setting to retrieve.
- * @param def Value to return if the setting is not defined.
- *
- * @return The setting's current value, or 'def' if it is not defined
- * or not a valid {@code long}.
- */
- default long getLong(String name, long def) {
- String valString = getString(name);
- return parseLongOrUseDefault(valString, def);
- }
-
- /** Convert a string to a long, or uses a default if the string is malformed or null */
- static long parseLongOrUseDefault(String valString, long def) {
- long value;
- try {
- value = valString != null ? Long.parseLong(valString) : def;
- } catch (NumberFormatException e) {
- value = def;
- }
- return value;
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a {@code long}. Note that internally setting values are always
- * stored as strings; this function converts the string to a {@code long}
- * for you.
- * <p>
- * This version does not take a default value. If the setting has not
- * been set, or the string value is not a number,
- * it throws {@link Settings.SettingNotFoundException}.
- *
- * @param name The name of the setting to retrieve.
- *
- * @return The setting's current value.
- * @throws Settings.SettingNotFoundException Thrown if a setting by the given
- * name can't be found or the setting value is not an integer.
- */
- default long getLong(String name)
- throws Settings.SettingNotFoundException {
- String valString = getString(name);
- return parseLongOrThrow(name, valString);
- }
-
- /** Convert a string to a long, or throws an exception if the string is malformed or null */
- static long parseLongOrThrow(String name, String valString)
- throws Settings.SettingNotFoundException {
- try {
- return Long.parseLong(valString);
- } catch (NumberFormatException e) {
- throw new Settings.SettingNotFoundException(name);
- }
- }
-
- /**
- * Convenience function for updating a secure settings value as a long
- * integer. This will either create a new entry in the table if the
- * given name does not exist, or modify the value of the existing row
- * with that name. Note that internally setting values are always
- * stored as strings, so this function converts the given value to a
- * string before storing it.
- *
- * @param name The name of the setting to modify.
- * @param value The new value for the setting.
- * @return true if the value was set, false on database errors
- */
- default boolean putLong(String name, long value) {
- return putString(name, Long.toString(value));
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a floating point number. Note that internally setting values are
- * always stored as strings; this function converts the string to an
- * float for you. The default value will be returned if the setting
- * is not defined or not a valid float.
- *
- * @param name The name of the setting to retrieve.
- * @param def Value to return if the setting is not defined.
- *
- * @return The setting's current value, or 'def' if it is not defined
- * or not a valid float.
- */
- default float getFloat(String name, float def) {
- String v = getString(name);
- return parseFloat(v, def);
- }
-
- /** Convert a string to a float, or uses a default if the string is malformed or null */
- static float parseFloat(String v, float def) {
- try {
- return v != null ? Float.parseFloat(v) : def;
- } catch (NumberFormatException e) {
- return def;
- }
- }
-
- /**
- * Convenience function for retrieving a single secure settings value
- * as a float. Note that internally setting values are always
- * stored as strings; this function converts the string to a float
- * for you.
- * <p>
- * This version does not take a default value. If the setting has not
- * been set, or the string value is not a number,
- * it throws {@link Settings.SettingNotFoundException}.
- *
- * @param name The name of the setting to retrieve.
- *
- * @throws Settings.SettingNotFoundException Thrown if a setting by the given
- * name can't be found or the setting value is not a float.
- *
- * @return The setting's current value.
- */
- default float getFloat(String name)
- throws Settings.SettingNotFoundException {
- String v = getString(name);
- return parseFloatOrThrow(name, v);
- }
-
- /** Convert a string to a float, or throws an exception if the string is malformed or null */
- static float parseFloatOrThrow(String name, String v)
- throws Settings.SettingNotFoundException {
- if (v == null) {
- throw new Settings.SettingNotFoundException(name);
- }
- try {
- return Float.parseFloat(v);
- } catch (NumberFormatException e) {
- throw new Settings.SettingNotFoundException(name);
- }
- }
-
- /**
- * Convenience function for updating a single settings value as a
- * floating point number. This will either create a new entry in the
- * table if the given name does not exist, or modify the value of the
- * existing row with that name. Note that internally setting values
- * are always stored as strings, so this function converts the given
- * value to a string before storing it.
- *
- * @param name The name of the setting to modify.
- * @param value The new value for the setting.
- * @return true if the value was set, false on database errors
- */
- default boolean putFloat(String name, float value) {
- return putString(name, Float.toString(value));
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
new file mode 100644
index 0000000..ec89610
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.settings
+
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.net.Uri
+import android.provider.Settings.SettingNotFoundException
+
+/**
+ * Used to interact with mainly with Settings.Global, but can also be used for Settings.System and
+ * Settings.Secure. To use the per-user System and Secure settings, [UserSettingsProxy] must be used
+ * instead.
+ *
+ * This interface can be implemented to give instance method (instead of static method) versions of
+ * Settings.Global. It can be injected into class constructors and then faked or mocked as needed in
+ * tests.
+ *
+ * You can ask for [GlobalSettings] to be injected as needed.
+ *
+ * This class also provides [.registerContentObserver] methods, normally found on [ContentResolver]
+ * instances, unifying setting related actions in one place.
+ */
+interface SettingsProxy {
+ /** Returns the [ContentResolver] this instance was constructed with. */
+ fun getContentResolver(): ContentResolver
+
+ /**
+ * Construct the content URI for a particular name/value pair, useful for monitoring changes
+ * with a ContentObserver.
+ *
+ * @param name to look up in the table
+ * @return the corresponding content URI, or null if not present
+ */
+ fun getUriFor(name: String): Uri
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * Implicitly calls [getUriFor] on the passed in name.
+ */
+ fun registerContentObserver(name: String, settingsObserver: ContentObserver) {
+ registerContentObserver(getUriFor(name), settingsObserver)
+ }
+
+ /** Convenience wrapper around [ContentResolver.registerContentObserver].' */
+ fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) =
+ registerContentObserver(uri, false, settingsObserver)
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * Implicitly calls [getUriFor] on the passed in name.
+ */
+ fun registerContentObserver(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) = registerContentObserver(getUriFor(name), notifyForDescendants, settingsObserver)
+
+ /** Convenience wrapper around [ContentResolver.registerContentObserver].' */
+ fun registerContentObserver(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) = getContentResolver().registerContentObserver(uri, notifyForDescendants, settingsObserver)
+
+ /** See [ContentResolver.unregisterContentObserver]. */
+ fun unregisterContentObserver(settingsObserver: ContentObserver) =
+ getContentResolver().unregisterContentObserver(settingsObserver)
+
+ /**
+ * Look up a name in the database.
+ *
+ * @param name to look up in the table
+ * @return the corresponding value, or null if not present
+ */
+ fun getString(name: String): String
+
+ /**
+ * Store a name/value pair into the database.
+ *
+ * @param name to store
+ * @param value to associate with the name
+ * @return true if the value was set, false on database errors
+ */
+ fun putString(name: String, value: String): Boolean
+
+ /**
+ * Store a name/value pair into the database.
+ *
+ * The method takes an optional tag to associate with the setting which can be used to clear
+ * only settings made by your package and associated with this tag by passing the tag to
+ * [ ][.resetToDefaults]. Anyone can override the current tag. Also if another package changes
+ * the setting then the tag will be set to the one specified in the set call which can be null.
+ * Also any of the settings setters that do not take a tag as an argument effectively clears the
+ * tag.
+ *
+ * For example, if you set settings A and B with tags T1 and T2 and another app changes setting
+ * A (potentially to the same value), it can assign to it a tag T3 (note that now the package
+ * that changed the setting is not yours). Now if you reset your changes for T1 and T2 only
+ * setting B will be reset and A not (as it was changed by another package) but since A did not
+ * change you are in the desired initial state. Now if the other app changes the value of A
+ * (assuming you registered an observer in the beginning) you would detect that the setting was
+ * changed by another app and handle this appropriately (ignore, set back to some value, etc).
+ *
+ * Also the method takes an argument whether to make the value the default for this setting. If
+ * the system already specified a default value, then the one passed in here will **not** be set
+ * as the default.
+ *
+ * @param name to store.
+ * @param value to associate with the name.
+ * @param tag to associate with the setting.
+ * @param makeDefault whether to make the value the default one.
+ * @return true if the value was set, false on database errors.
+ * @see .resetToDefaults
+ */
+ fun putString(name: String, value: String, tag: String, makeDefault: Boolean): Boolean
+
+ /**
+ * Convenience function for retrieving a single secure settings value as an integer. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * an integer for you. The default value will be returned if the setting is not defined or not
+ * an integer.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ * @return The setting's current value, or 'def' if it is not defined or not a valid integer.
+ */
+ fun getInt(name: String, def: Int): Int {
+ val v = getString(name)
+ return try {
+ v.toInt()
+ } catch (e: NumberFormatException) {
+ def
+ }
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as an integer. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * an integer for you.
+ *
+ * This version does not take a default value. If the setting has not been set, or the string
+ * value is not a number, it throws [Settings.SettingNotFoundException].
+ *
+ * @param name The name of the setting to retrieve.
+ * @return The setting's current value.
+ * @throws Settings.SettingNotFoundException Thrown if a setting by the given name can't be
+ * found or the setting value is not an integer.
+ */
+ @Throws(SettingNotFoundException::class)
+ fun getInt(name: String): Int {
+ val v = getString(name)
+ return try {
+ v.toInt()
+ } catch (e: NumberFormatException) {
+ throw SettingNotFoundException(name)
+ }
+ }
+
+ /**
+ * Convenience function for updating a single settings value as an integer. This will either
+ * create a new entry in the table if the given name does not exist, or modify the value of the
+ * existing row with that name. Note that internally setting values are always stored as
+ * strings, so this function converts the given value to a string before storing it.
+ *
+ * @param name The name of the setting to modify.
+ * @param value The new value for the setting.
+ * @return true if the value was set, false on database errors
+ */
+ fun putInt(name: String, value: Int): Boolean {
+ return putString(name, value.toString())
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a boolean. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * a boolean for you. The default value will be returned if the setting is not defined or not a
+ * boolean.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ * @return The setting's current value, or 'def' if it is not defined or not a valid boolean.
+ */
+ fun getBool(name: String, def: Boolean): Boolean {
+ return getInt(name, if (def) 1 else 0) != 0
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a boolean. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * a boolean for you.
+ *
+ * This version does not take a default value. If the setting has not been set, or the string
+ * value is not a number, it throws [Settings.SettingNotFoundException].
+ *
+ * @param name The name of the setting to retrieve.
+ * @return The setting's current value.
+ * @throws Settings.SettingNotFoundException Thrown if a setting by the given name can't be
+ * found or the setting value is not a boolean.
+ */
+ @Throws(SettingNotFoundException::class)
+ fun getBool(name: String): Boolean {
+ return getInt(name) != 0
+ }
+
+ /**
+ * Convenience function for updating a single settings value as a boolean. This will either
+ * create a new entry in the table if the given name does not exist, or modify the value of the
+ * existing row with that name. Note that internally setting values are always stored as
+ * strings, so this function converts the given value to a string before storing it.
+ *
+ * @param name The name of the setting to modify.
+ * @param value The new value for the setting.
+ * @return true if the value was set, false on database errors
+ */
+ fun putBool(name: String, value: Boolean): Boolean {
+ return putInt(name, if (value) 1 else 0)
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a `long`. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * a `long` for you. The default value will be returned if the setting is not defined or not a
+ * `long`.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ * @return The setting's current value, or 'def' if it is not defined or not a valid `long`.
+ */
+ fun getLong(name: String, def: Long): Long {
+ val valString = getString(name)
+ return parseLongOrUseDefault(valString, def)
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a `long`. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * a `long` for you.
+ *
+ * This version does not take a default value. If the setting has not been set, or the string
+ * value is not a number, it throws [Settings.SettingNotFoundException].
+ *
+ * @param name The name of the setting to retrieve.
+ * @return The setting's current value.
+ * @throws Settings.SettingNotFoundException Thrown if a setting by the given name can't be
+ * found or the setting value is not an integer.
+ */
+ @Throws(SettingNotFoundException::class)
+ fun getLong(name: String): Long {
+ val valString = getString(name)
+ return parseLongOrThrow(name, valString)
+ }
+
+ /**
+ * Convenience function for updating a secure settings value as a long integer. This will either
+ * create a new entry in the table if the given name does not exist, or modify the value of the
+ * existing row with that name. Note that internally setting values are always stored as
+ * strings, so this function converts the given value to a string before storing it.
+ *
+ * @param name The name of the setting to modify.
+ * @param value The new value for the setting.
+ * @return true if the value was set, false on database errors
+ */
+ fun putLong(name: String, value: Long): Boolean {
+ return putString(name, value.toString())
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a floating point
+ * number. Note that internally setting values are always stored as strings; this function
+ * converts the string to an float for you. The default value will be returned if the setting is
+ * not defined or not a valid float.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ * @return The setting's current value, or 'def' if it is not defined or not a valid float.
+ */
+ fun getFloat(name: String, def: Float): Float {
+ val v = getString(name)
+ return parseFloat(v, def)
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value as a float. Note that
+ * internally setting values are always stored as strings; this function converts the string to
+ * a float for you.
+ *
+ * This version does not take a default value. If the setting has not been set, or the string
+ * value is not a number, it throws [Settings.SettingNotFoundException].
+ *
+ * @param name The name of the setting to retrieve.
+ * @return The setting's current value.
+ * @throws Settings.SettingNotFoundException Thrown if a setting by the given name can't be
+ * found or the setting value is not a float.
+ */
+ @Throws(SettingNotFoundException::class)
+ fun getFloat(name: String): Float {
+ val v = getString(name)
+ return parseFloatOrThrow(name, v)
+ }
+
+ /**
+ * Convenience function for updating a single settings value as a floating point number. This
+ * will either create a new entry in the table if the given name does not exist, or modify the
+ * value of the existing row with that name. Note that internally setting values are always
+ * stored as strings, so this function converts the given value to a string before storing it.
+ *
+ * @param name The name of the setting to modify.
+ * @param value The new value for the setting.
+ * @return true if the value was set, false on database errors
+ */
+ fun putFloat(name: String, value: Float): Boolean {
+ return putString(name, value.toString())
+ }
+
+ companion object {
+ /** Convert a string to a long, or uses a default if the string is malformed or null */
+ @JvmStatic
+ fun parseLongOrUseDefault(valString: String, def: Long): Long {
+ val value: Long
+ value =
+ try {
+ valString.toLong()
+ } catch (e: NumberFormatException) {
+ def
+ }
+ return value
+ }
+
+ /** Convert a string to a long, or throws an exception if the string is malformed or null */
+ @JvmStatic
+ @Throws(SettingNotFoundException::class)
+ fun parseLongOrThrow(name: String, valString: String?): Long {
+ if (valString == null) {
+ throw SettingNotFoundException(name)
+ }
+ return try {
+ valString.toLong()
+ } catch (e: NumberFormatException) {
+ throw SettingNotFoundException(name)
+ }
+ }
+
+ /** Convert a string to a float, or uses a default if the string is malformed or null */
+ @JvmStatic
+ fun parseFloat(v: String?, def: Float): Float {
+ return try {
+ v?.toFloat() ?: def
+ } catch (e: NumberFormatException) {
+ def
+ }
+ }
+
+ /**
+ * Convert a string to a float, or throws an exception if the string is malformed or null
+ */
+ @JvmStatic
+ @Throws(SettingNotFoundException::class)
+ fun parseFloatOrThrow(name: String, v: String?): Float {
+ if (v == null) {
+ throw SettingNotFoundException(name)
+ }
+ return try {
+ v.toFloat()
+ } catch (e: NumberFormatException) {
+ throw SettingNotFoundException(name)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java
deleted file mode 100644
index 10cf082..0000000
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.java
+++ /dev/null
@@ -1,283 +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.util.settings;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.app.tracing.TraceUtils;
-import com.android.systemui.settings.UserTracker;
-
-import kotlin.Unit;
-
-/**
- * Used to interact with per-user Settings.Secure and Settings.System settings (but not
- * Settings.Global, since those do not vary per-user)
- * <p>
- * This interface can be implemented to give instance method (instead of static method) versions
- * of Settings.Secure and Settings.System. It can be injected into class constructors and then
- * faked or mocked as needed in tests.
- * <p>
- * You can ask for {@link SecureSettings} or {@link SystemSettings} to be injected as needed.
- * <p>
- * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
- * normally found on {@link ContentResolver} instances, unifying setting related actions in one
- * place.
- */
-public interface UserSettingsProxy extends SettingsProxy {
-
- /**
- * Returns that {@link UserTracker} this instance was constructed with.
- */
- UserTracker getUserTracker();
-
- /**
- * Returns the user id for the associated {@link ContentResolver}.
- */
- default int getUserId() {
- return getContentResolver().getUserId();
- }
-
- /**
- * Returns the actual current user handle when querying with the current user. Otherwise,
- * returns the passed in user id.
- */
- default int getRealUserHandle(int userHandle) {
- if (userHandle != UserHandle.USER_CURRENT) {
- return userHandle;
- }
- return getUserTracker().getUserId();
- }
-
- @Override
- default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
- registerContentObserverForUser(uri, settingsObserver, getUserId());
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
- */
- @Override
- default void registerContentObserver(Uri uri, boolean notifyForDescendants,
- ContentObserver settingsObserver) {
- registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, getUserId());
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
- *
- * Implicitly calls {@link #getUriFor(String)} on the passed in name.
- */
- default void registerContentObserverForUser(
- String name, ContentObserver settingsObserver, int userHandle) {
- registerContentObserverForUser(
- getUriFor(name), settingsObserver, userHandle);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
- */
- default void registerContentObserverForUser(
- Uri uri, ContentObserver settingsObserver, int userHandle) {
- registerContentObserverForUser(
- uri, false, settingsObserver, userHandle);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
- *
- * Implicitly calls {@link #getUriFor(String)} on the passed in name.
- */
- default void registerContentObserverForUser(
- String name, boolean notifyForDescendants, ContentObserver settingsObserver,
- int userHandle) {
- registerContentObserverForUser(
- getUriFor(name), notifyForDescendants, settingsObserver, userHandle);
- }
-
- /**
- * Convenience wrapper around
- * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
- */
- default void registerContentObserverForUser(
- Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver,
- int userHandle) {
- TraceUtils.trace(
- () -> {
- // The limit for trace tags length is 127 chars, which leaves us 90 for Uri.
- return "USP#registerObserver#[" + uri.toString() + "]";
- }, () -> {
- getContentResolver().registerContentObserver(
- uri, notifyForDescendants, settingsObserver,
- getRealUserHandle(userHandle));
- return Unit.INSTANCE;
- });
- }
-
- /**
- * Look up a name in the database.
- * @param name to look up in the table
- * @return the corresponding value, or null if not present
- */
- @Override
- default String getString(String name) {
- return getStringForUser(name, getUserId());
- }
-
- /**See {@link #getString(String)}. */
- String getStringForUser(String name, int userHandle);
-
- /**
- * Store a name/value pair into the database. Values written by this method will be
- * overridden if a restore happens in the future.
- *
- * @param name to store
- * @param value to associate with the name
- * @return true if the value was set, false on database errors
- */
- boolean putString(String name, String value, boolean overrideableByRestore);
-
- @Override
- default boolean putString(String name, String value) {
- return putStringForUser(name, value, getUserId());
- }
-
- /** See {@link #putString(String, String)}. */
- boolean putStringForUser(String name, String value, int userHandle);
-
- /** See {@link #putString(String, String)}. */
- boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag,
- boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore);
-
- @Override
- default int getInt(String name, int def) {
- return getIntForUser(name, def, getUserId());
- }
-
- /** See {@link #getInt(String, int)}. */
- default int getIntForUser(String name, int def, int userHandle) {
- String v = getStringForUser(name, userHandle);
- try {
- return v != null ? Integer.parseInt(v) : def;
- } catch (NumberFormatException e) {
- return def;
- }
- }
-
- @Override
- default int getInt(String name) throws Settings.SettingNotFoundException {
- return getIntForUser(name, getUserId());
- }
-
- /** See {@link #getInt(String)}. */
- default int getIntForUser(String name, int userHandle)
- throws Settings.SettingNotFoundException {
- String v = getStringForUser(name, userHandle);
- try {
- return Integer.parseInt(v);
- } catch (NumberFormatException e) {
- throw new Settings.SettingNotFoundException(name);
- }
- }
-
- @Override
- default boolean putInt(String name, int value) {
- return putIntForUser(name, value, getUserId());
- }
-
- /** See {@link #putInt(String, int)}. */
- default boolean putIntForUser(String name, int value, int userHandle) {
- return putStringForUser(name, Integer.toString(value), userHandle);
- }
-
- @Override
- default boolean getBool(String name, boolean def) {
- return getBoolForUser(name, def, getUserId());
- }
-
- /** See {@link #getBool(String, boolean)}. */
- default boolean getBoolForUser(String name, boolean def, int userHandle) {
- return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
- }
-
- @Override
- default boolean getBool(String name) throws Settings.SettingNotFoundException {
- return getBoolForUser(name, getUserId());
- }
-
- /** See {@link #getBool(String)}. */
- default boolean getBoolForUser(String name, int userHandle)
- throws Settings.SettingNotFoundException {
- return getIntForUser(name, userHandle) != 0;
- }
-
- @Override
- default boolean putBool(String name, boolean value) {
- return putBoolForUser(name, value, getUserId());
- }
-
- /** See {@link #putBool(String, boolean)}. */
- default boolean putBoolForUser(String name, boolean value, int userHandle) {
- return putIntForUser(name, value ? 1 : 0, userHandle);
- }
-
- /** See {@link #getLong(String, long)}. */
- default long getLongForUser(String name, long def, int userHandle) {
- String valString = getStringForUser(name, userHandle);
- return SettingsProxy.parseLongOrUseDefault(valString, def);
- }
-
- /** See {@link #getLong(String)}. */
- default long getLongForUser(String name, int userHandle)
- throws Settings.SettingNotFoundException {
- String valString = getStringForUser(name, userHandle);
- return SettingsProxy.parseLongOrThrow(name, valString);
- }
-
- /** See {@link #putLong(String, long)}. */
- default boolean putLongForUser(String name, long value, int userHandle) {
- return putStringForUser(name, Long.toString(value), userHandle);
- }
-
- /** See {@link #getFloat(String)}. */
- default float getFloatForUser(String name, float def, int userHandle) {
- String v = getStringForUser(name, userHandle);
- return SettingsProxy.parseFloat(v, def);
- }
-
- /** See {@link #getFloat(String, float)}. */
- default float getFloatForUser(String name, int userHandle)
- throws Settings.SettingNotFoundException {
- String v = getStringForUser(name, userHandle);
- return SettingsProxy.parseFloatOrThrow(name, v);
- }
-
- /** See {@link #putFloat(String, float)} */
- default boolean putFloatForUser(String name, float value, int userHandle) {
- return putStringForUser(name, Float.toString(value), userHandle);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
new file mode 100644
index 0000000..2285270
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.settings
+
+import android.annotation.UserIdInt
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.UserHandle
+import android.provider.Settings.SettingNotFoundException
+import com.android.app.tracing.TraceUtils.trace
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
+import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
+import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
+import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault
+
+/**
+ * Used to interact with per-user Settings.Secure and Settings.System settings (but not
+ * Settings.Global, since those do not vary per-user)
+ *
+ * This interface can be implemented to give instance method (instead of static method) versions of
+ * Settings.Secure and Settings.System. It can be injected into class constructors and then faked or
+ * mocked as needed in tests.
+ *
+ * You can ask for [SecureSettings] or [SystemSettings] to be injected as needed.
+ *
+ * This class also provides [.registerContentObserver] methods, normally found on [ContentResolver]
+ * instances, unifying setting related actions in one place.
+ */
+interface UserSettingsProxy : SettingsProxy {
+
+ /** Returns that [UserTracker] this instance was constructed with. */
+ val userTracker: UserTracker
+
+ /** Returns the user id for the associated [ContentResolver]. */
+ var userId: Int
+ get() = getContentResolver().userId
+ set(_) {
+ throw UnsupportedOperationException(
+ "userId cannot be set in interface, use setter from an implementation instead."
+ )
+ }
+
+ /**
+ * Returns the actual current user handle when querying with the current user. Otherwise,
+ * returns the passed in user id.
+ */
+ fun getRealUserHandle(userHandle: Int): Int {
+ return if (userHandle != UserHandle.USER_CURRENT) {
+ userHandle
+ } else userTracker.userId
+ }
+
+ override fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
+ registerContentObserverForUser(uri, settingsObserver, userId)
+ }
+
+ /** Convenience wrapper around [ContentResolver.registerContentObserver].' */
+ override fun registerContentObserver(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) {
+ registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, userId)
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver]
+ *
+ * Implicitly calls [getUriFor] on the passed in name.
+ */
+ fun registerContentObserverForUser(
+ name: String,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ registerContentObserverForUser(getUriFor(name), settingsObserver, userHandle)
+ }
+
+ /** Convenience wrapper around [ContentResolver.registerContentObserver] */
+ fun registerContentObserverForUser(
+ uri: Uri,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ registerContentObserverForUser(uri, false, settingsObserver, userHandle)
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver]
+ *
+ * Implicitly calls [getUriFor] on the passed in name.
+ */
+ fun registerContentObserverForUser(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ registerContentObserverForUser(
+ getUriFor(name),
+ notifyForDescendants,
+ settingsObserver,
+ userHandle
+ )
+ }
+
+ /** Convenience wrapper around [ContentResolver.registerContentObserver] */
+ fun registerContentObserverForUser(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ trace({ "USP#registerObserver#[$uri]" }) {
+ getContentResolver()
+ .registerContentObserver(
+ uri,
+ notifyForDescendants,
+ settingsObserver,
+ getRealUserHandle(userHandle)
+ )
+ Unit
+ }
+ }
+
+ /**
+ * Look up a name in the database.
+ *
+ * @param name to look up in the table
+ * @return the corresponding value, or null if not present
+ */
+ override fun getString(name: String): String {
+ return getStringForUser(name, userId)
+ }
+
+ /** See [getString]. */
+ fun getStringForUser(name: String, userHandle: Int): String
+
+ /**
+ * Store a name/value pair into the database. Values written by this method will be overridden
+ * if a restore happens in the future.
+ *
+ * @param name to store
+ * @param value to associate with the name
+ * @return true if the value was set, false on database errors
+ */
+ fun putString(name: String, value: String, overrideableByRestore: Boolean): Boolean
+ override fun putString(name: String, value: String): Boolean {
+ return putStringForUser(name, value, userId)
+ }
+
+ /** Similar implementation to [putString] for the specified [userHandle]. */
+ fun putStringForUser(name: String, value: String, userHandle: Int): Boolean
+
+ /** Similar implementation to [putString] for the specified [userHandle]. */
+ fun putStringForUser(
+ name: String,
+ value: String,
+ tag: String?,
+ makeDefault: Boolean,
+ @UserIdInt userHandle: Int,
+ overrideableByRestore: Boolean
+ ): Boolean
+
+ override fun getInt(name: String, def: Int): Int {
+ return getIntForUser(name, def, userId)
+ }
+
+ /** Similar implementation to [getInt] for the specified [userHandle]. */
+ fun getIntForUser(name: String, def: Int, userHandle: Int): Int {
+ val v = getStringForUser(name, userHandle)
+ return try {
+ v.toInt()
+ } catch (e: NumberFormatException) {
+ def
+ }
+ }
+
+ @Throws(SettingNotFoundException::class)
+ override fun getInt(name: String) = getIntForUser(name, userId)
+
+ /** Similar implementation to [getInt] for the specified [userHandle]. */
+ @Throws(SettingNotFoundException::class)
+ fun getIntForUser(name: String, userHandle: Int): Int {
+ val v = getStringForUser(name, userHandle)
+ return try {
+ v.toInt()
+ } catch (e: NumberFormatException) {
+ throw SettingNotFoundException(name)
+ }
+ }
+
+ override fun putInt(name: String, value: Int) = putIntForUser(name, value, userId)
+
+ /** Similar implementation to [getInt] for the specified [userHandle]. */
+ fun putIntForUser(name: String, value: Int, userHandle: Int) =
+ putStringForUser(name, value.toString(), userHandle)
+
+ override fun getBool(name: String, def: Boolean) = getBoolForUser(name, def, userId)
+
+ /** Similar implementation to [getBool] for the specified [userHandle]. */
+ fun getBoolForUser(name: String, def: Boolean, userHandle: Int) =
+ getIntForUser(name, if (def) 1 else 0, userHandle) != 0
+
+ @Throws(SettingNotFoundException::class)
+ override fun getBool(name: String) = getBoolForUser(name, userId)
+
+ /** Similar implementation to [getBool] for the specified [userHandle]. */
+ @Throws(SettingNotFoundException::class)
+ fun getBoolForUser(name: String, userHandle: Int): Boolean {
+ return getIntForUser(name, userHandle) != 0
+ }
+
+ override fun putBool(name: String, value: Boolean): Boolean {
+ return putBoolForUser(name, value, userId)
+ }
+
+ /** Similar implementation to [putBool] for the specified [userHandle]. */
+ fun putBoolForUser(name: String, value: Boolean, userHandle: Int) =
+ putIntForUser(name, if (value) 1 else 0, userHandle)
+
+ /** Similar implementation to [getLong] for the specified [userHandle]. */
+ fun getLongForUser(name: String, def: Long, userHandle: Int): Long {
+ val valString = getStringForUser(name, userHandle)
+ return parseLongOrUseDefault(valString, def)
+ }
+
+ /** Similar implementation to [getLong] for the specified [userHandle]. */
+ @Throws(SettingNotFoundException::class)
+ fun getLongForUser(name: String, userHandle: Int): Long {
+ val valString = getStringForUser(name, userHandle)
+ return parseLongOrThrow(name, valString)
+ }
+
+ /** Similar implementation to [putLong] for the specified [userHandle]. */
+ fun putLongForUser(name: String, value: Long, userHandle: Int) =
+ putStringForUser(name, value.toString(), userHandle)
+
+ /** Similar implementation to [getFloat] for the specified [userHandle]. */
+ fun getFloatForUser(name: String, def: Float, userHandle: Int): Float {
+ val v = getStringForUser(name, userHandle)
+ return parseFloat(v, def)
+ }
+
+ /** Similar implementation to [getFloat] for the specified [userHandle]. */
+ @Throws(SettingNotFoundException::class)
+ fun getFloatForUser(name: String, userHandle: Int): Float {
+ val v = getStringForUser(name, userHandle)
+ return parseFloatOrThrow(name, v)
+ }
+
+ /** Similar implementation to [putFloat] for the specified [userHandle]. */
+ fun putFloatForUser(name: String, value: Float, userHandle: Int) =
+ putStringForUser(name, value.toString(), userHandle)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e56893a..ce5545c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -118,6 +118,7 @@
import com.android.systemui.Prefs;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.haptics.slider.HapticSliderViewBinder;
+import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig;
import com.android.systemui.haptics.slider.SeekbarHapticPlugin;
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig;
import com.android.systemui.media.dialog.MediaOutputDialogManager;
@@ -2621,6 +2622,13 @@
/* upperBookendScale= */ 1f,
/* lowerBookendScale= */ 0.05f,
/* exponent= */ 1f / 0.89f);
+ private static final SeekableSliderTrackerConfig sSliderTrackerConfig =
+ new SeekableSliderTrackerConfig(
+ /* waitTimeMillis= */100,
+ /* jumpThreshold= */0.02f,
+ /* lowerBookendThreshold= */0.01f,
+ /* upperBookendThreshold= */0.99f
+ );
private View view;
private TextView header;
@@ -2662,7 +2670,8 @@
mHapticPlugin = new SeekbarHapticPlugin(
vibratorHelper,
systemClock,
- sSliderHapticFeedbackConfig);
+ sSliderHapticFeedbackConfig,
+ sSliderTrackerConfig);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
index 3117abc..e1787e8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
@@ -21,22 +21,15 @@
import androidx.slice.Slice
import androidx.slice.SliceViewManager
import com.android.settingslib.bluetooth.BluetoothUtils
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.slice.sliceForUri
-import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-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
/** Provides ANC slice data */
interface AncSliceRepository {
@@ -49,35 +42,30 @@
* - there is no supported device connected;
* - there is no slice provider for the uri;
*/
- fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?>
+ fun ancSlice(
+ device: BluetoothDevice,
+ width: Int,
+ isCollapsed: Boolean,
+ hideLabel: Boolean
+ ): Flow<Slice?>
}
-@OptIn(ExperimentalCoroutinesApi::class)
class AncSliceRepositoryImpl
@AssistedInject
constructor(
- mediaRepositoryFactory: LocalMediaRepositoryFactory,
- @Background private val backgroundCoroutineContext: CoroutineContext,
@Main private val mainCoroutineContext: CoroutineContext,
@Assisted private val sliceViewManager: SliceViewManager,
) : AncSliceRepository {
- private val localMediaRepository = mediaRepositoryFactory.create(null)
-
- override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
- return localMediaRepository.currentConnectedDevice
- .map {
- (it as? BluetoothMediaDevice)
- ?.cachedDevice
- ?.device
- ?.getExtraControlUri(width, isCollapsed, hideLabel)
- }
- .distinctUntilChanged()
- .flatMapLatest { sliceUri ->
- sliceUri ?: return@flatMapLatest flowOf(null)
- sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
- }
- .flowOn(backgroundCoroutineContext)
+ override fun ancSlice(
+ device: BluetoothDevice,
+ width: Int,
+ isCollapsed: Boolean,
+ hideLabel: Boolean
+ ): Flow<Slice?> {
+ val sliceUri =
+ device.getExtraControlUri(width, isCollapsed, hideLabel) ?: return flowOf(null)
+ return sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
}
private fun BluetoothDevice.getExtraControlUri(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
index cefa269..cfff457 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
@@ -19,6 +19,8 @@
import android.app.slice.Slice.HINT_ERROR
import android.app.slice.SliceItem.FORMAT_SLICE
import androidx.slice.Slice
+import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
+import com.android.systemui.volume.domain.model.AudioOutputDevice
import com.android.systemui.volume.panel.component.anc.data.repository.AncSliceRepository
import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -32,6 +34,7 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
/** Provides a valid slice from [AncSliceRepository]. */
@@ -40,6 +43,7 @@
class AncSliceInteractor
@Inject
constructor(
+ private val audioOutputInteractor: AudioOutputInteractor,
private val ancSliceRepository: AncSliceRepository,
scope: CoroutineScope,
) {
@@ -70,9 +74,20 @@
* remove the labels from the [Slice].
*/
private fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
- return ancSliceRepository
- .ancSlice(width = width, isCollapsed = isCollapsed, hideLabel = hideLabel)
- .filter { it?.isValidSlice() != false }
+ return audioOutputInteractor.currentAudioDevice.flatMapLatest { outputDevice ->
+ if (outputDevice is AudioOutputDevice.Bluetooth) {
+ ancSliceRepository
+ .ancSlice(
+ device = outputDevice.cachedBluetoothDevice.device,
+ width = width,
+ isCollapsed = isCollapsed,
+ hideLabel = hideLabel,
+ )
+ .filter { it?.isValidSlice() != false }
+ } else {
+ flowOf(null)
+ }
+ }
}
private fun Slice.isValidSlice(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt
index 4812765..a714f80 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaControllerInteractor.kt
@@ -86,7 +86,7 @@
send(MediaControllerChangeModel.ExtrasChanged(extras))
}
- override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
+ override fun onAudioInfoChanged(info: MediaController.PlaybackInfo) {
send(MediaControllerChangeModel.AudioInfoChanged(info))
}
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
index 599bd73..6e1ebc8 100644
--- 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
@@ -57,7 +57,7 @@
}
/** [MediaController.PlaybackInfo] changes for the [MediaDeviceSession]. */
- fun playbackInfo(session: MediaDeviceSession): Flow<MediaController.PlaybackInfo?> {
+ fun playbackInfo(session: MediaDeviceSession): Flow<MediaController.PlaybackInfo> {
return stateChanges(session) {
emit(MediaControllerChangeModel.AudioInfoChanged(it.playbackInfo))
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt
index ef5a44a..8b5116a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaControllerChangeModel.kt
@@ -40,6 +40,6 @@
data class ExtrasChanged(val extras: Bundle?) : MediaControllerChangeModel
- data class AudioInfoChanged(val info: MediaController.PlaybackInfo?) :
+ data class AudioInfoChanged(val info: MediaController.PlaybackInfo) :
MediaControllerChangeModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
index 298ca67..9ca50d6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -18,11 +18,9 @@
import android.media.AudioDeviceAttributes
import android.media.AudioDeviceInfo
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.media.PhoneMediaDevice
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
+import com.android.systemui.volume.domain.model.AudioOutputDevice
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -46,16 +44,20 @@
class SpatialAudioComponentInteractor
@Inject
constructor(
- mediaOutputInteractor: MediaOutputInteractor,
+ audioOutputInteractor: AudioOutputInteractor,
private val spatializerInteractor: SpatializerInteractor,
@VolumePanelScope private val coroutineScope: CoroutineScope,
) {
private val changes = MutableSharedFlow<Unit>()
private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> =
- mediaOutputInteractor.currentConnectedDevice
- .map { mediaDevice ->
- if (mediaDevice == null) builtinSpeaker else mediaDevice.getAudioDeviceAttributes()
+ audioOutputInteractor.currentAudioDevice
+ .map { audioDevice ->
+ if (audioDevice is AudioOutputDevice.Unknown) {
+ builtinSpeaker
+ } else {
+ audioDevice.getAudioDeviceAttributes()
+ }
}
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), builtinSpeaker)
@@ -135,36 +137,35 @@
changes.emit(Unit)
}
- private suspend fun MediaDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
+ private suspend fun AudioOutputDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
when (this) {
- is PhoneMediaDevice -> return builtinSpeaker
- is BluetoothMediaDevice -> {
- val device = cachedDevice ?: return null
+ is AudioOutputDevice.BuiltIn -> return builtinSpeaker
+ is AudioOutputDevice.Bluetooth -> {
return listOf(
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_BLE_HEADSET,
- device.address,
+ cachedBluetoothDevice.address,
),
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_BLE_SPEAKER,
- device.address,
+ cachedBluetoothDevice.address,
),
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_BLE_BROADCAST,
- device.address,
+ cachedBluetoothDevice.address,
),
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
- device.address,
+ cachedBluetoothDevice.address,
),
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_HEARING_AID,
- device.address,
+ cachedBluetoothDevice.address,
)
)
.firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
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 c08cd64..fd01b48 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
@@ -77,8 +77,6 @@
mapOf(
AudioStream(AudioManager.STREAM_NOTIFICATION) to
R.string.stream_notification_unavailable,
- AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm_unavailable,
- AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_media_unavailable,
)
private val uiEventByStream =
mapOf(
@@ -126,7 +124,7 @@
}
}
- private suspend fun AudioStreamModel.toState(
+ private fun AudioStreamModel.toState(
isEnabled: Boolean,
ringerMode: RingerMode,
): State {
@@ -138,7 +136,13 @@
valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
icon = getIcon(ringerMode),
label = label,
- disabledMessage = disabledTextByStream[audioStream]?.let(context::getString),
+ disabledMessage =
+ context.getString(
+ disabledTextByStream.getOrDefault(
+ audioStream,
+ R.string.stream_alarm_unavailable,
+ )
+ ),
isEnabled = isEnabled,
a11yStep = volumeRange.step,
a11yClickDescription =
@@ -167,14 +171,13 @@
null
},
audioStreamModel = this,
- isMutable = audioVolumeInteractor.isAffectedByMute(audioStream),
+ isMutable = isAffectedByMute,
)
}
private fun AudioStreamModel.getIcon(ringerMode: RingerMode): Icon {
- val isMutedOrNoVolume = isMuted || volume == minVolume
val iconRes =
- if (isMutedOrNoVolume) {
+ if (isAffectedByMute && isMuted) {
if (audioStream.value in streamsAffectedByRing) {
if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
R.drawable.ic_volume_ringer_vibrate
diff --git a/packages/SystemUI/tests/goldens/animateFailure.json b/packages/SystemUI/tests/goldens/animateFailure.json
new file mode 100644
index 0000000..a008f92
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/animateFailure.json
@@ -0,0 +1,612 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ 64,
+ 80,
+ 96,
+ 112,
+ 128,
+ 144,
+ 160,
+ 176,
+ 192,
+ 208,
+ 224,
+ 240,
+ 256,
+ 272,
+ 288,
+ 304,
+ 320,
+ 336,
+ 352,
+ 368,
+ 384,
+ 400,
+ 416,
+ 432,
+ 448,
+ 464,
+ 480,
+ 496,
+ 512,
+ 528,
+ 544,
+ 560,
+ 576,
+ 592,
+ 608,
+ 624,
+ 640,
+ 656,
+ 672,
+ 688,
+ 704,
+ 720,
+ 736,
+ 752,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "PinBouncer::dotScaling",
+ "type": "float[]",
+ "data_points": [
+ [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ [
+ 0.93142855,
+ 1,
+ 1,
+ 0.93142855,
+ 1,
+ 1,
+ 0.93142855,
+ 1,
+ 1
+ ],
+ [
+ 0.86285716,
+ 1,
+ 1,
+ 0.86285716,
+ 1,
+ 1,
+ 0.86285716,
+ 1,
+ 1
+ ],
+ [
+ 0.7942857,
+ 0.93571424,
+ 1,
+ 0.7942857,
+ 0.93571424,
+ 1,
+ 0.7942857,
+ 0.93571424,
+ 1
+ ],
+ [
+ 0.78571427,
+ 0.86714286,
+ 1,
+ 0.78571427,
+ 0.86714286,
+ 1,
+ 0.78571427,
+ 0.86714286,
+ 1
+ ],
+ [
+ 0.78571427,
+ 0.7985714,
+ 0.94000006,
+ 0.78571427,
+ 0.7985714,
+ 0.94000006,
+ 0.78571427,
+ 0.7985714,
+ 0.94000006
+ ],
+ [
+ 0.7872844,
+ 0.78571427,
+ 0.87142855,
+ 0.7872844,
+ 0.78571427,
+ 0.87142855,
+ 0.7872844,
+ 0.78571427,
+ 0.87142855
+ ],
+ [
+ 0.7925441,
+ 0.78571427,
+ 0.8028571,
+ 0.7925441,
+ 0.78571427,
+ 0.8028571,
+ 0.7925441,
+ 0.78571427,
+ 0.8028571
+ ],
+ [
+ 0.8037901,
+ 0.7872844,
+ 0.78571427,
+ 0.8037901,
+ 0.7872844,
+ 0.78571427,
+ 0.8037901,
+ 0.7872844,
+ 0.78571427
+ ],
+ [
+ 0.8223549,
+ 0.7925441,
+ 0.78571427,
+ 0.8223549,
+ 0.7925441,
+ 0.78571427,
+ 0.8223549,
+ 0.7925441,
+ 0.78571427
+ ],
+ [
+ 0.84427696,
+ 0.8037901,
+ 0.7872844,
+ 0.84427696,
+ 0.8037901,
+ 0.7872844,
+ 0.84427696,
+ 0.8037901,
+ 0.7872844
+ ],
+ [
+ 0.864585,
+ 0.8223549,
+ 0.7925441,
+ 0.864585,
+ 0.8223549,
+ 0.7925441,
+ 0.864585,
+ 0.8223549,
+ 0.7925441
+ ],
+ [
+ 0.8817363,
+ 0.84427696,
+ 0.8037901,
+ 0.8817363,
+ 0.84427696,
+ 0.8037901,
+ 0.8817363,
+ 0.84427696,
+ 0.8037901
+ ],
+ [
+ 0.89635646,
+ 0.864585,
+ 0.8223549,
+ 0.89635646,
+ 0.864585,
+ 0.8223549,
+ 0.89635646,
+ 0.864585,
+ 0.8223549
+ ],
+ [
+ 0.908528,
+ 0.8817363,
+ 0.84427696,
+ 0.908528,
+ 0.8817363,
+ 0.84427696,
+ 0.908528,
+ 0.8817363,
+ 0.84427696
+ ],
+ [
+ 0.91881,
+ 0.89635646,
+ 0.864585,
+ 0.91881,
+ 0.89635646,
+ 0.864585,
+ 0.91881,
+ 0.89635646,
+ 0.864585
+ ],
+ [
+ 0.9280548,
+ 0.908528,
+ 0.8817363,
+ 0.9280548,
+ 0.908528,
+ 0.8817363,
+ 0.9280548,
+ 0.908528,
+ 0.8817363
+ ],
+ [
+ 0.9362979,
+ 0.91881,
+ 0.89635646,
+ 0.9362979,
+ 0.91881,
+ 0.89635646,
+ 0.9362979,
+ 0.91881,
+ 0.89635646
+ ],
+ [
+ 0.9433999,
+ 0.9280548,
+ 0.908528,
+ 0.9433999,
+ 0.9280548,
+ 0.908528,
+ 0.9433999,
+ 0.9280548,
+ 0.908528
+ ],
+ [
+ 0.9497632,
+ 0.9362979,
+ 0.91881,
+ 0.9497632,
+ 0.9362979,
+ 0.91881,
+ 0.9497632,
+ 0.9362979,
+ 0.91881
+ ],
+ [
+ 0.9552536,
+ 0.9433999,
+ 0.9280548,
+ 0.9552536,
+ 0.9433999,
+ 0.9280548,
+ 0.9552536,
+ 0.9433999,
+ 0.9280548
+ ],
+ [
+ 0.96035147,
+ 0.9497632,
+ 0.9362979,
+ 0.96035147,
+ 0.9497632,
+ 0.9362979,
+ 0.96035147,
+ 0.9497632,
+ 0.9362979
+ ],
+ [
+ 0.9649086,
+ 0.9552536,
+ 0.9433999,
+ 0.9649086,
+ 0.9552536,
+ 0.9433999,
+ 0.9649086,
+ 0.9552536,
+ 0.9433999
+ ],
+ [
+ 0.96897155,
+ 0.96035147,
+ 0.9497632,
+ 0.96897155,
+ 0.96035147,
+ 0.9497632,
+ 0.96897155,
+ 0.96035147,
+ 0.9497632
+ ],
+ [
+ 0.9727647,
+ 0.9649086,
+ 0.9552536,
+ 0.9727647,
+ 0.9649086,
+ 0.9552536,
+ 0.9727647,
+ 0.9649086,
+ 0.9552536
+ ],
+ [
+ 0.9760455,
+ 0.96897155,
+ 0.96035147,
+ 0.9760455,
+ 0.96897155,
+ 0.96035147,
+ 0.9760455,
+ 0.96897155,
+ 0.96035147
+ ],
+ [
+ 0.97915274,
+ 0.9727647,
+ 0.9649086,
+ 0.97915274,
+ 0.9727647,
+ 0.9649086,
+ 0.97915274,
+ 0.9727647,
+ 0.9649086
+ ],
+ [
+ 0.98185575,
+ 0.9760455,
+ 0.96897155,
+ 0.98185575,
+ 0.9760455,
+ 0.96897155,
+ 0.98185575,
+ 0.9760455,
+ 0.96897155
+ ],
+ [
+ 0.98434585,
+ 0.97915274,
+ 0.9727647,
+ 0.98434585,
+ 0.97915274,
+ 0.9727647,
+ 0.98434585,
+ 0.97915274,
+ 0.9727647
+ ],
+ [
+ 0.9866356,
+ 0.98185575,
+ 0.9760455,
+ 0.9866356,
+ 0.98185575,
+ 0.9760455,
+ 0.9866356,
+ 0.98185575,
+ 0.9760455
+ ],
+ [
+ 0.98856884,
+ 0.98434585,
+ 0.97915274,
+ 0.98856884,
+ 0.98434585,
+ 0.97915274,
+ 0.98856884,
+ 0.98434585,
+ 0.97915274
+ ],
+ [
+ 0.99050206,
+ 0.9866356,
+ 0.98185575,
+ 0.99050206,
+ 0.9866356,
+ 0.98185575,
+ 0.99050206,
+ 0.9866356,
+ 0.98185575
+ ],
+ [
+ 0.9920071,
+ 0.98856884,
+ 0.98434585,
+ 0.9920071,
+ 0.98856884,
+ 0.98434585,
+ 0.9920071,
+ 0.98856884,
+ 0.98434585
+ ],
+ [
+ 0.99343646,
+ 0.99050206,
+ 0.9866356,
+ 0.99343646,
+ 0.99050206,
+ 0.9866356,
+ 0.99343646,
+ 0.99050206,
+ 0.9866356
+ ],
+ [
+ 0.99481374,
+ 0.9920071,
+ 0.98856884,
+ 0.99481374,
+ 0.9920071,
+ 0.98856884,
+ 0.99481374,
+ 0.9920071,
+ 0.98856884
+ ],
+ [
+ 0.99578595,
+ 0.99343646,
+ 0.99050206,
+ 0.99578595,
+ 0.99343646,
+ 0.99050206,
+ 0.99578595,
+ 0.99343646,
+ 0.99050206
+ ],
+ [
+ 0.9967581,
+ 0.99481374,
+ 0.9920071,
+ 0.9967581,
+ 0.99481374,
+ 0.9920071,
+ 0.9967581,
+ 0.99481374,
+ 0.9920071
+ ],
+ [
+ 0.9976717,
+ 0.99578595,
+ 0.99343646,
+ 0.9976717,
+ 0.99578595,
+ 0.99343646,
+ 0.9976717,
+ 0.99578595,
+ 0.99343646
+ ],
+ [
+ 0.99822795,
+ 0.9967581,
+ 0.99481374,
+ 0.99822795,
+ 0.9967581,
+ 0.99481374,
+ 0.99822795,
+ 0.9967581,
+ 0.99481374
+ ],
+ [
+ 0.99878407,
+ 0.9976717,
+ 0.99578595,
+ 0.99878407,
+ 0.9976717,
+ 0.99578595,
+ 0.99878407,
+ 0.9976717,
+ 0.99578595
+ ],
+ [
+ 0.9993403,
+ 0.99822795,
+ 0.9967581,
+ 0.9993403,
+ 0.99822795,
+ 0.9967581,
+ 0.9993403,
+ 0.99822795,
+ 0.9967581
+ ],
+ [
+ 0.99954754,
+ 0.99878407,
+ 0.9976717,
+ 0.99954754,
+ 0.99878407,
+ 0.9976717,
+ 0.99954754,
+ 0.99878407,
+ 0.9976717
+ ],
+ [
+ 0.9997241,
+ 0.9993403,
+ 0.99822795,
+ 0.9997241,
+ 0.9993403,
+ 0.99822795,
+ 0.9997241,
+ 0.9993403,
+ 0.99822795
+ ],
+ [
+ 0.9999007,
+ 0.99954754,
+ 0.99878407,
+ 0.9999007,
+ 0.99954754,
+ 0.99878407,
+ 0.9999007,
+ 0.99954754,
+ 0.99878407
+ ],
+ [
+ 1,
+ 0.9997241,
+ 0.9993403,
+ 1,
+ 0.9997241,
+ 0.9993403,
+ 1,
+ 0.9997241,
+ 0.9993403
+ ],
+ [
+ 1,
+ 0.9999007,
+ 0.99954754,
+ 1,
+ 0.9999007,
+ 0.99954754,
+ 1,
+ 0.9999007,
+ 0.99954754
+ ],
+ [
+ 1,
+ 1,
+ 0.9997241,
+ 1,
+ 1,
+ 0.9997241,
+ 1,
+ 1,
+ 0.9997241
+ ],
+ [
+ 1,
+ 1,
+ 0.9999007,
+ 1,
+ 1,
+ 0.9999007,
+ 1,
+ 1,
+ 0.9999007
+ ],
+ [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/doubleClick_swapSide.json b/packages/SystemUI/tests/goldens/doubleClick_swapSide.json
new file mode 100644
index 0000000..044ddbc
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/doubleClick_swapSide.json
@@ -0,0 +1,195 @@
+{
+ "frame_ids": [
+ "before",
+ 0,
+ 16,
+ 32,
+ 48,
+ 64,
+ 80,
+ 96,
+ 112,
+ 128,
+ 144,
+ 160,
+ 176,
+ 192,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "userSwitcher_pos",
+ "type": "dpOffset",
+ "data_points": [
+ {
+ "x": 0,
+ "y": 96
+ },
+ {
+ "x": 0,
+ "y": 96
+ },
+ {
+ "x": 0,
+ "y": 96
+ },
+ {
+ "x": 0,
+ "y": 96
+ },
+ {
+ "x": 45.008995,
+ "y": 96
+ },
+ {
+ "x": 123.20912,
+ "y": 96
+ },
+ {
+ "x": 194.33762,
+ "y": 96
+ },
+ {
+ "x": 248.24419,
+ "y": 96
+ },
+ {
+ "x": 285.66364,
+ "y": 96
+ },
+ {
+ "x": 310.326,
+ "y": 96
+ },
+ {
+ "x": 326.03296,
+ "y": 96
+ },
+ {
+ "x": 335.79584,
+ "y": 96
+ },
+ {
+ "x": 341.7547,
+ "y": 96
+ },
+ {
+ "x": 345.34082,
+ "y": 96
+ },
+ {
+ "x": 350.4762,
+ "y": 96
+ }
+ ]
+ },
+ {
+ "name": "userSwitcher_alpha",
+ "type": "float",
+ "data_points": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 0.44034958,
+ 0,
+ 0,
+ 0,
+ 0.24635443,
+ 0.49282384,
+ 0.67560554,
+ 0.7993379,
+ 0.8786727,
+ 0.9278107,
+ 1
+ ]
+ },
+ {
+ "name": "foldAware_pos",
+ "type": "dpOffset",
+ "data_points": [
+ {
+ "x": 350.4762,
+ "y": 96
+ },
+ {
+ "x": 350.4762,
+ "y": 96
+ },
+ {
+ "x": 350.4762,
+ "y": 96
+ },
+ {
+ "x": 350.4762,
+ "y": 96
+ },
+ {
+ "x": 305.4672,
+ "y": 96
+ },
+ {
+ "x": 227.26706,
+ "y": 96
+ },
+ {
+ "x": 156.13857,
+ "y": 96
+ },
+ {
+ "x": 102.232,
+ "y": 96
+ },
+ {
+ "x": 64.81257,
+ "y": 96
+ },
+ {
+ "x": 40.150204,
+ "y": 96
+ },
+ {
+ "x": 24.443243,
+ "y": 96
+ },
+ {
+ "x": 14.680362,
+ "y": 96
+ },
+ {
+ "x": 8.721494,
+ "y": 96
+ },
+ {
+ "x": 5.1353703,
+ "y": 96
+ },
+ {
+ "x": 0,
+ "y": 96
+ }
+ ]
+ },
+ {
+ "name": "foldAware_alpha",
+ "type": "float",
+ "data_points": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 0.44034958,
+ 0,
+ 0,
+ 0,
+ 0.24635443,
+ 0.49282384,
+ 0.67560554,
+ 0.7993379,
+ 0.8786727,
+ 0.9278107,
+ 1
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/entryAnimation.json b/packages/SystemUI/tests/goldens/entryAnimation.json
new file mode 100644
index 0000000..11bf09f
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/entryAnimation.json
@@ -0,0 +1,823 @@
+{
+ "frame_ids": [
+ 0,
+ 16,
+ 32,
+ 48,
+ 64,
+ 80,
+ 96,
+ 112,
+ 128,
+ 144,
+ 160,
+ 176,
+ 192,
+ 208,
+ 224,
+ 240,
+ 256,
+ 272,
+ 288,
+ 304,
+ 320,
+ 336,
+ 352,
+ 368,
+ 384,
+ 400,
+ 416,
+ 432,
+ 448,
+ 464,
+ 480,
+ 496,
+ 512,
+ 528,
+ "after"
+ ],
+ "features": [
+ {
+ "name": "PinBouncer::dotAppearFadeIn",
+ "type": "float[]",
+ "data_points": [
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0.13006775,
+ 0,
+ 0,
+ 0.13006775,
+ 0,
+ 0,
+ 0.13006775,
+ 0,
+ 0
+ ],
+ [
+ 0.23268975,
+ 0,
+ 0,
+ 0.23268975,
+ 0,
+ 0,
+ 0.23268975,
+ 0,
+ 0
+ ],
+ [
+ 0.31893033,
+ 0.12296748,
+ 0,
+ 0.31893033,
+ 0.12296748,
+ 0,
+ 0.31893033,
+ 0.12296748,
+ 0
+ ],
+ [
+ 0.3938481,
+ 0.22658443,
+ 0,
+ 0.3938481,
+ 0.22658443,
+ 0,
+ 0.3938481,
+ 0.22658443,
+ 0
+ ],
+ [
+ 0.45988238,
+ 0.3139104,
+ 0.115867205,
+ 0.45988238,
+ 0.3139104,
+ 0.115867205,
+ 0.45988238,
+ 0.3139104,
+ 0.115867205
+ ],
+ [
+ 0.52037334,
+ 0.38916573,
+ 0.22036704,
+ 0.52037334,
+ 0.38916573,
+ 0.22036704,
+ 0.52037334,
+ 0.38916573,
+ 0.22036704
+ ],
+ [
+ 0.57470226,
+ 0.45587063,
+ 0.3084957,
+ 0.57470226,
+ 0.45587063,
+ 0.3084957,
+ 0.57470226,
+ 0.45587063,
+ 0.3084957
+ ],
+ [
+ 0.6230466,
+ 0.5169778,
+ 0.38448337,
+ 0.6230466,
+ 0.5169778,
+ 0.38448337,
+ 0.6230466,
+ 0.5169778,
+ 0.38448337
+ ],
+ [
+ 0.6682857,
+ 0.5713067,
+ 0.45185885,
+ 0.6682857,
+ 0.5713067,
+ 0.45185885,
+ 0.6682857,
+ 0.5713067,
+ 0.45185885
+ ],
+ [
+ 0.7079632,
+ 0.6202191,
+ 0.5135822,
+ 0.7079632,
+ 0.6202191,
+ 0.5135822,
+ 0.7079632,
+ 0.6202191,
+ 0.5135822
+ ],
+ [
+ 0.7447962,
+ 0.6654583,
+ 0.56791115,
+ 0.7447962,
+ 0.6654583,
+ 0.56791115,
+ 0.7447962,
+ 0.6654583,
+ 0.56791115
+ ],
+ [
+ 0.77875835,
+ 0.7056612,
+ 0.6173917,
+ 0.77875835,
+ 0.7056612,
+ 0.6173917,
+ 0.77875835,
+ 0.7056612,
+ 0.6173917
+ ],
+ [
+ 0.80779475,
+ 0.74249417,
+ 0.66263086,
+ 0.80779475,
+ 0.74249417,
+ 0.66263086,
+ 0.80779475,
+ 0.74249417,
+ 0.66263086
+ ],
+ [
+ 0.83683115,
+ 0.77694356,
+ 0.7033591,
+ 0.83683115,
+ 0.77694356,
+ 0.7033591,
+ 0.83683115,
+ 0.77694356,
+ 0.7033591
+ ],
+ [
+ 0.86171645,
+ 0.80597997,
+ 0.7401921,
+ 0.86171645,
+ 0.80597997,
+ 0.7401921,
+ 0.86171645,
+ 0.80597997,
+ 0.7401921
+ ],
+ [
+ 0.884127,
+ 0.83501637,
+ 0.7751288,
+ 0.884127,
+ 0.83501637,
+ 0.7751288,
+ 0.884127,
+ 0.83501637,
+ 0.7751288
+ ],
+ [
+ 0.9042124,
+ 0.86024225,
+ 0.8041652,
+ 0.9042124,
+ 0.86024225,
+ 0.8041652,
+ 0.9042124,
+ 0.86024225,
+ 0.8041652
+ ],
+ [
+ 0.9215058,
+ 0.8828717,
+ 0.8332016,
+ 0.9215058,
+ 0.8828717,
+ 0.8332016,
+ 0.9215058,
+ 0.8828717,
+ 0.8332016
+ ],
+ [
+ 0.9374617,
+ 0.9029571,
+ 0.8587681,
+ 0.9374617,
+ 0.9029571,
+ 0.8587681,
+ 0.9374617,
+ 0.9029571,
+ 0.8587681
+ ],
+ [
+ 0.95089734,
+ 0.92046183,
+ 0.88161635,
+ 0.95089734,
+ 0.92046183,
+ 0.88161635,
+ 0.95089734,
+ 0.92046183,
+ 0.88161635
+ ],
+ [
+ 0.9626156,
+ 0.93662196,
+ 0.90170175,
+ 0.9626156,
+ 0.93662196,
+ 0.90170175,
+ 0.9626156,
+ 0.93662196,
+ 0.90170175
+ ],
+ [
+ 0.97289115,
+ 0.95005757,
+ 0.91941786,
+ 0.97289115,
+ 0.95005757,
+ 0.91941786,
+ 0.97289115,
+ 0.95005757,
+ 0.91941786
+ ],
+ [
+ 0.98082036,
+ 0.96197337,
+ 0.9357822,
+ 0.98082036,
+ 0.96197337,
+ 0.9357822,
+ 0.98082036,
+ 0.96197337,
+ 0.9357822
+ ],
+ [
+ 0.98803866,
+ 0.9722489,
+ 0.94921786,
+ 0.98803866,
+ 0.9722489,
+ 0.94921786,
+ 0.98803866,
+ 0.9722489,
+ 0.94921786
+ ],
+ [
+ 0.99259704,
+ 0.98036927,
+ 0.9613311,
+ 0.99259704,
+ 0.98036927,
+ 0.9613311,
+ 0.99259704,
+ 0.98036927,
+ 0.9613311
+ ],
+ [
+ 0.99685574,
+ 0.9875875,
+ 0.97160673,
+ 0.99685574,
+ 0.9875875,
+ 0.97160673,
+ 0.99685574,
+ 0.9875875,
+ 0.97160673
+ ],
+ [
+ 0.9984336,
+ 0.99233085,
+ 0.9799181,
+ 0.9984336,
+ 0.99233085,
+ 0.9799181,
+ 0.9984336,
+ 0.99233085,
+ 0.9799181
+ ],
+ [
+ 0.99982595,
+ 0.99658954,
+ 0.98713636,
+ 0.99982595,
+ 0.99658954,
+ 0.98713636,
+ 0.99982595,
+ 0.99658954,
+ 0.98713636
+ ],
+ [
+ 1,
+ 0.99834657,
+ 0.99206465,
+ 1,
+ 0.99834657,
+ 0.99206465,
+ 1,
+ 0.99834657,
+ 0.99206465
+ ],
+ [
+ 1,
+ 0.99973893,
+ 0.9963234,
+ 1,
+ 0.99973893,
+ 0.9963234,
+ 1,
+ 0.99973893,
+ 0.9963234
+ ],
+ [
+ 1,
+ 1,
+ 0.99825954,
+ 1,
+ 1,
+ 0.99825954,
+ 1,
+ 1,
+ 0.99825954
+ ],
+ [
+ 1,
+ 1,
+ 0.9996519,
+ 1,
+ 1,
+ 0.9996519,
+ 1,
+ 1,
+ 0.9996519
+ ],
+ [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "PinBouncer::dotAppearMoveUp",
+ "type": "float[]",
+ "data_points": [
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ [
+ 0.25108898,
+ 0.24185245,
+ 0.23379733,
+ 0.25108898,
+ 0.24185245,
+ 0.23379733,
+ 0.25108898,
+ 0.24185245,
+ 0.23379733
+ ],
+ [
+ 0.36994478,
+ 0.35579002,
+ 0.34344575,
+ 0.36994478,
+ 0.35579002,
+ 0.34344575,
+ 0.36994478,
+ 0.35579002,
+ 0.34344575
+ ],
+ [
+ 0.45856017,
+ 0.44208717,
+ 0.4277212,
+ 0.45856017,
+ 0.44208717,
+ 0.4277212,
+ 0.45856017,
+ 0.44208717,
+ 0.4277212
+ ],
+ [
+ 0.5303175,
+ 0.5132119,
+ 0.49780974,
+ 0.5303175,
+ 0.5132119,
+ 0.49780974,
+ 0.5303175,
+ 0.5132119,
+ 0.49780974
+ ],
+ [
+ 0.5929084,
+ 0.57152635,
+ 0.5528793,
+ 0.5929084,
+ 0.57152635,
+ 0.5528793,
+ 0.5929084,
+ 0.57152635,
+ 0.5528793
+ ],
+ [
+ 0.6415321,
+ 0.6216319,
+ 0.6042771,
+ 0.6415321,
+ 0.6216319,
+ 0.6042771,
+ 0.6415321,
+ 0.6216319,
+ 0.6042771
+ ],
+ [
+ 0.6889181,
+ 0.6668597,
+ 0.64661235,
+ 0.6889181,
+ 0.6668597,
+ 0.64661235,
+ 0.6889181,
+ 0.6668597,
+ 0.64661235
+ ],
+ [
+ 0.72852343,
+ 0.70699567,
+ 0.6879909,
+ 0.72852343,
+ 0.70699567,
+ 0.6879909,
+ 0.72852343,
+ 0.70699567,
+ 0.6879909
+ ],
+ [
+ 0.763233,
+ 0.7418899,
+ 0.7227609,
+ 0.763233,
+ 0.7418899,
+ 0.7227609,
+ 0.763233,
+ 0.7418899,
+ 0.7227609
+ ],
+ [
+ 0.7938958,
+ 0.7733934,
+ 0.75354666,
+ 0.7938958,
+ 0.7733934,
+ 0.75354666,
+ 0.7938958,
+ 0.7733934,
+ 0.75354666
+ ],
+ [
+ 0.82150793,
+ 0.8013512,
+ 0.7816832,
+ 0.82150793,
+ 0.8013512,
+ 0.7816832,
+ 0.82150793,
+ 0.8013512,
+ 0.7816832
+ ],
+ [
+ 0.84668195,
+ 0.82613826,
+ 0.807758,
+ 0.84668195,
+ 0.82613826,
+ 0.807758,
+ 0.84668195,
+ 0.82613826,
+ 0.807758
+ ],
+ [
+ 0.86843777,
+ 0.84911424,
+ 0.83017635,
+ 0.86843777,
+ 0.84911424,
+ 0.83017635,
+ 0.86843777,
+ 0.84911424,
+ 0.83017635
+ ],
+ [
+ 0.88804924,
+ 0.86938363,
+ 0.85123545,
+ 0.88804924,
+ 0.86938363,
+ 0.85123545,
+ 0.88804924,
+ 0.86938363,
+ 0.85123545
+ ],
+ [
+ 0.90616417,
+ 0.8875992,
+ 0.87020856,
+ 0.90616417,
+ 0.8875992,
+ 0.87020856,
+ 0.90616417,
+ 0.8875992,
+ 0.87020856
+ ],
+ [
+ 0.92120105,
+ 0.90447646,
+ 0.8872067,
+ 0.92120105,
+ 0.90447646,
+ 0.8872067,
+ 0.92120105,
+ 0.90447646,
+ 0.8872067
+ ],
+ [
+ 0.93561906,
+ 0.91881925,
+ 0.9030046,
+ 0.93561906,
+ 0.91881925,
+ 0.9030046,
+ 0.93561906,
+ 0.91881925,
+ 0.9030046
+ ],
+ [
+ 0.9472463,
+ 0.9325603,
+ 0.91674215,
+ 0.9472463,
+ 0.9325603,
+ 0.91674215,
+ 0.9472463,
+ 0.9325603,
+ 0.91674215
+ ],
+ [
+ 0.95841366,
+ 0.9437798,
+ 0.9296044,
+ 0.95841366,
+ 0.9437798,
+ 0.9296044,
+ 0.95841366,
+ 0.9437798,
+ 0.9296044
+ ],
+ [
+ 0.9671384,
+ 0.9546126,
+ 0.9407567,
+ 0.9671384,
+ 0.9546126,
+ 0.9407567,
+ 0.9671384,
+ 0.9546126,
+ 0.9407567
+ ],
+ [
+ 0.97568256,
+ 0.96334505,
+ 0.95089674,
+ 0.97568256,
+ 0.96334505,
+ 0.95089674,
+ 0.97568256,
+ 0.96334505,
+ 0.95089674
+ ],
+ [
+ 0.98170155,
+ 0.9714737,
+ 0.9600369,
+ 0.98170155,
+ 0.9714737,
+ 0.9600369,
+ 0.98170155,
+ 0.9714737,
+ 0.9600369
+ ],
+ [
+ 0.9877205,
+ 0.9782621,
+ 0.96764565,
+ 0.9877205,
+ 0.9782621,
+ 0.96764565,
+ 0.9877205,
+ 0.9782621,
+ 0.96764565
+ ],
+ [
+ 0.9916518,
+ 0.98386985,
+ 0.9752545,
+ 0.9916518,
+ 0.98386985,
+ 0.9752545,
+ 0.9916518,
+ 0.98386985,
+ 0.9752545
+ ],
+ [
+ 0.99514234,
+ 0.98918015,
+ 0.9805117,
+ 0.99514234,
+ 0.98918015,
+ 0.9805117,
+ 0.99514234,
+ 0.98918015,
+ 0.9805117
+ ],
+ [
+ 0.9976143,
+ 0.99243224,
+ 0.98576087,
+ 0.9976143,
+ 0.99243224,
+ 0.98576087,
+ 0.9976143,
+ 0.99243224,
+ 0.98576087
+ ],
+ [
+ 0.998737,
+ 0.9956844,
+ 0.9900688,
+ 0.998737,
+ 0.9956844,
+ 0.9900688,
+ 0.998737,
+ 0.9956844,
+ 0.9900688
+ ],
+ [
+ 0.9998597,
+ 0.99771196,
+ 0.9931129,
+ 0.9998597,
+ 0.99771196,
+ 0.9931129,
+ 0.9998597,
+ 0.99771196,
+ 0.9931129
+ ],
+ [
+ 1,
+ 0.9987579,
+ 0.99615705,
+ 1,
+ 0.9987579,
+ 0.99615705,
+ 1,
+ 0.9987579,
+ 0.99615705
+ ],
+ [
+ 1,
+ 0.9998039,
+ 0.9977971,
+ 1,
+ 0.9998039,
+ 0.9977971,
+ 1,
+ 0.9998039,
+ 0.9977971
+ ],
+ [
+ 1,
+ 1,
+ 0.99877614,
+ 1,
+ 1,
+ 0.99877614,
+ 1,
+ 1,
+ 0.99877614
+ ],
+ [
+ 1,
+ 1,
+ 0.9997552,
+ 1,
+ 1,
+ 0.9997552,
+ 1,
+ 1,
+ 0.9997552
+ ],
+ [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
similarity index 77%
rename from packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
index 516b665..93c0eea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
@@ -39,9 +39,9 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class WindowMagnificationSizePrefsTest extends SysuiTestCase {
+public class WindowMagnificationFrameSizePrefsTest extends SysuiTestCase {
- WindowMagnificationSizePrefs mWindowMagnificationSizePrefs;
+ WindowMagnificationFrameSizePrefs mWindowMagnificationFrameSizePrefs;
FakeSharedPreferences mSharedPreferences;
@Before
@@ -51,24 +51,24 @@
when(mContext.getSharedPreferences(
eq("window_magnification_preferences"), anyInt()))
.thenReturn(mSharedPreferences);
- mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
+ mWindowMagnificationFrameSizePrefs = new WindowMagnificationFrameSizePrefs(mContext);
}
@Test
public void saveSizeForCurrentDensity_getExpectedSize() {
Size testSize = new Size(500, 500);
- mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+ mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(testSize);
- assertThat(mWindowMagnificationSizePrefs.getSizeForCurrentDensity())
+ assertThat(mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity())
.isEqualTo(testSize);
}
@Test
public void saveSizeForCurrentDensity_containsPreferenceForCurrentDensity() {
Size testSize = new Size(500, 500);
- mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+ mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(testSize);
- assertThat(mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity())
+ assertThat(mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity())
.isTrue();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
index 0df4fbf..9ba56d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
@@ -36,12 +36,12 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.any
private const val USER_ID = 8
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 5e4272f..2682633 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
@@ -44,6 +44,8 @@
import org.mockito.junit.MockitoJUnit
private const val USER_ID = 9
+private const val REQUEST_ID = 9L
+private const val WRONG_REQUEST_ID = 10L
private const val CHALLENGE = 90L
private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -105,6 +107,7 @@
repository.setPrompt(
PromptInfo().apply { isConfirmationRequested = case },
USER_ID,
+ REQUEST_ID,
CHALLENGE,
PromptKind.Biometric(),
OP_PACKAGE_NAME
@@ -124,6 +127,7 @@
repository.setPrompt(
PromptInfo().apply { isConfirmationRequested = case },
USER_ID,
+ REQUEST_ID,
CHALLENGE,
PromptKind.Biometric(),
OP_PACKAGE_NAME
@@ -134,12 +138,12 @@
}
@Test
- fun setsAndUnsetsPrompt() =
+ fun setsAndUnsetsPrompt_whenRequestIdMatches() =
testScope.runTest {
val kind = PromptKind.Pin
val promptInfo = PromptInfo()
- repository.setPrompt(promptInfo, USER_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
+ repository.setPrompt(promptInfo, USER_ID, REQUEST_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
assertThat(repository.promptKind.value).isEqualTo(kind)
assertThat(repository.userId.value).isEqualTo(USER_ID)
@@ -147,11 +151,33 @@
assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
assertThat(repository.opPackageName.value).isEqualTo(OP_PACKAGE_NAME)
- repository.unsetPrompt()
+ repository.unsetPrompt(REQUEST_ID)
assertThat(repository.promptInfo.value).isNull()
assertThat(repository.userId.value).isNull()
assertThat(repository.challenge.value).isNull()
assertThat(repository.opPackageName.value).isNull()
}
+
+ @Test
+ fun setsAndUnsetsPrompt_whenRequestIdDoesNotMatch() =
+ testScope.runTest {
+ val kind = PromptKind.Pin
+ val promptInfo = PromptInfo()
+
+ repository.setPrompt(promptInfo, USER_ID, REQUEST_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
+
+ assertThat(repository.promptKind.value).isEqualTo(kind)
+ assertThat(repository.userId.value).isEqualTo(USER_ID)
+ assertThat(repository.challenge.value).isEqualTo(CHALLENGE)
+ assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
+ assertThat(repository.opPackageName.value).isEqualTo(OP_PACKAGE_NAME)
+
+ repository.unsetPrompt(WRONG_REQUEST_ID)
+
+ assertThat(repository.promptInfo.value).isNotNull()
+ assertThat(repository.userId.value).isNotNull()
+ assertThat(repository.challenge.value).isNotNull()
+ assertThat(repository.opPackageName.value).isNotNull()
+ }
}
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 8695c01..c4d0d23 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
@@ -33,6 +33,7 @@
import org.mockito.junit.MockitoJUnit
private const val USER_ID = 22
+private const val REQUEST_ID = 22L
private const val OPERATION_ID = 100L
private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -112,6 +113,7 @@
},
kind = PromptKind.Pin,
userId = USER_ID,
+ requestId = REQUEST_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
)
@@ -137,6 +139,7 @@
},
kind = PromptKind.Pin,
userId = USER_ID,
+ requestId = REQUEST_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
)
@@ -165,6 +168,7 @@
},
kind = PromptKind.Pin,
userId = USER_ID,
+ requestId = REQUEST_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
)
@@ -198,6 +202,7 @@
},
kind = kind,
userId = USER_ID,
+ requestId = REQUEST_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
)
@@ -223,7 +228,7 @@
assertThat(pattern.stealthMode).isEqualTo(isStealth)
}
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
assertThat(prompt).isNull()
}
@@ -346,12 +351,14 @@
promptInfo: PromptInfo,
kind: PromptKind,
userId: Int,
+ requestId: Long,
challenge: Long,
opPackageName: String,
) {
biometricPromptRepository.setPrompt(
promptInfo,
userId,
+ requestId,
challenge,
kind,
opPackageName,
@@ -359,8 +366,8 @@
}
/** Unset the current authentication request. */
- private fun PromptCredentialInteractor.resetPrompt() {
- biometricPromptRepository.unsetPrompt()
+ private fun PromptCredentialInteractor.resetPrompt(requestId: Long) {
+ biometricPromptRepository.unsetPrompt(requestId)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 4068404..3102a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -59,6 +59,7 @@
private const val NEGATIVE_TEXT = "escape"
private const val USER_ID = 8
+ private const val REQUEST_ID = 8L
private const val CHALLENGE = 999L
private const val OP_PACKAGE_NAME = "biometric.testapp"
private val componentNameOverriddenForConfirmDeviceCredentialActivity =
@@ -150,6 +151,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -179,7 +181,7 @@
}
assertThat(isConfirmationRequired).isEqualTo(confirmationRequired)
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -206,6 +208,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -214,7 +217,7 @@
assertThat(promptKind?.isBiometric()).isTrue()
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -230,6 +233,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -238,7 +242,7 @@
assertThat(promptKind).isEqualTo(PromptKind.Password)
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -258,6 +262,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -266,7 +271,7 @@
assertThat(promptKind).isEqualTo(PromptKind.Password)
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -290,6 +295,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -298,7 +304,7 @@
assertThat(promptKind).isEqualTo(PromptKind.Password)
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -319,6 +325,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
@@ -327,7 +334,7 @@
assertThat(promptKind?.isBiometric()).isTrue()
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
@@ -355,6 +362,7 @@
interactor.setPrompt(
info,
USER_ID,
+ REQUEST_ID,
BiometricModalities(),
CHALLENGE,
OP_PACKAGE_NAME,
@@ -365,7 +373,7 @@
assertThat(currentPrompt).isNull()
assertThat(credentialKind).isEqualTo(PromptKind.None)
- interactor.resetPrompt()
+ interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
index 3245020..9e804c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
@@ -22,6 +22,7 @@
import org.junit.runners.JUnit4
private const val USER_ID = 9
+private const val REQUEST_ID = 9L
private const val OPERATION_ID = 10L
@OptIn(ExperimentalCoroutinesApi::class)
@@ -171,7 +172,7 @@
) =
runTest(dispatcher) {
init()
- promptRepository.setPrompt(promptInfo(), USER_ID, OPERATION_ID, kind)
+ promptRepository.setPrompt(promptInfo(), USER_ID, REQUEST_ID, OPERATION_ID, kind)
block()
}
}
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 fa78f0c..c177511 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
@@ -96,6 +96,7 @@
import org.mockito.junit.MockitoJUnit
private const val USER_ID = 4
+private const val REQUEST_ID = 4L
private const val CHALLENGE = 2L
private const val DELAY = 1000L
private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -382,25 +383,11 @@
}
if (testCase.isFaceOnly) {
- val shouldRepeatAnimation by collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
- val lastPulseLightToDark by collectLastValue(iconViewModel.lastPulseLightToDark)
-
- val expectedIconAsset =
- if (shouldPulseAnimation!!) {
- if (lastPulseLightToDark!!) {
- R.drawable.face_dialog_pulse_dark_to_light
- } else {
- R.drawable.face_dialog_pulse_light_to_dark
- }
- } else {
- R.drawable.face_dialog_pulse_dark_to_light
- }
+ val expectedIconAsset = R.raw.face_dialog_authenticating
assertThat(iconAsset).isEqualTo(expectedIconAsset)
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_authenticating)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(true)
}
if (testCase.isCoex) {
@@ -422,26 +409,11 @@
}
} else {
// implicit flow
- val shouldRepeatAnimation by
- collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
- val lastPulseLightToDark by collectLastValue(iconViewModel.lastPulseLightToDark)
-
- val expectedIconAsset =
- if (shouldPulseAnimation!!) {
- if (lastPulseLightToDark!!) {
- R.drawable.face_dialog_pulse_dark_to_light
- } else {
- R.drawable.face_dialog_pulse_light_to_dark
- }
- } else {
- R.drawable.face_dialog_pulse_dark_to_light
- }
+ val expectedIconAsset = R.raw.face_dialog_authenticating
assertThat(iconAsset).isEqualTo(expectedIconAsset)
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_authenticating)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(true)
}
}
}
@@ -531,14 +503,9 @@
}
if (testCase.isFaceOnly) {
- val shouldRepeatAnimation by collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
-
- assertThat(shouldPulseAnimation!!).isEqualTo(false)
assertThat(iconAsset).isEqualTo(R.drawable.face_dialog_dark_to_error)
assertThat(iconContentDescriptionId).isEqualTo(R.string.keyguard_face_failed)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(false)
// Clear error, go to idle
errorJob.join()
@@ -547,7 +514,6 @@
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_idle)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(false)
}
if (testCase.isCoex) {
@@ -630,15 +596,10 @@
// If co-ex, using implicit flow (explicit flow always requires confirmation)
if (testCase.isFaceOnly || testCase.isCoex) {
- val shouldRepeatAnimation by collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
-
- assertThat(shouldPulseAnimation!!).isEqualTo(false)
assertThat(iconAsset).isEqualTo(R.drawable.face_dialog_dark_to_checkmark)
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_authenticated)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(false)
}
}
}
@@ -660,15 +621,10 @@
)
if (testCase.isFaceOnly) {
- val shouldRepeatAnimation by collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
-
- assertThat(shouldPulseAnimation!!).isEqualTo(false)
assertThat(iconAsset).isEqualTo(R.drawable.face_dialog_wink_from_dark)
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_authenticated)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(false)
}
// explicit flow because confirmation requested
@@ -710,15 +666,10 @@
viewModel.confirmAuthenticated()
if (testCase.isFaceOnly) {
- val shouldRepeatAnimation by collectLastValue(iconViewModel.shouldRepeatAnimation)
- val shouldPulseAnimation by collectLastValue(iconViewModel.shouldPulseAnimation)
-
- assertThat(shouldPulseAnimation!!).isEqualTo(false)
assertThat(iconAsset).isEqualTo(R.drawable.face_dialog_dark_to_checkmark)
assertThat(iconContentDescriptionId)
.isEqualTo(R.string.biometric_dialog_face_icon_description_confirmed)
assertThat(shouldAnimateIconView).isEqualTo(true)
- assertThat(shouldRepeatAnimation).isEqualTo(false)
}
// explicit flow because confirmation requested
@@ -1457,7 +1408,7 @@
whenever(activityTaskManager.getTasks(1)).thenReturn(listOf(runningTaskInfo))
selector =
PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
- selector.resetPrompt()
+ selector.resetPrompt(REQUEST_ID)
viewModel =
PromptViewModel(
@@ -1688,6 +1639,7 @@
setPrompt(
info,
USER_ID,
+ REQUEST_ID,
BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face),
CHALLENGE,
packageName,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerContentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerContentTest.kt
new file mode 100644
index 0000000..9a36678
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerContentTest.kt
@@ -0,0 +1,116 @@
+/*
+ * 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.composable
+
+import android.app.AlertDialog
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.doubleClick
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.performTouchInput
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.android.compose.theme.PlatformTheme
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.ui.BouncerDialogFactory
+import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
+import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.motion.createSysUiComposeMotionTestRule
+import com.android.systemui.scene.domain.interactor.sceneContainerStartable
+import com.android.systemui.testKosmos
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeFeatureCaptures.alpha
+import platform.test.motion.compose.ComposeFeatureCaptures.positionInRoot
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.feature
+import platform.test.motion.compose.motionTestValueOfNode
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.compose.runTest
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays.FoldableInner
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class BouncerContentTest : SysuiTestCase() {
+ private val deviceSpec = DeviceEmulationSpec(FoldableInner)
+ private val kosmos = testKosmos()
+
+ @get:Rule val motionTestRule = createSysUiComposeMotionTestRule(kosmos, deviceSpec)
+
+ private val bouncerDialogFactory =
+ object : BouncerDialogFactory {
+ override fun invoke(): AlertDialog {
+ throw AssertionError()
+ }
+ }
+
+ @Before
+ fun setUp() {
+ kosmos.sceneContainerStartable.start()
+ kosmos.fakeFeatureFlagsClassic.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ }
+
+ @Composable
+ private fun BouncerContentUnderTest() {
+ PlatformTheme {
+ BouncerContent(
+ viewModel = kosmos.bouncerViewModel,
+ layout = BouncerSceneLayout.BESIDE_USER_SWITCHER,
+ modifier = Modifier.fillMaxSize().testTag("BouncerContent"),
+ dialogFactory = bouncerDialogFactory
+ )
+ }
+ }
+
+ @Test
+ fun doubleClick_swapSide() =
+ motionTestRule.runTest {
+ val motion =
+ recordMotion(
+ content = { BouncerContentUnderTest() },
+ ComposeRecordingSpec(
+ MotionControl {
+ onNode(hasTestTag("BouncerContent")).performTouchInput {
+ doubleClick(position = centerLeft)
+ }
+
+ awaitCondition {
+ motionTestValueOfNode(BouncerMotionTestKeys.swapAnimationEnd)
+ }
+ }
+ ) {
+ feature(hasTestTag("UserSwitcher"), positionInRoot, "userSwitcher_pos")
+ feature(hasTestTag("UserSwitcher"), alpha, "userSwitcher_alpha")
+ feature(hasTestTag("FoldAware"), positionInRoot, "foldAware_pos")
+ feature(hasTestTag("FoldAware"), alpha, "foldAware_alpha")
+ }
+ )
+
+ assertThat(motion).timeSeriesMatchesGolden()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/PatternBouncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/PatternBouncerTest.kt
new file mode 100644
index 0000000..4f6f98e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/PatternBouncerTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.composable
+
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
+import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.motion.createSysUiComposeMotionTestRule
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.takeWhile
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.feature
+import platform.test.motion.compose.motionTestValueOfNode
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.compose.runTest
+import platform.test.motion.golden.DataPointTypes
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class PatternBouncerTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+
+ @get:Rule val motionTestRule = createSysUiComposeMotionTestRule(kosmos)
+
+ private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
+ private val viewModel by lazy {
+ PatternBouncerViewModel(
+ applicationContext = context,
+ viewModelScope = kosmos.testScope.backgroundScope,
+ interactor = bouncerInteractor,
+ isInputEnabled = MutableStateFlow(true).asStateFlow(),
+ onIntentionalUserInput = {},
+ )
+ }
+
+ @Composable
+ private fun PatternBouncerUnderTest() {
+ PatternBouncer(viewModel, centerDotsVertically = true, modifier = Modifier.size(400.dp))
+ }
+
+ @Test
+ fun entryAnimation() =
+ motionTestRule.runTest {
+ val motion =
+ recordMotion(
+ content = { play -> if (play) PatternBouncerUnderTest() },
+ ComposeRecordingSpec.until(
+ recordBefore = false,
+ checkDone = { motionTestValueOfNode(MotionTestKeys.entryCompleted) }
+ ) {
+ feature(MotionTestKeys.dotAppearFadeIn, floatArray)
+ feature(MotionTestKeys.dotAppearMoveUp, floatArray)
+ }
+ )
+
+ assertThat(motion).timeSeriesMatchesGolden()
+ }
+
+ @Test
+ fun animateFailure() =
+ motionTestRule.runTest {
+ val failureAnimationMotionControl =
+ MotionControl(
+ delayReadyToPlay = {
+ // Skip entry animation.
+ awaitCondition { motionTestValueOfNode(MotionTestKeys.entryCompleted) }
+ },
+ delayRecording = {
+ // Trigger failure animation by calling onDragEnd without having recorded a
+ // pattern before.
+ viewModel.onDragEnd()
+ // Failure animation starts when animateFailure flips to true...
+ viewModel.animateFailure.takeWhile { !it }.collect {}
+ }
+ ) {
+ // ... and ends when the composable flips it back to false.
+ viewModel.animateFailure.takeWhile { it }.collect {}
+ }
+
+ val motion =
+ recordMotion(
+ content = { PatternBouncerUnderTest() },
+ ComposeRecordingSpec(failureAnimationMotionControl) {
+ feature(MotionTestKeys.dotScaling, floatArray)
+ }
+ )
+ assertThat(motion).timeSeriesMatchesGolden()
+ }
+
+ companion object {
+ val floatArray = DataPointTypes.listOf(DataPointTypes.float)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
index 617e310..85d6211 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
@@ -59,9 +59,7 @@
underTest = PackageUpdateMonitor(USER, PACKAGE, {}, bgHandler, context)
underTest.startMonitoring()
- // There are two receivers registered
- verify(context, times(1))
- .registerReceiverAsUser(any(), eq(USER), any(), eq(null), eq(bgHandler))
+
verify(packageManager).registerPackageMonitorCallback(any(), eq(USER.getIdentifier()))
// context will be used to get PackageManager, the test should clear invocations
// for next startMonitoring() assertion
@@ -83,7 +81,7 @@
clearInvocations(packageManager)
underTest.stopMonitoring()
- verify(context).unregisterReceiver(any())
+
verify(packageManager).unregisterPackageMonitorCallback(any())
// context will be used to get PackageManager, the test should clear invocations
// for next stopMonitoring() assertion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 53560d7..48a5df9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -25,16 +25,19 @@
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.KeyguardTransitionRunner
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -45,6 +48,8 @@
import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
@@ -372,6 +377,43 @@
assertThat(wtfHandler.failed).isTrue()
}
+ @Test
+ fun simulateRaceConditionIsProcessedInOrder() =
+ testScope.runTest {
+ val ktr = KeyguardTransitionRepositoryImpl(kosmos.testDispatcher)
+ val steps by collectValues(ktr.transitions.dropWhile { step -> step.from == OFF })
+
+ // Add a delay to the first transition in order to attempt to have the second transition
+ // be processed first
+ val info1 = TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, animator = null)
+ launch {
+ ktr.forceDelayForRaceConditionTest = true
+ ktr.startTransition(info1)
+ }
+ val info2 = TransitionInfo(OWNER_NAME, LOCKSCREEN, OCCLUDED, animator = null)
+ launch {
+ ktr.forceDelayForRaceConditionTest = false
+ ktr.startTransition(info2)
+ }
+
+ runCurrent()
+ assertThat(steps.isEmpty()).isTrue()
+
+ advanceTimeBy(60L)
+ assertThat(steps[0])
+ .isEqualTo(
+ TransitionStep(info1.from, info1.to, 0f, TransitionState.STARTED, OWNER_NAME)
+ )
+ assertThat(steps[1])
+ .isEqualTo(
+ TransitionStep(info1.from, info1.to, 0f, TransitionState.CANCELED, OWNER_NAME)
+ )
+ assertThat(steps[2])
+ .isEqualTo(
+ TransitionStep(info2.from, info2.to, 0f, TransitionState.STARTED, OWNER_NAME)
+ )
+ }
+
private fun listWithStep(
step: BigDecimal,
start: BigDecimal = BigDecimal.ZERO,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 00f94a5..fa3fe5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1669,7 +1669,9 @@
// THEN a transition from DOZING => OCCLUDED should occur
assertThat(transitionRepository)
.startedTransition(
- ownerName = "FromDozingTransitionInteractor",
+ ownerName =
+ "FromDozingTransitionInteractor" +
+ "(keyguardInteractor.onCameraLaunchDetected)",
from = KeyguardState.DOZING,
to = KeyguardState.OCCLUDED,
animatorAssertion = { it.isNotNull() },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index a77169e..2b8a644 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -20,8 +20,11 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -30,6 +33,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -38,6 +42,7 @@
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -727,42 +732,48 @@
@Test
@EnableSceneContainer
- fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() =
+ fun lockscreenVisibility() =
testScope.runTest {
- val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+ val isDeviceUnlocked by
+ collectLastValue(
+ kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+ )
+ assertThat(isDeviceUnlocked).isFalse()
- sceneTransitions.value = lsToGone
+ val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+ val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
assertThat(lockscreenVisibility).isTrue()
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
- assertThat(lockscreenVisibility).isFalse()
-
- sceneTransitions.value = goneToLs
- assertThat(lockscreenVisibility).isFalse()
-
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "")
+ assertThat(currentScene).isEqualTo(Scenes.Bouncer)
assertThat(lockscreenVisibility).isTrue()
- }
- @Test
- @EnableSceneContainer
- fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() =
- testScope.runTest {
- val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
-
- sceneTransitions.value = goneToLs
+ kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+ assertThat(isDeviceUnlocked).isTrue()
+ kosmos.sceneInteractor.changeScene(Scenes.Gone, "")
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
assertThat(lockscreenVisibility).isFalse()
- sceneTransitions.value = lsToGone
+ kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
assertThat(lockscreenVisibility).isFalse()
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+ kosmos.sceneInteractor.changeScene(Scenes.QuickSettings, "")
+ assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
assertThat(lockscreenVisibility).isFalse()
- sceneTransitions.value = goneToLs
+ kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+ assertThat(currentScene).isEqualTo(Scenes.Shade)
assertThat(lockscreenVisibility).isFalse()
- sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ kosmos.sceneInteractor.changeScene(Scenes.Gone, "")
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ assertThat(lockscreenVisibility).isFalse()
+
+ kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "")
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
assertThat(lockscreenVisibility).isTrue()
}
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 7856f9b..a89139b 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
@@ -196,7 +196,7 @@
verify(globalSettings)
.registerContentObserver(
eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
- settingsObserverCaptor.capture()
+ capture(settingsObserverCaptor)
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 9bb21f0..9616f610 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -128,6 +128,7 @@
mContext,
TEST_PACKAGE,
mContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
index 2e6388a..16b00c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -129,6 +129,7 @@
mContext,
TEST_PACKAGE,
mContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 4eb0038..45ae506 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -199,6 +199,7 @@
mSpyContext,
mPackageName,
mContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -292,6 +293,7 @@
mSpyContext,
null,
mContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -333,6 +335,7 @@
mSpyContext,
null,
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -588,6 +591,7 @@
mSpyContext,
"",
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -621,6 +625,7 @@
mSpyContext,
"",
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -667,6 +672,7 @@
mSpyContext,
null,
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -693,6 +699,7 @@
mSpyContext,
null,
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -972,6 +979,7 @@
mSpyContext,
null,
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
@@ -1174,6 +1182,7 @@
mSpyContext,
null,
mSpyContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
index 5dbfe47..1e8fbea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
@@ -64,7 +64,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, times(1))
- .createAndShow(eq(getContext().getPackageName()), eq(false), any(), any());
+ .createAndShow(eq(getContext().getPackageName()), eq(false), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -76,7 +76,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -87,7 +87,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -101,7 +101,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -115,7 +115,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, times(1))
.createAndShow(eq(getContext().getPackageName()), eq(true), any());
}
@@ -129,7 +129,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -142,7 +142,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -155,7 +155,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
@@ -166,7 +166,7 @@
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogManager, never())
- .createAndShow(any(), anyBoolean(), any(), any());
+ .createAndShow(any(), anyBoolean(), any(), any(), any());
verify(mMockMediaOutputBroadcastDialogManager, never())
.createAndShow(any(), anyBoolean(), any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index cdef964..92d0a72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -142,6 +142,7 @@
mContext,
TEST_PACKAGE,
mContext.getUser(),
+ /* token */ null,
mMediaSessionManager,
mLocalBluetoothManager,
mStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
deleted file mode 100644
index 85cc88d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.monet
-
-import android.testing.AndroidTestingRunner
-import android.util.Log
-import android.util.Pair
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.theme.DynamicColors
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
-import com.google.ux.material.libmonet.hct.Hct
-import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
-import java.io.File
-import java.io.FileWriter
-import java.io.StringWriter
-import javax.xml.parsers.DocumentBuilderFactory
-import javax.xml.transform.OutputKeys
-import javax.xml.transform.TransformerException
-import javax.xml.transform.TransformerFactory
-import javax.xml.transform.dom.DOMSource
-import javax.xml.transform.stream.StreamResult
-import kotlin.math.abs
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-
-private const val fileHeader =
- """
- ~ 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.
-"""
-
-private fun testName(name: String): String {
- return "Auto generated by: atest ColorSchemeTest#$name"
-}
-
-private const val commentRoles =
- "Colors used in Android system, from design system. These " +
- "values can be overlaid at runtime by OverlayManager RROs."
-
-private const val commentOverlay = "This value can be overlaid at runtime by OverlayManager RROs."
-
-private fun commentWhite(paletteName: String): String {
- return "Lightest shade of the $paletteName color used by the system. White. $commentOverlay"
-}
-
-private fun commentBlack(paletteName: String): String {
- return "Darkest shade of the $paletteName color used by the system. Black. $commentOverlay"
-}
-
-private fun commentShade(paletteName: String, tone: Int): String {
- return "Shade of the $paletteName system color at $tone% perceptual luminance (L* in L*a*b* " +
- "color space). $commentOverlay"
-}
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class ColorSchemeTest : SysuiTestCase() {
- private val defaultContrast = 0.0
- private val defaultIsDark = false
- private val defaultIsFidelity = false
-
- @Test
- fun generateThemeStyles() {
- val document = buildDoc<Any>()
-
- val themes = document.createElement("themes")
- document.appendWithBreak(themes)
-
- var hue = 0.0
- while (hue < 360) {
- val sourceColor = Hct.from(hue, 50.0, 50.0)
- val sourceColorHex = sourceColor.toInt().toRGBHex()
-
- val theme = document.createElement("theme")
- theme.setAttribute("color", sourceColorHex)
- themes.appendChild(theme)
-
- for (styleValue in Style.entries) {
- if (
- styleValue == Style.CLOCK ||
- styleValue == Style.CLOCK_VIBRANT ||
- styleValue == Style.CONTENT
- ) {
- continue
- }
-
- val style = document.createElement(styleValue.name.lowercase())
- val colorScheme = ColorScheme(sourceColor.toInt(), defaultIsDark, styleValue)
-
- style.appendChild(
- document.createTextNode(
- listOf(
- colorScheme.accent1,
- colorScheme.accent2,
- colorScheme.accent3,
- colorScheme.neutral1,
- colorScheme.neutral2
- )
- .flatMap { a -> listOf(*a.allShades.toTypedArray()) }
- .joinToString(",", transform = Int::toRGBHex)
- )
- )
- theme.appendChild(style)
- }
-
- hue += 60
- }
-
- saveFile(document, "current_themes.xml")
- }
-
- @Test
- fun generateDefaultValues() {
- val document = buildDoc<Any>()
-
- val resources = document.createElement("resources")
- document.appendWithBreak(resources)
-
- // shade colors
- val colorScheme = ColorScheme(GOOGLE_BLUE, defaultIsDark)
- arrayOf(
- Triple("accent1", "Primary", colorScheme.accent1),
- Triple("accent2", "Secondary", colorScheme.accent2),
- Triple("accent3", "Tertiary", colorScheme.accent3),
- Triple("neutral1", "Neutral", colorScheme.neutral1),
- Triple("neutral2", "Secondary Neutral", colorScheme.neutral2)
- )
- .forEach {
- val (paletteName, readable, palette) = it
- palette.allShadesMapped.entries.forEachIndexed { index, (shade, colorValue) ->
- val comment =
- when (index) {
- 0 -> commentWhite(readable)
- palette.allShadesMapped.entries.size - 1 -> commentBlack(readable)
- else -> commentShade(readable, abs(shade / 10 - 100))
- }
- resources.createColorEntry("system_${paletteName}_$shade", colorValue, comment)
- }
- }
-
- resources.appendWithBreak(document.createComment(commentRoles), 2)
-
- fun generateDynamic(pairs: List<Pair<String, DynamicColor>>) {
- arrayOf(false, true).forEach { isDark ->
- val suffix = if (isDark) "_dark" else "_light"
- val dynamicScheme =
- SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, defaultContrast)
- pairs.forEach {
- resources.createColorEntry(
- "system_${it.first}$suffix",
- it.second.getArgb(dynamicScheme)
- )
- }
- }
- }
-
- // dynamic colors
- generateDynamic(DynamicColors.allDynamicColorsMapped(defaultIsFidelity))
-
- // fixed colors
- val dynamicScheme =
- SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), defaultIsDark, defaultContrast)
- DynamicColors.getFixedColorsMapped(defaultIsFidelity).forEach {
- resources.createColorEntry("system_${it.first}", it.second.getArgb(dynamicScheme))
- }
-
- resources.appendWithBreak(document.createComment(commentRoles), 2)
-
- // custom colors
- generateDynamic(DynamicColors.getCustomColorsMapped(defaultIsFidelity))
-
- saveFile(document, "role_values.xml")
- }
-
- // Helper Functions
-
- private inline fun <reified T> buildDoc(): Document {
- val functionName = T::class.simpleName + ""
- val factory = DocumentBuilderFactory.newInstance()
- val builder = factory.newDocumentBuilder()
- val document = builder.newDocument()
-
- document.appendWithBreak(document.createComment(fileHeader))
- document.appendWithBreak(document.createComment(testName(functionName)))
-
- return document
- }
-
- private fun documentToString(document: Document): String {
- try {
- val transformerFactory = TransformerFactory.newInstance()
- val transformer = transformerFactory.newTransformer()
- transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "application/xml")
- transformer.setOutputProperty(OutputKeys.METHOD, "xml")
- transformer.setOutputProperty(OutputKeys.INDENT, "yes")
- transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4")
-
- val stringWriter = StringWriter()
- transformer.transform(DOMSource(document), StreamResult(stringWriter))
- return stringWriter.toString()
- } catch (e: TransformerException) {
- throw RuntimeException("Error transforming XML", e)
- }
- }
-
- private fun saveFile(document: Document, fileName: String) {
- val outPath = context.filesDir.path + "/" + fileName
- Log.d("ColorSchemeXml", "Artifact $fileName created")
- val writer = FileWriter(File(outPath))
- writer.write(documentToString(document))
- writer.close()
- }
-}
-
-private fun Element.createColorEntry(name: String, value: Int, comment: String? = null) {
- val doc = this.ownerDocument
-
- if (comment != null) {
- this.appendChild(doc.createComment(comment))
- }
-
- val color = doc.createElement("color")
- this.appendChild(color)
-
- color.setAttribute("name", name)
- color.appendChild(doc.createTextNode("#" + value.toRGBHex()))
-}
-
-private fun Node.appendWithBreak(child: Node, lineBreaks: Int = 1): Node {
- val doc = if (this is Document) this else this.ownerDocument
- val node = doc.createTextNode("\n".repeat(lineBreaks))
- this.appendChild(node)
- return this.appendChild(child)
-}
-
-private fun Int.toRGBHex(): String {
- return "%06X".format(0xFFFFFF and this)
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
new file mode 100644
index 0000000..e81e42b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.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.motion
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import org.junit.rules.RuleChain
+import platform.test.motion.MotionTestRule
+import platform.test.motion.compose.ComposeToolkit
+import platform.test.motion.testing.createGoldenPathManager
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.PathConfig
+import platform.test.screenshot.utils.compose.ComposeScreenshotTestRule
+
+/** Create a [MotionTestRule] for motion tests of Compose-based System UI. */
+fun createSysUiComposeMotionTestRule(
+ kosmos: Kosmos,
+ deviceEmulationSpec: DeviceEmulationSpec = DeviceEmulationSpec(Displays.Phone),
+ pathConfig: PathConfig = PathConfig(),
+): MotionTestRule<ComposeToolkit> {
+ val goldenPathManager =
+ createGoldenPathManager("frameworks/base/packages/SystemUI/tests/goldens", pathConfig)
+ val testScope = kosmos.testScope
+
+ val composeScreenshotTestRule =
+ ComposeScreenshotTestRule(deviceEmulationSpec, goldenPathManager)
+
+ return MotionTestRule(
+ ComposeToolkit(composeScreenshotTestRule.composeRule, testScope),
+ goldenPathManager,
+ bitmapDiffer = composeScreenshotTestRule,
+ extraRules = RuleChain.outerRule(composeScreenshotTestRule)
+ )
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
index d15cfbf..2da4b72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
@@ -23,8 +23,8 @@
import com.android.systemui.qs.panels.data.repository.IconTilesRepository
import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
import com.android.systemui.qs.panels.data.repository.iconTilesRepository
-import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -45,8 +45,6 @@
@RunWith(AndroidTestingRunner::class)
class GridConsistencyInteractorTest : SysuiTestCase() {
- data object TestGridLayoutType : GridLayoutType
-
private val iconOnlyTiles =
MutableStateFlow(
setOf(
@@ -65,17 +63,13 @@
override val iconTilesSpecs: StateFlow<Set<TileSpec>>
get() = iconOnlyTiles.asStateFlow()
}
- gridConsistencyInteractorsMap =
- mapOf(
- Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor),
- Pair(TestGridLayoutType, noopGridConsistencyInteractor)
- )
}
private val underTest = with(kosmos) { gridConsistencyInteractor }
@Before
fun setUp() {
+ // Mostly testing InfiniteGridConsistencyInteractor because it reorders tiles
with(kosmos) { gridLayoutTypeRepository.setLayout(InfiniteGridLayoutType) }
underTest.start()
}
@@ -86,7 +80,7 @@
with(kosmos) {
testScope.runTest {
// Using the no-op grid consistency interactor
- gridLayoutTypeRepository.setLayout(TestGridLayoutType)
+ gridLayoutTypeRepository.setLayout(PartitionedGridLayoutType)
// Setting an invalid layout with holes
// [ Large A ] [ sa ]
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
new file mode 100644
index 0000000..b77a15b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
@@ -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.systemui.screenrecord.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+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.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class ScreenRecordRepositoryTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val testScope = kosmos.testScope
+ private val recordingController = mock<RecordingController>()
+
+ private val underTest =
+ ScreenRecordRepositoryImpl(
+ bgCoroutineContext = testScope.testScheduler,
+ recordingController = recordingController,
+ )
+
+ private val isRecording = ScreenRecordModel.Recording
+ private val isDoingNothing = ScreenRecordModel.DoingNothing
+ private val isStarting0 = ScreenRecordModel.Starting(0)
+
+ @Test
+ fun dataMatchesController() =
+ testScope.runTest {
+ whenever(recordingController.isRecording).thenReturn(false)
+ whenever(recordingController.isStarting).thenReturn(false)
+
+ val callbackCaptor = argumentCaptor<RecordingController.RecordingStateChangeCallback>()
+
+ val lastModel by collectLastValue(underTest.screenRecordState)
+ runCurrent()
+
+ verify(recordingController).addCallback(callbackCaptor.capture())
+ val callback = callbackCaptor.firstValue
+
+ assertThat(lastModel).isEqualTo(isDoingNothing)
+
+ val expectedModelStartingIn1 = ScreenRecordModel.Starting(1)
+ callback.onCountdown(1)
+ assertThat(lastModel).isEqualTo(expectedModelStartingIn1)
+
+ val expectedModelStartingIn0 = isStarting0
+ callback.onCountdown(0)
+ assertThat(lastModel).isEqualTo(expectedModelStartingIn0)
+
+ callback.onCountdownEnd()
+ assertThat(lastModel).isEqualTo(isDoingNothing)
+
+ callback.onRecordingStart()
+ assertThat(lastModel).isEqualTo(isRecording)
+
+ callback.onRecordingEnd()
+ assertThat(lastModel).isEqualTo(isDoingNothing)
+ }
+
+ @Test
+ fun data_whenRecording_matchesController() =
+ testScope.runTest {
+ whenever(recordingController.isRecording).thenReturn(true)
+ whenever(recordingController.isStarting).thenReturn(false)
+
+ val lastModel by collectLastValue(underTest.screenRecordState)
+ runCurrent()
+
+ assertThat(lastModel).isEqualTo(isRecording)
+ }
+
+ @Test
+ fun data_whenStarting_matchesController() =
+ testScope.runTest {
+ whenever(recordingController.isRecording).thenReturn(false)
+ whenever(recordingController.isStarting).thenReturn(true)
+
+ val lastModel by collectLastValue(underTest.screenRecordState)
+ runCurrent()
+
+ assertThat(lastModel).isEqualTo(isStarting0)
+ }
+
+ @Test
+ fun data_whenRecordingAndStarting_matchesControllerRecording() =
+ testScope.runTest {
+ whenever(recordingController.isRecording).thenReturn(true)
+ whenever(recordingController.isStarting).thenReturn(true)
+
+ val lastModel by collectLastValue(underTest.screenRecordState)
+ runCurrent()
+
+ assertThat(lastModel).isEqualTo(isRecording)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
new file mode 100644
index 0000000..2e8498a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.testing.AndroidTestingRunner
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.screenshot.data.repository.profileTypeRepository
+import com.android.systemui.screenshot.policy.TestUserIds
+import com.android.systemui.screenshot.resources.Messages
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@RunWith(AndroidTestingRunner::class)
+class AnnouncementResolverTest {
+ private val kosmos = Kosmos()
+
+ private val screenshotMessage = "Saving screenshot"
+ private val workMessage = "Saving to work profile"
+ private val privateMessage = "Saving to private profile"
+
+ private val messages =
+ mock(Messages::class.java).also {
+ whenever(it.savingScreenshotAnnouncement).thenReturn(screenshotMessage)
+ whenever(it.savingToWorkProfileAnnouncement).thenReturn(workMessage)
+ whenever(it.savingToPrivateProfileAnnouncement).thenReturn(privateMessage)
+ }
+
+ private val announcementResolver =
+ AnnouncementResolver(
+ messages,
+ kosmos.profileTypeRepository,
+ TestScope(UnconfinedTestDispatcher())
+ )
+
+ @Test
+ fun personalProfile() = runTest {
+ assertThat(announcementResolver.getScreenshotAnnouncement(TestUserIds.PERSONAL))
+ .isEqualTo(screenshotMessage)
+ }
+
+ @Test
+ fun workProfile() = runTest {
+ assertThat(announcementResolver.getScreenshotAnnouncement(TestUserIds.WORK))
+ .isEqualTo(workMessage)
+ }
+
+ @Test
+ fun privateProfile() = runTest {
+ assertThat(announcementResolver.getScreenshotAnnouncement(TestUserIds.PRIVATE))
+ .isEqualTo(privateMessage)
+ }
+}
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 8e32907..041adea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -24,6 +24,7 @@
import static com.google.common.truth.Truth.assertThat;
import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.SharedFlowKt.MutableSharedFlow;
import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import static org.mockito.ArgumentMatchers.any;
@@ -40,6 +41,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.animation.Animator;
import android.annotation.IdRes;
import android.content.ContentResolver;
import android.content.res.Configuration;
@@ -203,16 +205,20 @@
import dagger.Lazy;
import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.channels.BufferOverflow;
import kotlinx.coroutines.test.TestScope;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.mockito.stubbing.Answer;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -347,7 +353,6 @@
@Mock private KeyguardClockPositionAlgorithm mKeyguardClockPositionAlgorithm;
@Mock private NaturalScrollingSettingObserver mNaturalScrollingSettingObserver;
@Mock private LargeScreenHeaderHelper mLargeScreenHeaderHelper;
-
protected final int mMaxUdfpsBurnInOffsetY = 5;
protected FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -362,8 +367,11 @@
protected PowerInteractor mPowerInteractor;
protected FakeHeadsUpNotificationRepository mFakeHeadsUpNotificationRepository =
new FakeHeadsUpNotificationRepository();
- protected HeadsUpNotificationInteractor mHeadsUpNotificationInteractor =
- new HeadsUpNotificationInteractor(mFakeHeadsUpNotificationRepository);
+ protected NotificationsKeyguardViewStateRepository mNotificationsKeyguardViewStateRepository =
+ new NotificationsKeyguardViewStateRepository();
+ protected NotificationsKeyguardInteractor mNotificationsKeyguardInteractor =
+ new NotificationsKeyguardInteractor(mNotificationsKeyguardViewStateRepository);
+ protected HeadsUpNotificationInteractor mHeadsUpNotificationInteractor;
protected NotificationPanelViewController.TouchHandler mTouchHandler;
protected ConfigurationController mConfigurationController;
protected SysuiStatusBarStateController mStatusBarStateController;
@@ -387,9 +395,11 @@
protected FragmentHostManager.FragmentListener mFragmentListener;
+ @Rule(order = 200)
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
mFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false);
mFeatureFlags.set(Flags.QS_USER_DETAIL_SHORTCUT, false);
@@ -411,12 +421,15 @@
mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
MutableStateFlow(false));
+ when(mKeyguardTransitionInteractor.isInTransition(any(), any()))
+ .thenReturn(emptyFlow());
+ when(mKeyguardTransitionInteractor.getCurrentKeyguardState()).thenReturn(
+ MutableSharedFlow(0, 0, BufferOverflow.SUSPEND));
+ when(mDeviceEntryFaceAuthInteractor.isBypassEnabled()).thenReturn(MutableStateFlow(false));
DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
mock(DeviceEntryUdfpsInteractor.class);
when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
- when(mKeyguardTransitionInteractor.isInTransitionToState(any())).thenReturn(emptyFlow());
-
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
mKosmos.getDeviceProvisioningInteractor(),
@@ -664,6 +677,11 @@
when(mView.requireViewById(R.id.keyguard_long_press))
.thenReturn(mock(LongPressHandlingView.class));
+ mHeadsUpNotificationInteractor =
+ new HeadsUpNotificationInteractor(mFakeHeadsUpNotificationRepository,
+ mDeviceEntryFaceAuthInteractor, mKeyguardTransitionInteractor,
+ mNotificationsKeyguardInteractor, mShadeInteractor);
+
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
mMainHandler,
@@ -761,6 +779,9 @@
@Override
public void onOpenStarted() {}
});
+ // Create a set to which the class will add all animators used, so that we can
+ // verify that they are all stopped.
+ mNotificationPanelViewController.mTestSetOfAnimatorsUsed = new HashSet<>();
ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
verify(mView, atLeast(1)).addOnAttachStateChangeListener(
@@ -822,13 +843,20 @@
@After
public void tearDown() {
+ List<Animator> leakedAnimators = null;
if (mNotificationPanelViewController != null) {
mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel();
mNotificationPanelViewController.cancelHeightAnimator();
+ leakedAnimators = mNotificationPanelViewController.mTestSetOfAnimatorsUsed.stream()
+ .filter(Animator::isRunning).toList();
+ mNotificationPanelViewController.mTestSetOfAnimatorsUsed.forEach(Animator::cancel);
}
if (mMainHandler != null) {
mMainHandler.removeCallbacksAndMessages(null);
}
+ if (leakedAnimators != null) {
+ assertThat(leakedAnimators).isEmpty();
+ }
}
protected void setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index e1cdda4..6536405 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -705,6 +705,7 @@
}
@Test
+ @Ignore("b/341163515 - fails to clean up animators correctly")
public void testSwipeWhileLocked_notifiesKeyguardState() {
mStatusBarStateController.setState(KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
index 6631d29..d47bd47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
@@ -79,10 +79,9 @@
verify(mView, atLeastOnce()).addView(viewCaptor.capture(), anyInt())
val userSwitcherStub =
- CollectionUtils.find(
- viewCaptor.getAllValues(),
- { view -> view.getId() == R.id.keyguard_user_switcher_stub }
- )
+ CollectionUtils.find(viewCaptor.allValues) { view ->
+ view.id == R.id.keyguard_user_switcher_stub
+ }
assertThat(userSwitcherStub).isNotNull()
assertThat(userSwitcherStub).isInstanceOf(ViewStub::class.java)
}
@@ -251,7 +250,7 @@
// WHEN a pinned heads up is present
mFakeHeadsUpNotificationRepository.setNotifications(
- fakeHeadsUpRowRepository("key", isPinned = true)
+ FakeHeadsUpRowRepository("key", isPinned = true)
)
}
advanceUntilIdle()
@@ -274,9 +273,4 @@
// THEN the panel should be visible
assertThat(mNotificationPanelViewController.isExpanded).isTrue()
}
-
- 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/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
index 2bd0d79..fe066ca2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
@@ -32,6 +32,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static java.util.Collections.emptySet;
+
import android.app.AlarmManager;
import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
@@ -62,6 +64,7 @@
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
@@ -81,6 +84,8 @@
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLockFake;
+import kotlinx.coroutines.flow.StateFlow;
+
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
@@ -143,6 +148,8 @@
@Mock
protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock
+ protected BiometricMessageInteractor mBiometricMessageInteractor;
+ @Mock
protected ScreenLifecycle mScreenLifecycle;
@Mock
protected AuthController mAuthController;
@@ -226,6 +233,8 @@
when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
.thenReturn(mDisclosureWithOrganization);
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
+ when(mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow())
+ .thenReturn(mock(StateFlow.class));
when(mFaceHelpMessageDeferralFactory.create()).thenReturn(mFaceHelpMessageDeferral);
@@ -269,10 +278,12 @@
mock(BouncerMessageInteractor.class),
mFlags,
mIndicationHelper,
- KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor()
+ KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor(),
+ mBiometricMessageInteractor
);
mController.init();
mController.setIndicationArea(mIndicationArea);
+ mController.mCoExAcquisitionMsgIdsToShowCallback.accept(emptySet());
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 995b538..cfe9e2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -89,7 +89,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
@Test
public void afterFaceLockout_skipShowingFaceNotRecognized() {
@@ -131,14 +131,11 @@
@Test
public void onAlignmentStateChanged_showsSlowChargingIndication() {
- mInstrumentation.runOnMainSync(() -> {
- createController();
- verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
- mController.setVisible(true);
+ createController();
+ verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+ mController.setVisible(true);
- mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
- });
- mInstrumentation.waitForIdleSync();
+ mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
mTestableLooper.processAllMessages();
verifyIndicationMessage(INDICATION_TYPE_ALIGNMENT,
@@ -149,14 +146,11 @@
@Test
public void onAlignmentStateChanged_showsNotChargingIndication() {
- mInstrumentation.runOnMainSync(() -> {
- createController();
- verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
- mController.setVisible(true);
+ createController();
+ verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+ mController.setVisible(true);
- mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
- });
- mInstrumentation.waitForIdleSync();
+ mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
mTestableLooper.processAllMessages();
verifyIndicationMessage(INDICATION_TYPE_ALIGNMENT,
@@ -168,15 +162,12 @@
@FlakyTest(bugId = 279944472)
@Test
public void onAlignmentStateChanged_whileDozing_showsSlowChargingIndication() {
- mInstrumentation.runOnMainSync(() -> {
- createController();
- verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
- mController.setVisible(true);
- mStatusBarStateListener.onDozingChanged(true);
+ createController();
+ verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+ mController.setVisible(true);
+ mStatusBarStateListener.onDozingChanged(true);
- mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
- });
- mInstrumentation.waitForIdleSync();
+ mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
mTestableLooper.processAllMessages();
assertThat(mTextView.getText()).isEqualTo(
@@ -187,15 +178,12 @@
@Test
public void onAlignmentStateChanged_whileDozing_showsNotChargingIndication() {
- mInstrumentation.runOnMainSync(() -> {
- createController();
- verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
- mController.setVisible(true);
- mStatusBarStateListener.onDozingChanged(true);
+ createController();
+ verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+ mController.setVisible(true);
+ mStatusBarStateListener.onDozingChanged(true);
- mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
- });
- mInstrumentation.waitForIdleSync();
+ mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
mTestableLooper.processAllMessages();
assertThat(mTextView.getText()).isEqualTo(
@@ -642,6 +630,12 @@
@Test
public void sendFaceHelpMessages_fingerprintEnrolled() {
createController();
+ mController.mCoExAcquisitionMsgIdsToShowCallback.accept(
+ Set.of(
+ BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED,
+ BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED
+ )
+ );
// GIVEN unlocking with fingerprint is possible and allowed
fingerprintUnlockIsPossibleAndAllowed();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
new file mode 100644
index 0000000..fa2b343
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.chips.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class OngoingActivityChipsViewModelTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos()
+ private val underTest = kosmos.ongoingActivityChipsViewModel
+
+ @Test
+ fun chip_allHidden_hidden() =
+ kosmos.testScope.runTest {
+ kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+ kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden)
+ }
+
+ @Test
+ fun chip_screenRecordShow_restHidden_screenRecordShown() =
+ kosmos.testScope.runTest {
+ val screenRecordChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+ startTimeMs = 500L,
+ ) {}
+ kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+ kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(screenRecordChip)
+ }
+
+ @Test
+ fun chip_screenRecordShowAndCallShow_screenRecordShown() =
+ kosmos.testScope.runTest {
+ val screenRecordChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+ startTimeMs = 500L,
+ ) {}
+ kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ kosmos.callChipInteractor.chip.value = callChip
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(screenRecordChip)
+ }
+
+ @Test
+ fun chip_screenRecordHideAndCallShown_callShown() =
+ kosmos.testScope.runTest {
+ kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ kosmos.callChipInteractor.chip.value = callChip
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(callChip)
+ }
+
+ @Test
+ fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
+ kosmos.testScope.runTest {
+ // Start with just the lower priority call chip
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ kosmos.callChipInteractor.chip.value = callChip
+ kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(callChip)
+
+ // WHEN the higher priority screen record chip is added
+ val screenRecordChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+ startTimeMs = 500L,
+ ) {}
+ kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+ // THEN the higher priority screen record chip is used
+ assertThat(latest).isEqualTo(screenRecordChip)
+ }
+
+ @Test
+ fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
+ kosmos.testScope.runTest {
+ // Start with both the higher priority screen record chip and lower priority call chip
+ val screenRecordChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+ startTimeMs = 500L,
+ ) {}
+ kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ kosmos.callChipInteractor.chip.value = callChip
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertThat(latest).isEqualTo(screenRecordChip)
+
+ // WHEN the higher priority screen record is removed
+ kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+ // THEN the lower priority call is used
+ assertThat(latest).isEqualTo(callChip)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index 8e8a351..9e733be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification
+import android.platform.test.annotations.DisableFlags
import android.provider.DeviceConfig
import android.provider.Settings
@@ -25,6 +26,7 @@
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.Utils
import com.android.systemui.util.mockito.any
@@ -41,6 +43,7 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
+@DisableFlags(PriorityPeopleSection.FLAG_NAME) // this class has no logic with the flag enabled
class NotificationSectionsFeatureManagerTest : SysuiTestCase() {
var manager: NotificationSectionsFeatureManager? = null
val proxyFake = DeviceConfigProxyFake()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index 1870194..eeb51a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -16,9 +16,11 @@
package com.android.systemui.statusbar.notification.interruption
+import android.Manifest.permission
import android.app.Notification.CATEGORY_EVENT
import android.app.Notification.CATEGORY_REMINDER
import android.app.NotificationManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,6 +30,8 @@
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.`when`
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -51,7 +55,8 @@
uiEventLogger,
userTracker,
avalancheProvider,
- systemSettings
+ systemSettings,
+ packageManager
)
}
@@ -83,14 +88,18 @@
fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isConversation = true
- isImportantConversation = false
- whenMs = whenAgo(5)
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(5)
+ }
+ )
}
}
@@ -98,14 +107,18 @@
fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldNotHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_DEFAULT
- isConversation = true
- isImportantConversation = false
- whenMs = whenAgo(15)
- })
+ assertShouldNotHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_DEFAULT
+ isConversation = true
+ isImportantConversation = false
+ whenMs = whenAgo(15)
+ }
+ )
}
}
@@ -113,12 +126,16 @@
fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isImportantConversation = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isImportantConversation = true
+ }
+ )
}
}
@@ -126,12 +143,16 @@
fun testAvalancheFilter_duringAvalanche_allowCall() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isCall = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isCall = true
+ }
+ )
}
}
@@ -139,12 +160,16 @@
fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- category = CATEGORY_REMINDER
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_REMINDER
+ }
+ )
}
}
@@ -152,12 +177,16 @@
fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- category = CATEGORY_EVENT
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ category = CATEGORY_EVENT
+ }
+ )
}
}
@@ -165,7 +194,9 @@
fun testAvalancheFilter_duringAvalanche_allowFsi() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
assertFsiNotSuppressed()
}
}
@@ -174,16 +205,44 @@
fun testAvalancheFilter_duringAvalanche_allowColorized() {
avalancheProvider.startTime = whenAgo(10)
- withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
ensurePeekState()
- assertShouldHeadsUp(buildEntry {
- importance = NotificationManager.IMPORTANCE_HIGH
- isColorized = true
- })
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ isColorized = true
+ }
+ )
}
}
@Test
+ fun testAvalancheFilter_duringAvalanche_allowEmergency() {
+ avalancheProvider.startTime = whenAgo(10)
+
+ `when`(
+ packageManager.checkPermission(
+ org.mockito.Mockito.eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+ anyString()
+ )
+ ).thenReturn(PERMISSION_GRANTED)
+
+ withFilter(
+ AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+ ) {
+ ensurePeekState()
+ assertShouldHeadsUp(
+ buildEntry {
+ importance = NotificationManager.IMPORTANCE_HIGH
+ }
+ )
+ }
+ }
+
+
+ @Test
fun testPeekCondition_suppressesOnlyPeek() {
withCondition(TestCondition(types = setOf(PEEK)) { true }) {
assertPeekSuppressed()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 3b979a7..71e7dc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -42,6 +42,7 @@
import android.app.PendingIntent.FLAG_MUTABLE
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.graphics.drawable.Icon
import android.hardware.display.FakeAmbientDisplayConfiguration
@@ -129,6 +130,7 @@
protected val userTracker = FakeUserTracker()
protected val avalancheProvider: AvalancheProvider = mock()
lateinit var systemSettings: SystemSettings
+ protected val packageManager: PackageManager = mock()
protected abstract val provider: VisualInterruptionDecisionProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
index 60aaa64..61c008b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
@@ -15,11 +15,11 @@
*/
package com.android.systemui.statusbar.notification.interruption
+import android.content.pm.PackageManager
import android.hardware.display.AmbientDisplayConfiguration
import android.os.Handler
import android.os.PowerManager
import com.android.internal.logging.UiEventLogger
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
@@ -53,7 +53,8 @@
uiEventLogger: UiEventLogger,
userTracker: UserTracker,
avalancheProvider: AvalancheProvider,
- systemSettings: SystemSettings
+ systemSettings: SystemSettings,
+ packageManager: PackageManager,
): VisualInterruptionDecisionProvider {
return if (VisualInterruptionRefactor.isEnabled) {
VisualInterruptionDecisionProviderImpl(
@@ -73,7 +74,8 @@
uiEventLogger,
userTracker,
avalancheProvider,
- systemSettings
+ systemSettings,
+ packageManager
)
} else {
NotificationInterruptStateProviderWrapper(
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 f3f16f7..cde241b 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
@@ -57,6 +57,7 @@
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceState;
@@ -339,6 +340,7 @@
@Mock private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
@Mock private KeyboardShortcuts mKeyboardShortcuts;
@Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+ @Mock private PackageManager mPackageManager;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -392,7 +394,8 @@
mock(UiEventLogger.class),
mUserTracker,
mAvalancheProvider,
- mSystemSettings);
+ mSystemSettings,
+ mPackageManager);
mVisualInterruptionDecisionProvider.start();
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 71f09a5..f3d6407 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -181,6 +181,7 @@
mViewModel =
new KeyguardStatusBarViewModel(
mTestScope.getBackgroundScope(),
+ mKosmos.getHeadsUpNotificationInteractor(),
mKeyguardInteractor,
new KeyguardStatusBarInteractor(new FakeKeyguardStatusBarRepository()),
mBatteryController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index fdf77ae..ff182ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -46,6 +46,7 @@
import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -55,6 +56,7 @@
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -90,10 +92,11 @@
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
-
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter();
private NotificationIconAreaController mMockNotificationAreaController;
private ShadeExpansionStateManager mShadeExpansionStateManager;
private OngoingCallController mOngoingCallController;
+ private OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
// Set in instantiate()
@@ -667,6 +670,7 @@
MockitoAnnotations.initMocks(this);
setUpDaggerComponent();
mOngoingCallController = mock(OngoingCallController.class);
+ mOngoingActivityChipsViewModel = mKosmos.getOngoingActivityChipsViewModel();
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
mStatusBarIconController = mock(StatusBarIconController.class);
@@ -687,6 +691,7 @@
return new CollapsedStatusBarFragment(
mStatusBarFragmentComponentFactory,
mOngoingCallController,
+ mOngoingActivityChipsViewModel,
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 865b312..606feab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -19,77 +19,59 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.filters.SmallTest
-import com.android.systemui.CoroutineTestScopeModule
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.collectValues
-import com.android.systemui.communal.dagger.CommunalModule
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
import com.android.systemui.log.assertLogsWtf
-import com.android.systemui.runTest
import com.android.systemui.statusbar.data.model.StatusBarMode
-import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
+import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
-import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor
import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
import org.junit.Test
@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
+ private val kosmos = Kosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- CommunalModule::class,
- BiometricsDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<CollapsedStatusBarViewModelImpl> {
- val statusBarModeRepository: FakeStatusBarModeRepository
- val activeNotificationListRepository: ActiveNotificationListRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ private val testScope = kosmos.testScope
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- testScope: CoroutineTestScopeModule,
- ): TestComponent
- }
- }
+ private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository
+ private val activeNotificationListRepository = kosmos.activeNotificationListRepository
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
- @OptIn(ExperimentalCoroutinesApi::class)
- private val testComponent: TestComponent =
- DaggerCollapsedStatusBarViewModelImplTest_TestComponent.factory()
- .create(
- test = this,
- testScope = CoroutineTestScopeModule(TestScope(UnconfinedTestDispatcher())),
- )
+ private val underTest =
+ CollapsedStatusBarViewModelImpl(
+ kosmos.lightsOutInteractor,
+ kosmos.activeNotificationsInteractor,
+ kosmos.keyguardTransitionInteractor,
+ kosmos.applicationCoroutineScope,
+ )
@Test
fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -100,15 +82,13 @@
)
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isTrue()
-
- job.cancel()
+ assertThat(latest).isTrue()
}
@Test
fun isTransitioningFromLockscreenToOccluded_running_isTrue() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -119,15 +99,13 @@
)
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isTrue()
-
- job.cancel()
+ assertThat(latest).isTrue()
}
@Test
fun isTransitioningFromLockscreenToOccluded_finished_isFalse() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
@@ -135,15 +113,13 @@
testScope.testScheduler,
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
-
- job.cancel()
+ assertThat(latest).isFalse()
}
@Test
fun isTransitioningFromLockscreenToOccluded_canceled_isFalse() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -154,15 +130,13 @@
)
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
-
- job.cancel()
+ assertThat(latest).isFalse()
}
@Test
fun isTransitioningFromLockscreenToOccluded_irrelevantTransition_isFalse() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -173,15 +147,13 @@
)
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
-
- job.cancel()
+ assertThat(latest).isFalse()
}
@Test
fun isTransitioningFromLockscreenToOccluded_followsRepoUpdates() =
- testComponent.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isTransitioningFromLockscreenToOccluded)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -192,7 +164,7 @@
)
)
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isTrue()
+ assertThat(latest).isTrue()
// WHEN the repo updates the transition to finished
keyguardTransitionRepository.sendTransitionStep(
@@ -205,14 +177,12 @@
)
// THEN our manager also updates
- assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
-
- job.cancel()
+ assertThat(latest).isFalse()
}
@Test
fun transitionFromLockscreenToDreamStartedEvent_started_emitted() =
- testComponent.runTest {
+ testScope.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -229,7 +199,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() =
- testComponent.runTest {
+ testScope.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -264,7 +234,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() =
- testComponent.runTest {
+ testScope.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -313,7 +283,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() =
- testComponent.runTest {
+ testScope.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -330,7 +300,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() =
- testComponent.runTest {
+ testScope.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -351,7 +321,7 @@
@Test
@EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_lowProfileWithNotifications_true() =
- testComponent.runTest {
+ testScope.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value =
StatusBarMode.LIGHTS_OUT_TRANSPARENT
activeNotificationListRepository.activeNotifications.value =
@@ -365,7 +335,7 @@
@Test
@EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_lowProfileWithoutNotifications_false() =
- testComponent.runTest {
+ testScope.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value =
StatusBarMode.LIGHTS_OUT_TRANSPARENT
activeNotificationListRepository.activeNotifications.value =
@@ -379,7 +349,7 @@
@Test
@EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_defaultStatusBarModeWithoutNotifications_false() =
- testComponent.runTest {
+ testScope.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
activeNotificationListRepository.activeNotifications.value =
activeNotificationsStore(emptyList())
@@ -392,7 +362,7 @@
@Test
@EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_defaultStatusBarModeWithNotifications_false() =
- testComponent.runTest {
+ testScope.runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
activeNotificationListRepository.activeNotifications.value =
activeNotificationsStore(testNotifications)
@@ -405,7 +375,7 @@
@Test
@DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
fun areNotificationsLightsOut_requiresFlagEnabled() =
- testComponent.runTest {
+ testScope.runTest {
assertLogsWtf {
val flow = underTest.areNotificationsLightsOut(DISPLAY_ID)
assertThat(flow).isEqualTo(emptyFlow<Boolean>())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index ab10bc4..d88289d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -21,12 +21,18 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.domain.interactor.keyguardStatusBarInteractor
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
+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.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.batteryController
import com.android.systemui.testKosmos
@@ -50,7 +56,11 @@
class KeyguardStatusBarViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
+ private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
+ private val headsUpRepository by lazy { kosmos.headsUpNotificationRepository }
+ private val headsUpNotificationInteractor by lazy { kosmos.headsUpNotificationInteractor }
private val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
+ private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
private val keyguardInteractor by lazy { kosmos.keyguardInteractor }
private val keyguardStatusBarInteractor by lazy { kosmos.keyguardStatusBarInteractor }
private val batteryController = kosmos.batteryController
@@ -74,6 +84,7 @@
underTest =
KeyguardStatusBarViewModel(
testScope.backgroundScope,
+ headsUpNotificationInteractor,
keyguardInteractor,
keyguardStatusBarInteractor,
batteryController,
@@ -112,7 +123,22 @@
}
@Test
- fun isVisible_statusBarStateKeyguard_andNotDozing_true() =
+ fun isVisible_headsUpStatusBarShown_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isVisible)
+
+ // WHEN HUN displayed on the bypass lock screen
+ headsUpRepository.setNotifications(FakeHeadsUpRowRepository("key 0", isPinned = true))
+ keyguardTransitionRepository.emitInitialStepsFromOff(KeyguardState.LOCKSCREEN)
+ keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ faceAuthRepository.isBypassEnabled.value = true
+
+ // THEN KeyguardStatusBar is NOT visible to make space for HeadsUpStatusBar
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isVisible_statusBarStateKeyguard_andNotDozing_andNotShowingHeadsUpStatusBar_true() =
testScope.runTest {
val latest by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index a5e7a67..5ad88ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -64,6 +64,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.monet.DynamicColors;
import com.android.systemui.monet.Style;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -997,7 +998,7 @@
// All fixed colors were added once
// All custom dynamic tokens added twice
verify(dynamic, times(
- DynamicColors.allDynamicColorsMapped(false).size() * 2
+ DynamicColors.getAllDynamicColorsMapped(false).size() * 2
+ DynamicColors.getFixedColorsMapped(false).size()
+ DynamicColors.getCustomColorsMapped(false).size() * 2)
).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index fd368eb..eaef007 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -18,8 +18,11 @@
import android.content.Context
import android.hardware.display.DisplayManager
+import android.os.HandlerThread
import android.os.Looper
+import android.os.Process
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -40,6 +43,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
+@RunWithLooper
class RotationChangeProviderTest : SysuiTestCase() {
private lateinit var rotationChangeProvider: RotationChangeProvider
@@ -48,7 +52,10 @@
@Mock lateinit var listener: RotationListener
@Mock lateinit var display: Display
@Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
- private val fakeHandler = FakeHandler(Looper.getMainLooper())
+ private val bgThread =
+ HandlerThread("UnfoldBgTest", Process.THREAD_PRIORITY_FOREGROUND).apply { start() }
+ private val bgHandler = FakeHandler(bgThread.looper)
+ private val callbackHandler = FakeHandler(Looper.getMainLooper())
private lateinit var spyContext: Context
@@ -57,9 +64,10 @@
MockitoAnnotations.initMocks(this)
spyContext = spy(context)
whenever(spyContext.display).thenReturn(display)
- rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
+ rotationChangeProvider =
+ RotationChangeProvider(displayManager, spyContext, bgHandler, callbackHandler)
rotationChangeProvider.addCallback(listener)
- fakeHandler.dispatchQueuedMessages()
+ bgHandler.dispatchQueuedMessages()
verify(displayManager).registerDisplayListener(displayListener.capture(), any())
}
@@ -76,7 +84,7 @@
verify(listener).onRotationChanged(42)
rotationChangeProvider.removeCallback(listener)
- fakeHandler.dispatchQueuedMessages()
+ bgHandler.dispatchQueuedMessages()
sendRotationUpdate(43)
verify(displayManager).unregisterDisplayListener(any())
@@ -86,6 +94,6 @@
private fun sendRotationUpdate(newRotation: Int) {
whenever(display.rotation).thenReturn(newRotation)
displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
- fakeHandler.dispatchQueuedMessages()
+ callbackHandler.dispatchQueuedMessages()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
new file mode 100644
index 0000000..ab95707
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -0,0 +1,236 @@
+/*
+ * 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.settings
+
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings.SettingNotFoundException
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.eq
+
+/** Tests for [SettingsProxy]. */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper
+class SettingsProxyTest : SysuiTestCase() {
+
+ private lateinit var mSettings: SettingsProxy
+ private lateinit var mContentObserver: ContentObserver
+
+ @Before
+ fun setUp() {
+ mSettings = FakeSettingsProxy()
+ mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
+ }
+
+ @Test
+ fun registerContentObserver_inputString_success() {
+ mSettings.registerContentObserver(TEST_SETTING, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserver_inputString_notifyForDescendants_true() {
+ mSettings.registerContentObserver(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserver_inputUri_success() {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserver_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserver(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+
+ @Test
+ fun unregisterContentObserver() {
+ mSettings.unregisterContentObserver(mContentObserver)
+ verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
+ }
+
+ @Test
+ fun getString_keyPresent_returnValidValue() {
+ mSettings.putString(TEST_SETTING, "test")
+ assertThat(mSettings.getString(TEST_SETTING)).isEqualTo("test")
+ }
+
+ @Test
+ fun getString_keyAbsent_returnEmptyValue() {
+ assertThat(mSettings.getString(TEST_SETTING)).isEmpty()
+ }
+
+ @Test
+ fun getInt_keyPresent_returnValidValue() {
+ mSettings.putInt(TEST_SETTING, 2)
+ assertThat(mSettings.getInt(TEST_SETTING)).isEqualTo(2)
+ }
+
+ @Test
+ fun getInt_keyPresent_nonIntegerValue_throwException() {
+ assertThrows(SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getInt(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getInt_keyAbsent_throwException() {
+ assertThrows(SettingNotFoundException::class.java) { mSettings.getInt(TEST_SETTING) }
+ }
+
+ @Test
+ fun getInt_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getInt(TEST_SETTING, 5)).isEqualTo(5)
+ }
+
+ @Test
+ fun getBool_keyPresent_returnValidValue() {
+ mSettings.putBool(TEST_SETTING, true)
+ assertThat(mSettings.getBool(TEST_SETTING)).isTrue()
+ }
+
+ @Test
+ fun getBool_keyPresent_nonBooleanValue_throwException() {
+ assertThrows(SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getBool(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getBool_keyAbsent_throwException() {
+ assertThrows(SettingNotFoundException::class.java) { mSettings.getBool(TEST_SETTING) }
+ }
+
+ @Test
+ fun getBool_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getBool(TEST_SETTING, false)).isEqualTo(false)
+ }
+
+ @Test
+ fun getLong_keyPresent_returnValidValue() {
+ mSettings.putLong(TEST_SETTING, 1L)
+ assertThat(mSettings.getLong(TEST_SETTING)).isEqualTo(1L)
+ }
+
+ @Test
+ fun getLong_keyPresent_nonLongValue_throwException() {
+ assertThrows(SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getLong(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getLong_keyAbsent_throwException() {
+ assertThrows(SettingNotFoundException::class.java) { mSettings.getLong(TEST_SETTING) }
+ }
+
+ @Test
+ fun getLong_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getLong(TEST_SETTING, 2L)).isEqualTo(2L)
+ }
+
+ @Test
+ fun getFloat_keyPresent_returnValidValue() {
+ mSettings.putFloat(TEST_SETTING, 2.5F)
+ assertThat(mSettings.getFloat(TEST_SETTING)).isEqualTo(2.5F)
+ }
+
+ @Test
+ fun getFloat_keyPresent_nonFloatValue_throwException() {
+ assertThrows(SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getFloat(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getFloat_keyAbsent_throwException() {
+ assertThrows(SettingNotFoundException::class.java) { mSettings.getFloat(TEST_SETTING) }
+ }
+
+ @Test
+ fun getFloat_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F)
+ }
+
+ private class FakeSettingsProxy : SettingsProxy {
+
+ private val mContentResolver = mock(ContentResolver::class.java)
+ private val settingToValueMap: MutableMap<String, String> = mutableMapOf()
+
+ override fun getContentResolver() = mContentResolver
+
+ override fun getUriFor(name: String) =
+ Uri.parse(StringBuilder().append("content://settings/").append(name).toString())
+
+ override fun getString(name: String): String {
+ return settingToValueMap[name] ?: ""
+ }
+
+ override fun putString(name: String, value: String): Boolean {
+ settingToValueMap[name] = value
+ return true
+ }
+
+ override fun putString(
+ name: String,
+ value: String,
+ tag: String,
+ makeDefault: Boolean
+ ): Boolean {
+ settingToValueMap[name] = value
+ return true
+ }
+ }
+
+ companion object {
+ private const val TEST_SETTING = "test_setting"
+ private val TEST_SETTING_URI = Uri.parse("content://settings/test_setting")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
new file mode 100644
index 0000000..56328b9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -0,0 +1,365 @@
+/*
+ * 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.settings
+
+import android.content.ContentResolver
+import android.content.pm.UserInfo
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.UserTracker
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.eq
+
+/** Tests for [UserSettingsProxy]. */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper
+class UserSettingsProxyTest : SysuiTestCase() {
+
+ private var mUserTracker = FakeUserTracker()
+ private var mSettings: UserSettingsProxy = FakeUserSettingsProxy(mUserTracker)
+ private var mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
+
+ @Before
+ fun setUp() {
+ mUserTracker.set(
+ listOf(UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_MAIN)),
+ selectedUserIndex = 0
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUser_inputString_success() {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUser_inputString_notifyForDescendants_true() {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUser_inputUri_success() {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUser_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserver_inputUri_success() {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), eq(0))
+ }
+
+ @Test
+ fun registerContentObserver_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserver(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), eq(0))
+ }
+
+ @Test
+ fun getString_keyPresent_returnValidValue() {
+ mSettings.putString(TEST_SETTING, "test")
+ assertThat(mSettings.getString(TEST_SETTING)).isEqualTo("test")
+ }
+
+ @Test
+ fun getString_keyAbsent_returnEmptyValue() {
+ assertThat(mSettings.getString(TEST_SETTING)).isEmpty()
+ }
+
+ @Test
+ fun getStringForUser_multipleUsers_validResult() {
+ mSettings.putStringForUser(TEST_SETTING, "test", MAIN_USER_ID)
+ mSettings.putStringForUser(TEST_SETTING, "test1", SECONDARY_USER_ID)
+ assertThat(mSettings.getStringForUser(TEST_SETTING, MAIN_USER_ID)).isEqualTo("test")
+ assertThat(mSettings.getStringForUser(TEST_SETTING, SECONDARY_USER_ID)).isEqualTo("test1")
+ }
+
+ @Test
+ fun getInt_keyPresent_returnValidValue() {
+ mSettings.putInt(TEST_SETTING, 2)
+ assertThat(mSettings.getInt(TEST_SETTING)).isEqualTo(2)
+ }
+
+ @Test
+ fun getInt_keyPresent_nonIntegerValue_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getInt(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getInt_keyAbsent_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.getInt(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getInt_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getInt(TEST_SETTING, 5)).isEqualTo(5)
+ }
+
+ @Test
+ fun getIntForUser_multipleUsers__validResult() {
+ mSettings.putIntForUser(TEST_SETTING, 1, MAIN_USER_ID)
+ mSettings.putIntForUser(TEST_SETTING, 2, SECONDARY_USER_ID)
+ assertThat(mSettings.getIntForUser(TEST_SETTING, MAIN_USER_ID)).isEqualTo(1)
+ assertThat(mSettings.getIntForUser(TEST_SETTING, SECONDARY_USER_ID)).isEqualTo(2)
+ }
+
+ @Test
+ fun getBool_keyPresent_returnValidValue() {
+ mSettings.putBool(TEST_SETTING, true)
+ assertThat(mSettings.getBool(TEST_SETTING)).isTrue()
+ }
+
+ @Test
+ fun getBool_keyPresent_nonBooleanValue_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getBool(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getBool_keyAbsent_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.getBool(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getBool_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getBool(TEST_SETTING, false)).isEqualTo(false)
+ }
+
+ @Test
+ fun getBoolForUser_multipleUsers__validResult() {
+ mSettings.putBoolForUser(TEST_SETTING, true, MAIN_USER_ID)
+ mSettings.putBoolForUser(TEST_SETTING, false, SECONDARY_USER_ID)
+ assertThat(mSettings.getBoolForUser(TEST_SETTING, MAIN_USER_ID)).isEqualTo(true)
+ assertThat(mSettings.getBoolForUser(TEST_SETTING, SECONDARY_USER_ID)).isEqualTo(false)
+ }
+
+ @Test
+ fun getLong_keyPresent_returnValidValue() {
+ mSettings.putLong(TEST_SETTING, 1L)
+ assertThat(mSettings.getLong(TEST_SETTING)).isEqualTo(1L)
+ }
+
+ @Test
+ fun getLong_keyPresent_nonLongValue_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getLong(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getLong_keyAbsent_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.getLong(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getLong_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getLong(TEST_SETTING, 2L)).isEqualTo(2L)
+ }
+
+ @Test
+ fun getLongForUser_multipleUsers__validResult() {
+ mSettings.putLongForUser(TEST_SETTING, 1L, MAIN_USER_ID)
+ mSettings.putLongForUser(TEST_SETTING, 2L, SECONDARY_USER_ID)
+ assertThat(mSettings.getLongForUser(TEST_SETTING, MAIN_USER_ID)).isEqualTo(1L)
+ assertThat(mSettings.getLongForUser(TEST_SETTING, SECONDARY_USER_ID)).isEqualTo(2L)
+ }
+
+ @Test
+ fun getFloat_keyPresent_returnValidValue() {
+ mSettings.putFloat(TEST_SETTING, 2.5F)
+ assertThat(mSettings.getFloat(TEST_SETTING)).isEqualTo(2.5F)
+ }
+
+ @Test
+ fun getFloat_keyPresent_nonFloatValue_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.putString(TEST_SETTING, "test")
+ mSettings.getFloat(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getFloat_keyAbsent_throwException() {
+ assertThrows(Settings.SettingNotFoundException::class.java) {
+ mSettings.getFloat(TEST_SETTING)
+ }
+ }
+
+ @Test
+ fun getFloat_keyAbsent_returnDefaultValue() {
+ assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F)
+ }
+
+ @Test
+ fun getFloatForUser_multipleUsers__validResult() {
+ mSettings.putFloatForUser(TEST_SETTING, 1F, MAIN_USER_ID)
+ mSettings.putFloatForUser(TEST_SETTING, 2F, SECONDARY_USER_ID)
+ assertThat(mSettings.getFloatForUser(TEST_SETTING, MAIN_USER_ID)).isEqualTo(1F)
+ assertThat(mSettings.getFloatForUser(TEST_SETTING, SECONDARY_USER_ID)).isEqualTo(2F)
+ }
+
+ /**
+ * Fake implementation of [UserSettingsProxy].
+ *
+ * This class uses a mock of [ContentResolver] to test the [ContentObserver] registration APIs.
+ */
+ private class FakeUserSettingsProxy(override val userTracker: UserTracker) : UserSettingsProxy {
+
+ private val mContentResolver = mock(ContentResolver::class.java)
+ private val userIdToSettingsValueMap: MutableMap<Int, MutableMap<String, String>> =
+ mutableMapOf()
+
+ override fun getContentResolver() = mContentResolver
+
+ override fun getUriFor(name: String) =
+ Uri.parse(StringBuilder().append(URI_PREFIX).append(name).toString())
+
+ override fun getStringForUser(name: String, userHandle: Int) =
+ userIdToSettingsValueMap[userHandle]?.get(name) ?: ""
+
+ override fun putString(
+ name: String,
+ value: String,
+ overrideableByRestore: Boolean
+ ): Boolean {
+ userIdToSettingsValueMap[DEFAULT_USER_ID]?.put(name, value)
+ return true
+ }
+
+ override fun putString(
+ name: String,
+ value: String,
+ tag: String,
+ makeDefault: Boolean
+ ): Boolean {
+ putStringForUser(name, value, DEFAULT_USER_ID)
+ return true
+ }
+
+ override fun putStringForUser(name: String, value: String, userHandle: Int): Boolean {
+ userIdToSettingsValueMap[userHandle] = mutableMapOf(Pair(name, value))
+ return true
+ }
+
+ override fun putStringForUser(
+ name: String,
+ value: String,
+ tag: String?,
+ makeDefault: Boolean,
+ userHandle: Int,
+ overrideableByRestore: Boolean
+ ): Boolean {
+ userIdToSettingsValueMap[userHandle]?.set(name, value)
+ return true
+ }
+
+ private companion object {
+ const val DEFAULT_USER_ID = 0
+ const val URI_PREFIX = "content://settings/"
+ }
+ }
+
+ private companion object {
+ const val MAIN_USER_ID = 10
+ const val SECONDARY_USER_ID = 20
+ const val TEST_SETTING = "test_setting"
+ val TEST_SETTING_URI = Uri.parse("content://settings/test_setting")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index df78110..7b0a556 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -467,7 +467,8 @@
mock(UiEventLogger.class),
mock(UserTracker.class),
mock(AvalancheProvider.class),
- mock(SystemSettings.class)
+ mock(SystemSettings.class),
+ mock(PackageManager.class)
);
interruptionDecisionProvider.start();
@@ -2132,8 +2133,7 @@
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
mBubbleController.registerBubbleStateListener(bubbleStateListener);
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(),
- new Rect(500, 1000, 600, 1100));
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 1000);
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
@@ -2157,7 +2157,7 @@
mBubbleController.updateBubble(mBubbleEntry2);
// Select first bubble
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
@@ -2166,7 +2166,7 @@
assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
// Stop dragging, first bubble should be expanded
- mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+ mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT, 0);
assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
}
@@ -2186,7 +2186,7 @@
mBubbleController.updateBubble(mBubbleEntry2);
// Select first bubble
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
@@ -2195,7 +2195,7 @@
assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
// Stop dragging, first bubble should be expanded
- mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+ mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT, 0);
assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
}
@@ -2215,7 +2215,7 @@
mBubbleController.updateBubble(mBubbleEntry2);
// Select first bubble
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
// Drag first bubble to dismiss
mBubbleController.startBubbleDrag(mBubbleEntry.getKey());
mBubbleController.dragBubbleToDismiss(mBubbleEntry.getKey());
@@ -2239,7 +2239,7 @@
mBubbleController.updateBubble(mBubbleEntry2);
// Select first bubble
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
// Drag second bubble to dismiss
mBubbleController.startBubbleDrag(mBubbleEntry2.getKey());
mBubbleController.dragBubbleToDismiss(mBubbleEntry2.getKey());
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
index 42b6e18..020f7fa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
@@ -66,6 +66,7 @@
FaceWakeUpTriggersConfigModule::class,
]
)
+@Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
interface SysUITestModule {
@Binds fun bindTestableContext(sysuiTestableContext: SysuiTestableContext): TestableContext
@@ -127,6 +128,7 @@
}
}
+@Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
interface SysUITestComponent<out T> {
val testScope: TestScope
val underTest: T
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
index e37bdc1..2809967 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
@@ -17,6 +17,9 @@
private val _userId = MutableStateFlow<Int?>(null)
override val userId = _userId.asStateFlow()
+ private val _requestId = MutableStateFlow<Long?>(null)
+ override val requestId = _requestId.asStateFlow()
+
private var _challenge = MutableStateFlow<Long?>(null)
override val challenge = _challenge.asStateFlow()
@@ -32,6 +35,7 @@
override fun setPrompt(
promptInfo: PromptInfo,
userId: Int,
+ requestId: Long,
gatekeeperChallenge: Long?,
kind: PromptKind,
opPackageName: String,
@@ -39,6 +43,7 @@
setPrompt(
promptInfo,
userId,
+ requestId,
gatekeeperChallenge,
kind,
forceConfirmation = false,
@@ -48,6 +53,7 @@
fun setPrompt(
promptInfo: PromptInfo,
userId: Int,
+ requestId: Long,
gatekeeperChallenge: Long?,
kind: PromptKind,
forceConfirmation: Boolean = false,
@@ -55,15 +61,17 @@
) {
_promptInfo.value = promptInfo
_userId.value = userId
+ _requestId.value = requestId
_challenge.value = gatekeeperChallenge
_promptKind.value = kind
_isConfirmationRequired.value = promptInfo.isConfirmationRequested || forceConfirmation
_opPackageName.value = opPackageName
}
- override fun unsetPrompt() {
+ override fun unsetPrompt(requestId: Long) {
_promptInfo.value = null
_userId.value = null
+ _requestId.value = null
_challenge.value = null
_promptKind.value = PromptKind.None
_opPackageName.value = null
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt
index 3ea4687..77d39f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt
@@ -18,6 +18,7 @@
import android.content.res.mainResources
import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
+import com.android.systemui.keyguard.domain.interactor.devicePostureInteractor
import com.android.systemui.kosmos.Kosmos
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -31,5 +32,6 @@
faceAuthInteractor = deviceEntryFaceAuthInteractor,
biometricSettingsInteractor = deviceEntryBiometricSettingsInteractor,
faceHelpMessageDeferralInteractor = faceHelpMessageDeferralInteractor,
+ devicePostureInteractor = devicePostureInteractor,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryKosmos.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryKosmos.kt
index 26b0b01..9bbb34c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.keyguard.data.repository
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.devicePostureRepository: DevicePostureRepository by
+ Kosmos.Fixture { FakeDevicePostureRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt
new file mode 100644
index 0000000..75eb3c9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt
@@ -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.systemui.keyguard.domain.interactor
+
+import com.android.systemui.keyguard.data.repository.devicePostureRepository
+import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.devicePostureInteractor by
+ Kosmos.Fixture {
+ DevicePostureInteractor(
+ devicePostureRepository = devicePostureRepository,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
index b38acc8..bd9c0be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
@@ -30,6 +31,7 @@
fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor,
notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
- sceneInteractor = sceneInteractor,
+ sceneInteractor = { sceneInteractor },
+ deviceEntryInteractor = { deviceEntryInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
index f1784a8..24201d7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.aodAlphaViewModel by Fixture {
@@ -30,5 +31,6 @@
goneToAodTransitionViewModel = goneToAodTransitionViewModel,
goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
keyguardInteractor = keyguardInteractor,
+ sceneInteractor = sceneInteractor,
)
}
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 a81ac03..f2f4332 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
@@ -55,6 +55,8 @@
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shadeController
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
@@ -62,11 +64,18 @@
import com.android.systemui.util.time.systemClock
import kotlinx.coroutines.ExperimentalCoroutinesApi
-/** Helper for using [Kosmos] from Java. */
+/**
+ * Helper for using [Kosmos] from Java.
+ *
+ * If your test class extends [SysuiTestCase], you may use the secondary constructor so that
+ * [Kosmos.applicationContext] and [Kosmos.testCase] are automatically set.
+ */
@Deprecated("Please convert your test to Kotlin and use [Kosmos] directly.")
-class KosmosJavaAdapter(
- testCase: SysuiTestCase,
-) {
+class KosmosJavaAdapter() {
+ constructor(testCase: SysuiTestCase) : this() {
+ kosmos.applicationContext = testCase.context
+ kosmos.testCase = testCase
+ }
private val kosmos = Kosmos()
@@ -78,6 +87,7 @@
val configurationInteractor by lazy { kosmos.configurationInteractor }
val bouncerRepository by lazy { kosmos.bouncerRepository }
val communalRepository by lazy { kosmos.fakeCommunalRepository }
+ val headsUpNotificationInteractor by lazy { kosmos.headsUpNotificationInteractor }
val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
val keyguardBouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
val keyguardInteractor by lazy { kosmos.keyguardInteractor }
@@ -117,8 +127,5 @@
val shadeRepository by lazy { kosmos.shadeRepository }
val shadeInteractor by lazy { kosmos.shadeInteractor }
- init {
- kosmos.applicationContext = testCase.context
- kosmos.testCase = testCase
- }
+ val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
index 34e99d3..5568c6c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
@@ -20,13 +20,24 @@
import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
val Kosmos.gridLayoutTypeInteractor by
Kosmos.Fixture { GridLayoutTypeInteractor(gridLayoutTypeRepository) }
val Kosmos.gridLayoutMap: Map<GridLayoutType, GridLayout> by
- Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridLayout)) }
+ Kosmos.Fixture {
+ mapOf(
+ Pair(PartitionedGridLayoutType, partitionedGridLayout),
+ Pair(InfiniteGridLayoutType, infiniteGridLayout)
+ )
+ }
var Kosmos.gridConsistencyInteractorsMap: Map<GridLayoutType, GridTypeConsistencyInteractor> by
- Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)) }
+ Kosmos.Fixture {
+ mapOf(
+ Pair(PartitionedGridLayoutType, noopGridConsistencyInteractor),
+ Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)
+ )
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt
index 26b0b01..4febfe91 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.qs.panels.domain.interactor
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout
+
+val Kosmos.partitionedGridLayout by
+ Kosmos.Fixture { PartitionedGridLayout(iconTilesInteractor, infiniteGridSizeInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
index 9481fca..6625bb5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
@@ -20,7 +20,7 @@
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap
import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor
-import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout
+import com.android.systemui.qs.panels.domain.interactor.partitionedGridLayout
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
val Kosmos.tileGridViewModel by
@@ -29,7 +29,7 @@
gridLayoutTypeInteractor,
gridLayoutMap,
currentTilesInteractor,
- infiniteGridLayout,
+ partitionedGridLayout,
applicationCoroutineScope,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
index 26b0b01..fb0e368 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.screenrecord.data.repository
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeScreenRecordRepository : ScreenRecordRepository {
+ override val screenRecordState: MutableStateFlow<ScreenRecordModel> =
+ MutableStateFlow(ScreenRecordModel.DoingNothing)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryKosmos.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryKosmos.kt
index 26b0b01..0ec660e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.screenrecord.data.repository
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.screenRecordRepository: FakeScreenRecordRepository by
+ Kosmos.Fixture { FakeScreenRecordRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.kt
new file mode 100644
index 0000000..cd08274
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.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.chips.ui.viewmodel
+
+import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeScreenRecordChipInteractor : ScreenRecordChipInteractor() {
+ override val chip: MutableStateFlow<OngoingActivityChipModel> =
+ MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
+
+class FakeCallChipInteractor : CallChipInteractor() {
+ override val chip: MutableStateFlow<OngoingActivityChipModel> =
+ MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
new file mode 100644
index 0000000..ffbaa7f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.chips.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+
+val Kosmos.screenRecordChipInteractor: FakeScreenRecordChipInteractor by
+ Kosmos.Fixture { FakeScreenRecordChipInteractor() }
+
+val Kosmos.callChipInteractor: FakeCallChipInteractor by Kosmos.Fixture { FakeCallChipInteractor() }
+
+val Kosmos.ongoingActivityChipsViewModel: OngoingActivityChipsViewModel by
+ Kosmos.Fixture {
+ OngoingActivityChipsViewModel(
+ testScope.backgroundScope,
+ screenRecordChipInteractor = screenRecordChipInteractor,
+ callChipInteractor = callChipInteractor,
+ )
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
index 26b0b01..0f2b477 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.statusbar.data.repository
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.statusBarModeRepository: StatusBarModeRepositoryStore by
+ Kosmos.Fixture { fakeStatusBarModeRepository }
+val Kosmos.fakeStatusBarModeRepository by Kosmos.Fixture { FakeStatusBarModeRepository() }
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
index 2e983a8..980d65f 100644
--- 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
@@ -18,7 +18,11 @@
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeHeadsUpRowRepository(override val key: String, override val elementKey: Any) :
+class FakeHeadsUpRowRepository(override val key: String, override val elementKey: Any = Any()) :
HeadsUpRowRepository {
+ constructor(key: String, isPinned: Boolean) : this(key = key) {
+ this.isPinned.value = isPinned
+ }
+
override val isPinned: MutableStateFlow<Boolean> = MutableStateFlow(false)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HeadsUpNotificationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HeadsUpNotificationInteractorKosmos.kt
index d345107..c74aec1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HeadsUpNotificationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HeadsUpNotificationInteractorKosmos.kt
@@ -16,11 +16,20 @@
package com.android.systemui.statusbar.notification.stack.domain.interactor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
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.domain.interactor.HeadsUpNotificationInteractor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
val Kosmos.headsUpNotificationInteractor by Fixture {
- HeadsUpNotificationInteractor(headsUpNotificationRepository)
+ HeadsUpNotificationInteractor(
+ headsUpNotificationRepository,
+ deviceEntryFaceAuthInteractor,
+ keyguardTransitionInteractor,
+ notificationsKeyguardInteractor,
+ shadeInteractor,
+ )
}
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 94f6ecd..de8b350 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
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.dump.dumpManager
-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
@@ -42,7 +41,6 @@
activeNotificationsInteractor,
notificationStackInteractor,
headsUpNotificationInteractor,
- keyguardInteractor,
remoteInputInteractor,
seenNotificationsInteractor,
shadeInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorKosmos.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorKosmos.kt
index 26b0b01..37b0119 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/model/ScreenRecordTileModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.qs.tiles.impl.screenrecord.domain.model
+package com.android.systemui.statusbar.phone.domain.interactor
-/** Data model for screen record tile */
-sealed interface ScreenRecordTileModel {
- data object Recording : ScreenRecordTileModel
- data class Starting(val millisUntilStarted: Long) : ScreenRecordTileModel
- data object DoingNothing : ScreenRecordTileModel
-}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.data.repository.statusBarModeRepository
+
+val Kosmos.lightsOutInteractor by Kosmos.Fixture { LightsOutInteractor(statusBarModeRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
index 6b27079..21d59f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
@@ -43,8 +43,6 @@
private val models: MutableMap<AudioStream, MutableStateFlow<AudioStreamModel>> = mutableMapOf()
private val lastAudibleVolumes: MutableMap<AudioStream, Int> = mutableMapOf()
- private var isAffectedByMute: MutableMap<AudioStream, Boolean> = mutableMapOf()
-
private fun getAudioStreamModelState(
audioStream: AudioStream
): MutableStateFlow<AudioStreamModel> =
@@ -55,6 +53,7 @@
volume = 0,
minVolume = 0,
maxVolume = 10,
+ isAffectedByMute = false,
isAffectedByRingerMode = false,
isMuted = false,
)
@@ -104,11 +103,4 @@
override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) {
mutableRingerMode.value = mode
}
-
- override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
- isAffectedByMute[audioStream] ?: true
-
- fun setIsAffectedByMute(audioStream: AudioStream, isAffected: Boolean) {
- isAffectedByMute[audioStream] = isAffected
- }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
index f9b7e69..2b5d1b9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
@@ -20,10 +20,13 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.util.mockito.mock
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
import com.android.systemui.volume.panel.component.anc.data.repository.FakeAncSliceRepository
import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor
var Kosmos.sliceViewManager: SliceViewManager by Kosmos.Fixture { mock {} }
val Kosmos.ancSliceRepository by Kosmos.Fixture { FakeAncSliceRepository() }
val Kosmos.ancSliceInteractor by
- Kosmos.Fixture { AncSliceInteractor(ancSliceRepository, testScope.backgroundScope) }
+ Kosmos.Fixture {
+ AncSliceInteractor(audioOutputInteractor, ancSliceRepository, testScope.backgroundScope)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
index d4a72b4..ebe6850 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.panel.component.anc.data.repository
+import android.bluetooth.BluetoothDevice
import androidx.slice.Slice
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -24,7 +25,12 @@
private val sliceByWidth = mutableMapOf<Int, MutableStateFlow<Slice?>>()
- override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
+ override fun ancSlice(
+ device: BluetoothDevice,
+ width: Int,
+ isCollapsed: Boolean,
+ hideLabel: Boolean
+ ): Flow<Slice?> {
return sliceByWidth.getOrPut(width) { MutableStateFlow(null) }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
new file mode 100644
index 0000000..4029609
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
@@ -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.systemui.volume.panel.component.mediaoutput.domain.interactor
+
+import android.annotation.SuppressLint
+import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.TestStubDrawable
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.settingslib.media.MediaDevice
+import com.android.settingslib.media.PhoneMediaDevice
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+@SuppressLint("StaticFieldLeak") // These are mocks
+object TestMediaDevicesFactory {
+
+ fun builtInMediaDevice(): MediaDevice = mock {
+ whenever(name).thenReturn("built_in_media")
+ whenever(icon).thenReturn(TestStubDrawable())
+ }
+
+ fun wiredMediaDevice(): MediaDevice =
+ mock<PhoneMediaDevice> {
+ whenever(deviceType)
+ .thenReturn(MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE)
+ whenever(name).thenReturn("wired_media")
+ whenever(icon).thenReturn(TestStubDrawable())
+ }
+
+ fun bluetoothMediaDevice(): MediaDevice {
+ val bluetoothDevice = mock<BluetoothDevice>()
+ val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+ whenever(isHearingAidDevice).thenReturn(true)
+ whenever(address).thenReturn("bt_media_device")
+ whenever(device).thenReturn(bluetoothDevice)
+ }
+ return mock<BluetoothMediaDevice> {
+ whenever(name).thenReturn("bt_media")
+ whenever(icon).thenReturn(TestStubDrawable())
+ whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+ }
+ }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
index 2bc2db3..fe10244 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
@@ -53,8 +53,8 @@
@UnfoldMain
fun provideMainRotationChangeProvider(
rotationChangeProviderFactory: RotationChangeProvider.Factory,
- @UnfoldMain mainHandler: Handler,
+ @UnfoldMain callbackHandler: Handler,
): RotationChangeProvider {
- return rotationChangeProviderFactory.create(mainHandler)
+ return rotationChangeProviderFactory.create(callbackHandler)
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 31b7ccc..f382070 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -87,6 +87,7 @@
@BindsInstance @UnfoldMain executor: Executor,
@BindsInstance @UnfoldMain handler: Handler,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
+ @BindsInstance @UnfoldBg bgHandler: Handler,
@BindsInstance displayManager: DisplayManager,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
): RemoteUnfoldSharedComponent
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index 1b7e71a..f83ea84 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -270,9 +270,9 @@
@UnfoldMain
fun provideRotationChangeProvider(
rotationChangeProviderFactory: RotationChangeProvider.Factory,
- @UnfoldMain mainHandler: Handler,
+ @UnfoldMain callbackHandler: Handler,
): RotationChangeProvider {
- return rotationChangeProviderFactory.create(mainHandler)
+ return rotationChangeProviderFactory.create(callbackHandler)
}
@Provides
@@ -280,8 +280,9 @@
@UnfoldBg
fun provideBgRotationChangeProvider(
rotationChangeProviderFactory: RotationChangeProvider.Factory,
- @UnfoldBg bgHandler: Handler,
+ @UnfoldBg callbackHandler: Handler,
): RotationChangeProvider {
- return rotationChangeProviderFactory.create(bgHandler)
+ // For UnfoldBg RotationChangeProvider we use bgHandler as callbackHandler
+ return rotationChangeProviderFactory.create(callbackHandler)
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 1cbaf31..8a4f985 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -77,6 +77,7 @@
mainExecutor: Executor,
mainHandler: Handler,
singleThreadBgExecutor: Executor,
+ bgHandler: Handler,
tracingTagPrefix: String,
displayManager: DisplayManager,
): RemoteUnfoldSharedComponent =
@@ -87,6 +88,7 @@
mainExecutor,
mainHandler,
singleThreadBgExecutor,
+ bgHandler,
displayManager,
tracingTagPrefix,
)
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 77f637b..a100974 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -20,6 +20,7 @@
import android.util.Log
import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
import androidx.core.util.Consumer
import com.android.systemui.unfold.compat.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -215,6 +216,7 @@
}
private inner class FoldRotationListener : RotationChangeProvider.RotationListener {
+ @WorkerThread
override fun onRotationChanged(newRotation: Int) {
assertInProgressThread()
if (isTransitionInProgress) cancelAnimation()
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index bb91f9b..4f3aee9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -21,6 +21,8 @@
import android.os.Handler
import android.os.RemoteException
import android.os.Trace
+import androidx.annotation.AnyThread
+import com.android.systemui.unfold.dagger.UnfoldBg
import com.android.systemui.unfold.util.CallbackController
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -35,7 +37,8 @@
constructor(
private val displayManager: DisplayManager,
private val context: Context,
- @Assisted private val handler: Handler,
+ @UnfoldBg private val bgHandler: Handler,
+ @Assisted private val callbackHandler: Handler,
) : CallbackController<RotationChangeProvider.RotationListener> {
private val listeners = mutableListOf<RotationListener>()
@@ -44,7 +47,7 @@
private var lastRotation: Int? = null
override fun addCallback(listener: RotationListener) {
- handler.post {
+ bgHandler.post {
if (listeners.isEmpty()) {
subscribeToRotation()
}
@@ -53,7 +56,7 @@
}
override fun removeCallback(listener: RotationListener) {
- handler.post {
+ bgHandler.post {
listeners -= listener
if (listeners.isEmpty()) {
unsubscribeToRotation()
@@ -64,7 +67,7 @@
private fun subscribeToRotation() {
try {
- displayManager.registerDisplayListener(displayListener, handler)
+ displayManager.registerDisplayListener(displayListener, callbackHandler)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -80,8 +83,11 @@
/** Gets notified of rotation changes. */
fun interface RotationListener {
- /** Called once rotation changes. */
- fun onRotationChanged(newRotation: Int)
+ /**
+ * Called once rotation changes. This callback is called on the handler provided to
+ * [RotationChangeProvider.Factory.create].
+ */
+ @AnyThread fun onRotationChanged(newRotation: Int)
}
private inner class RotationDisplayListener : DisplayManager.DisplayListener {
@@ -110,7 +116,7 @@
@AssistedFactory
interface Factory {
- /** Creates a new [RotationChangeProvider] that provides updated using [handler]. */
- fun create(handler: Handler): RotationChangeProvider
+ /** Creates a new [RotationChangeProvider] that provides updated using [callbackHandler]. */
+ fun create(callbackHandler: Handler): RotationChangeProvider
}
}
diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS
index 41fd68e..a90328c 100644
--- a/ravenwood/OWNERS
+++ b/ravenwood/OWNERS
@@ -2,4 +2,6 @@
jsharkey@google.com
omakoto@google.com
-jaggies@google.com
+
+per-file ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com
+per-file texts/ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
index 3edca7e..01e90d8 100644
--- a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
@@ -18,6 +18,7 @@
import android.platform.test.annotations.DisabledOnNonRavenwood;
import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -43,5 +44,13 @@
Assert.assertTrue(RavenwoodRule.isOnRavenwood());
}
+ @Test
+ public void testDumpSystemProperties() {
+ Log.w("XXX", "System properties");
+ for (var sp : System.getProperties().entrySet()) {
+ Log.w("XXX", "" + sp.getKey() + "=" + sp.getValue());
+ }
+ }
+
// TODO: Add more tests
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 56a3c64..5506a46 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -100,10 +100,11 @@
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
- android.os.SystemProperties.init$ravenwood(
- rule.mSystemProperties.getValues(),
- rule.mSystemProperties.getKeyReadablePredicate(),
- rule.mSystemProperties.getKeyWritablePredicate());
+// android.os.SystemProperties.init$ravenwood(
+// rule.mSystemProperties.getValues(),
+// rule.mSystemProperties.getKeyReadablePredicate(),
+// rule.mSystemProperties.getKeyWritablePredicate());
+ setSystemProperties(rule.mSystemProperties);
ServiceManager.init$ravenwood();
LocalServices.removeAllServicesForTest();
@@ -157,7 +158,7 @@
LocalServices.removeAllServicesForTest();
ServiceManager.reset$ravenwood();
- android.os.SystemProperties.reset$ravenwood();
+ setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
android.os.Binder.reset$ravenwood();
android.os.Process.reset$ravenwood();
@@ -291,4 +292,16 @@
collectMethods(clazz.getSuperclass(), result);
}
}
+
+ /**
+ * Set the current configuration to the actual SystemProperties.
+ */
+ public static void setSystemProperties(RavenwoodSystemProperties ravenwoodSystemProperties) {
+ var clone = new RavenwoodSystemProperties(ravenwoodSystemProperties, true);
+
+ android.os.SystemProperties.init$ravenwood(
+ clone.getValues(),
+ clone.getKeyReadablePredicate(),
+ clone.getKeyWritablePredicate());
+ }
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index 85ad4e4..c3786ee 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -22,7 +22,9 @@
import java.util.Set;
import java.util.function.Predicate;
-class RavenwoodSystemProperties {
+public class RavenwoodSystemProperties {
+ private volatile boolean mIsImmutable;
+
private final Map<String, String> mValues = new HashMap<>();
/** Set of additional keys that should be considered readable */
@@ -101,15 +103,23 @@
setValue("ro.debuggable", "1");
}
- Map<String, String> getValues() {
+ /** Copy constructor */
+ public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) {
+ this.mKeyReadable.addAll(source.mKeyReadable);
+ this.mKeyWritable.addAll(source.mKeyWritable);
+ this.mValues.putAll(source.mValues);
+ this.mIsImmutable = immutable;
+ }
+
+ public Map<String, String> getValues() {
return new HashMap<>(mValues);
}
- Predicate<String> getKeyReadablePredicate() {
+ public Predicate<String> getKeyReadablePredicate() {
return mKeyReadablePredicate;
}
- Predicate<String> getKeyWritablePredicate() {
+ public Predicate<String> getKeyWritablePredicate() {
return mKeyWritablePredicate;
}
@@ -123,12 +133,20 @@
"vendor_dlkm",
};
+ private void ensureNotImmutable() {
+ if (mIsImmutable) {
+ throw new RuntimeException("Unable to update immutable instance");
+ }
+ }
+
/**
* Set the given property for all possible partitions where it could be defined. For
* example, the value of {@code ro.build.type} is typically also mirrored under
* {@code ro.system.build.type}, etc.
*/
private void setValueForPartitions(String key, String value) {
+ ensureNotImmutable();
+
setValue("ro." + key, value);
for (String partition : PARTITIONS) {
setValue("ro." + partition + "." + key, value);
@@ -136,6 +154,8 @@
}
public void setValue(String key, Object value) {
+ ensureNotImmutable();
+
final String valueString = (value == null) ? null : String.valueOf(value);
if ((valueString == null) || valueString.isEmpty()) {
mValues.remove(key);
@@ -145,16 +165,19 @@
}
public void setAccessNone(String key) {
+ ensureNotImmutable();
mKeyReadable.remove(key);
mKeyWritable.remove(key);
}
public void setAccessReadOnly(String key) {
+ ensureNotImmutable();
mKeyReadable.add(key);
mKeyWritable.remove(key);
}
public void setAccessReadWrite(String key) {
+ ensureNotImmutable();
mKeyReadable.add(key);
mKeyWritable.add(key);
}
@@ -172,4 +195,11 @@
return key;
}
}
-}
+
+ /**
+ * Return an immutable, default instance.
+ */
+ // Create a default instance, and make an immutable copy of it.
+ public static final RavenwoodSystemProperties DEFAULT_VALUES =
+ new RavenwoodSystemProperties(new RavenwoodSystemProperties(), true);
+}
\ No newline at end of file
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
new file mode 100644
index 0000000..68bf922
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
@@ -0,0 +1,57 @@
+/*
+ * 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.platform.test.ravenwood.nativesubstitution;
+
+import android.platform.test.ravenwood.RavenwoodSystemProperties;
+import android.util.Log;
+
+import com.android.internal.ravenwood.RavenwoodEnvironment;
+
+public class RavenwoodEnvironment_host {
+ private static final String TAG = RavenwoodEnvironment.TAG;
+
+ private static final Object sInitializeLock = new Object();
+
+ // @GuardedBy("sInitializeLock")
+ private static boolean sInitialized;
+
+ private RavenwoodEnvironment_host() {
+ }
+
+ /**
+ * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
+ */
+ public static void ensureRavenwoodInitializedInternal() {
+ synchronized (sInitializeLock) {
+ if (sInitialized) {
+ return;
+ }
+ Log.w(TAG, "Initializing Ravenwood environment");
+
+ // Set the default values.
+ var sysProps = RavenwoodSystemProperties.DEFAULT_VALUES;
+
+ // We have a method that does it in RavenwoodRuleImpl, but we can't use that class
+ // here, So just inline it.
+ SystemProperties_host.initializeIfNeeded(
+ sysProps.getValues(),
+ sysProps.getKeyReadablePredicate(),
+ sysProps.getKeyWritablePredicate());
+
+ sInitialized = true;
+ }
+ }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
index eba6c8b..e7479d3 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
@@ -47,6 +47,21 @@
@GuardedBy("sLock")
private static SparseArray<String> sKeyHandles = new SparseArray<>();
+ /**
+ * Basically the same as {@link #native_init$ravenwood}, but it'll only run if no values are
+ * set yet.
+ */
+ public static void initializeIfNeeded(Map<String, String> values,
+ Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate) {
+ synchronized (sLock) {
+ if (sValues != null) {
+ return; // Already initialized.
+ }
+ native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
+ () -> {});
+ }
+ }
+
public static void native_init$ravenwood(Map<String, String> values,
Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
Runnable changeCallback) {
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index a50fb9a..1c57dd3 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -25,6 +25,16 @@
}
flag {
+ name: "clear_default_from_a11y_shortcut_target_service_restore"
+ namespace: "accessibility"
+ description: "Clears the config_defaultAccessibilityService from B&R for ACCESSIBILITY_SHORTCUT_TARGET_SERVICE."
+ bug: "341374402"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "compute_window_changes_on_a11y_v2"
namespace: "accessibility"
description: "Computes accessibility window changes in accessibility instead of wm package."
@@ -209,4 +219,4 @@
namespace: "accessibility"
description: "Feature allows users to change color correction saturation for daltonizer."
bug: "322829049"
-}
\ No newline at end of file
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 40d3e9a..053a1a7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -65,6 +65,7 @@
import android.annotation.Nullable;
import android.annotation.PermissionManuallyEnforced;
import android.annotation.RequiresNoPermission;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityOptions;
import android.app.AlertDialog;
@@ -857,6 +858,7 @@
mPackageMonitor = monitor;
}
+ @SuppressLint("MissingPermission")
private void registerBroadcastReceivers() {
// package changes
mPackageMonitor = new ManagerPackageMonitor(this);
@@ -890,33 +892,47 @@
removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) {
- synchronized (mLock) {
- restoreEnabledAccessibilityServicesLocked(
- intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
- intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
- 0));
+ if (which == null) {
+ return;
+ }
+ final String previousValue =
+ intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+ final String newValue =
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
+ final int restoredFromSdk =
+ intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
+ switch (which) {
+ case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES -> {
+ synchronized (mLock) {
+ restoreEnabledAccessibilityServicesLocked(
+ previousValue, newValue, restoredFromSdk);
+ }
}
- } else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) {
- synchronized (mLock) {
- restoreLegacyDisplayMagnificationNavBarIfNeededLocked(
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
- intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
- 0));
+ case ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED -> {
+ synchronized (mLock) {
+ restoreLegacyDisplayMagnificationNavBarIfNeededLocked(
+ newValue, restoredFromSdk);
+ }
}
- } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) {
- synchronized (mLock) {
- restoreAccessibilityButtonTargetsLocked(
- intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> {
+ synchronized (mLock) {
+ restoreAccessibilityButtonTargetsLocked(
+ previousValue, newValue);
+ }
}
- } else if (Settings.Secure.ACCESSIBILITY_QS_TARGETS.equals(which)) {
- if (!android.view.accessibility.Flags.a11yQsShortcut()) {
- return;
+ case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> {
+ if (!android.view.accessibility.Flags.a11yQsShortcut()) {
+ return;
+ }
+ restoreAccessibilityQsTargets(newValue);
}
- restoreAccessibilityQsTargets(
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> {
+ if (!android.view.accessibility.Flags
+ .restoreA11yShortcutTargetService()) {
+ return;
+ }
+ restoreAccessibilityShortcutTargetService(previousValue, newValue);
+ }
}
}
}
@@ -2079,6 +2095,65 @@
}
}
+ /**
+ * Merges the old and restored value of
+ * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
+ *
+ * <p>Also clears out {@link R.string#config_defaultAccessibilityService} from
+ * the merged set if it was not present before restoring.
+ */
+ private void restoreAccessibilityShortcutTargetService(
+ String oldValue, String restoredValue) {
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedStringToSet(oldValue, str -> str,
+ targetsFromSetting, /*doMerge=*/false);
+ final String defaultService =
+ mContext.getString(R.string.config_defaultAccessibilityService);
+ final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
+ ? null : ComponentName.unflattenFromString(defaultService);
+ boolean shouldClearDefaultService = defaultServiceComponent != null
+ && !stringSetContainsComponentName(targetsFromSetting, defaultServiceComponent);
+ readColonDelimitedStringToSet(restoredValue, str -> str,
+ targetsFromSetting, /*doMerge=*/true);
+ if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()) {
+ if (shouldClearDefaultService && stringSetContainsComponentName(
+ targetsFromSetting, defaultServiceComponent)) {
+ Slog.i(LOG_TAG, "Removing default service " + defaultService
+ + " from restore of "
+ + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+ targetsFromSetting.removeIf(str ->
+ defaultServiceComponent.equals(ComponentName.unflattenFromString(str)));
+ }
+ if (targetsFromSetting.isEmpty()) {
+ return;
+ }
+ }
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
+ final Set<String> shortcutTargets =
+ userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE);
+ shortcutTargets.clear();
+ shortcutTargets.addAll(targetsFromSetting);
+ persistColonDelimitedSetToSettingLocked(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ UserHandle.USER_SYSTEM, targetsFromSetting, str -> str);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ onUserStateChangedLocked(userState);
+ }
+ }
+
+ /**
+ * Returns {@code true} if the set contains the provided non-null {@link ComponentName}.
+ *
+ * <p>This ignores values in the set that are not valid {@link ComponentName}s.
+ */
+ private boolean stringSetContainsComponentName(Set<String> set,
+ @NonNull ComponentName componentName) {
+ return componentName != null && set.stream()
+ .map(ComponentName::unflattenFromString)
+ .anyMatch(componentName::equals);
+ }
+
private int getClientStateLocked(AccessibilityUserState userState) {
return userState.getClientStateLocked(
mUiAutomationManager.canIntrospect(),
@@ -2605,12 +2680,35 @@
}
builder.append(str);
}
+ final String builderValue = builder.toString();
+ final String settingValue = TextUtils.isEmpty(builderValue)
+ ? defaultEmptyString : builderValue;
+ if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
+ final String currentValue = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), settingName, userId);
+ if (Objects.equals(settingValue, currentValue)) {
+ // This logic exists to fix a bug where AccessibilityManagerService was writing
+ // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
+ // during setup, due to a race condition in package scanning making A11yMS think
+ // that the default service was not installed.
+ //
+ // Writing `null` was implicitly causing that Setting to have the default
+ // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
+ // Setting altogether.
+ //
+ // The "quick fix" here is to not write `null` if the existing value is already
+ // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
+ // that allows override-by-restore, but the full repercussions of using that here
+ // have not yet been evaluated.
+ // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
+ // "overridable by restore" when writing secure settings.
+ return;
+ }
+ }
final long identity = Binder.clearCallingIdentity();
try {
- final String settingValue = builder.toString();
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- settingName,
- TextUtils.isEmpty(settingValue) ? defaultEmptyString : settingValue, userId);
+ settingName, settingValue, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4257,7 +4355,7 @@
);
if (!targetWithNoTile.isEmpty()) {
- throw new IllegalArgumentException(
+ Slog.e(LOG_TAG,
"Unable to add/remove Tiles for a11y features: " + targetWithNoTile
+ "as the Tiles aren't provided");
}
@@ -6263,6 +6361,13 @@
}
}
}
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ // We care about all package changes, not just the whole package itself which is
+ // default behavior.
+ return true;
+ }
}
void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 2a7458f..04b42e4 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -974,6 +974,10 @@
clear(event, policyFlags);
return;
case ACTION_POINTER_DOWN:
+ if (mDraggingPointerId != INVALID_POINTER_ID) {
+ mDispatcher.sendMotionEvent(
+ event, ACTION_UP, rawEvent, pointerIdBits, policyFlags);
+ }
if (mState.isServiceDetectingGestures()) {
mAms.sendMotionEventToListeningServices(rawEvent);
return;
@@ -981,10 +985,6 @@
// We are in dragging state so we have two pointers and another one
// goes down => delegate the three pointers to the view hierarchy
mState.startDelegating();
- if (mDraggingPointerId != INVALID_POINTER_ID) {
- mDispatcher.sendMotionEvent(
- event, ACTION_UP, rawEvent, pointerIdBits, policyFlags);
- }
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
break;
case ACTION_MOVE:
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index bc14342..0719eba 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -26,6 +26,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresNoPermission;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -939,11 +940,11 @@
disableWindowMagnification(displayId, true);
}
- @SuppressWarnings("MissingPermissionAnnotation")
private class ConnectionCallback extends IMagnificationConnectionCallback.Stub implements
IBinder.DeathRecipient {
private boolean mExpiredDeathRecipient = false;
+ @RequiresNoPermission
@Override
public void onWindowMagnifierBoundsChanged(int displayId, Rect bounds) {
if (mTrace.isA11yTracingEnabledForTypes(
@@ -965,6 +966,7 @@
}
}
+ @RequiresNoPermission
@Override
public void onChangeMagnificationMode(int displayId, int magnificationMode)
throws RemoteException {
@@ -977,6 +979,7 @@
mCallback.onChangeMagnificationMode(displayId, magnificationMode);
}
+ @RequiresNoPermission
@Override
public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
if (mTrace.isA11yTracingEnabledForTypes(
@@ -995,6 +998,7 @@
mCallback.onSourceBoundsChanged(displayId, sourceBounds);
}
+ @RequiresNoPermission
@Override
public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (mTrace.isA11yTracingEnabledForTypes(
@@ -1007,6 +1011,7 @@
mCallback.onPerformScaleAction(displayId, scale, updatePersistence);
}
+ @RequiresNoPermission
@Override
public void onAccessibilityActionPerformed(int displayId) {
if (mTrace.isA11yTracingEnabledForTypes(
@@ -1018,6 +1023,7 @@
mCallback.onAccessibilityActionPerformed(displayId);
}
+ @RequiresNoPermission
@Override
public void onMove(int displayId) {
if (mTrace.isA11yTracingEnabledForTypes(
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index f6fb24f..03e7867 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -23,6 +23,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresNoPermission;
import android.os.RemoteException;
import android.util.Slog;
import android.view.accessibility.IMagnificationConnection;
@@ -262,7 +263,6 @@
return new RemoteAnimationCallback(callback, trace);
}
- @SuppressWarnings("MissingPermissionAnnotation")
private static class RemoteAnimationCallback extends
IRemoteMagnificationAnimationCallback.Stub {
private final MagnificationAnimationCallback mCallback;
@@ -279,6 +279,7 @@
}
}
+ @RequiresNoPermission
@Override
public void onResult(boolean success) throws RemoteException {
mCallback.onResult(success);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 71b16c3..5567707 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -521,9 +521,13 @@
false);
final boolean packageRemovedPermanently =
(extras == null || !isReplacing || (isReplacing && isArchival));
-
if (packageRemovedPermanently) {
for (String pkgName : pkgList) {
+ if (DEBUG) {
+ Slog.i(TAG, "calling removeHostsAndProvidersForPackageLocked() "
+ + "because package removed permanently. extras=" + extras
+ + " isReplacing=" + isReplacing + " isArchival=" + isArchival);
+ }
componentsModified |= removeHostsAndProvidersForPackageLocked(
pkgName, userId);
}
@@ -2053,6 +2057,9 @@
}
private void deleteHostLocked(Host host) {
+ if (DEBUG) {
+ Slog.i(TAG, "deleteHostLocked() " + host);
+ }
final int N = host.widgets.size();
for (int i = N - 1; i >= 0; i--) {
Widget widget = host.widgets.remove(i);
@@ -2065,6 +2072,9 @@
}
private void deleteAppWidgetLocked(Widget widget) {
+ if (DEBUG) {
+ Slog.i(TAG, "deleteAppWidgetLocked() " + widget);
+ }
// We first unbind all services that are bound to this id
// Check if we need to destroy any services (if no other app widgets are
// referencing the same service)
@@ -2532,6 +2542,10 @@
return widget;
}
}
+ if (DEBUG) {
+ Slog.i(TAG, "cannot find widget for appWidgetId=" + appWidgetId + " uid=" + uid
+ + " packageName=" + packageName);
+ }
return null;
}
@@ -2649,6 +2663,9 @@
// Remove widgets for provider that are hosted in userId.
private void deleteWidgetsLocked(Provider provider, int userId) {
+ if (DEBUG) {
+ Slog.i(TAG, "deleteWidgetsLocked() provider=" + provider + " userId=" + userId);
+ }
final int N = provider.widgets.size();
for (int i = N - 1; i >= 0; i--) {
Widget widget = provider.widgets.get(i);
@@ -3326,6 +3343,9 @@
* Adds the widget to mWidgets and tracks the package name in mWidgetPackages.
*/
void addWidgetLocked(Widget widget) {
+ if (DEBUG) {
+ Slog.i(TAG, "addWidgetLocked() " + widget);
+ }
mWidgets.add(widget);
onWidgetProviderAddedOrChangedLocked(widget);
@@ -3362,6 +3382,9 @@
* removes the associated package from the cache.
*/
void removeWidgetLocked(Widget widget) {
+ if (DEBUG) {
+ Slog.i(TAG, "removeWidgetLocked() " + widget);
+ }
mWidgets.remove(widget);
onWidgetRemovedLocked(widget);
scheduleNotifyAppWidgetRemovedLocked(widget);
@@ -3396,6 +3419,9 @@
* Clears all widgets and associated cache of packages with bound widgets.
*/
void clearWidgetsLocked() {
+ if (DEBUG) {
+ Slog.i(TAG, "clearWidgetsLocked()");
+ }
mWidgets.clear();
onWidgetsClearedLocked();
@@ -3757,6 +3783,9 @@
}
void onUserStopped(int userId) {
+ if (DEBUG) {
+ Slog.i(TAG, "onUserStopped() " + userId);
+ }
synchronized (mLock) {
boolean crossProfileWidgetsChanged = false;
@@ -3994,6 +4023,10 @@
}
private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
+ if (DEBUG) {
+ Slog.i(TAG, "removeHostsAndProvidersForPackageLocked() pkg=" + pkgName
+ + " userId=" + userId);
+ }
boolean removed = removeProvidersForPackageLocked(pkgName, userId);
// Delete the hosts for this package too
@@ -4552,6 +4585,10 @@
// have the bind widget permission have access to the widget.
return true;
}
+ if (DEBUG) {
+ Slog.i(TAG, "canAccessAppWidget() failed. packageName=" + packageName
+ + " uid=" + uid + " userId=" + userId + " widget=" + widget);
+ }
return false;
}
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 0c3d40d..ba84485 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -23,13 +23,6 @@
}
flag {
- name: "ignore_view_state_reset_to_empty"
- namespace: "autofill"
- description: "Mitigation for view state reset to empty causing no save dialog to show issue"
- bug: "297976948"
-}
-
-flag {
name: "include_invisible_view_group_in_assist_structure"
namespace: "autofill"
description: "Mitigation for autofill providers miscalculating view visibility"
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 9f279b1..f69a521 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -34,6 +34,7 @@
import android.provider.Downloads;
import android.system.ErrnoException;
import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -230,16 +231,23 @@
}
private static String getCurrentBootHeaders() throws IOException {
- return new StringBuilder(512)
- .append("Build: ").append(Build.FINGERPRINT).append("\n")
- .append("Hardware: ").append(Build.BOARD).append("\n")
- .append("Revision: ")
- .append(SystemProperties.get("ro.revision", "")).append("\n")
- .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
- .append("Radio: ").append(Build.getRadioVersion()).append("\n")
- .append("Kernel: ")
- .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
- .append("\n").toString();
+ StringBuilder builder = new StringBuilder(512)
+ .append("Build: ").append(Build.FINGERPRINT).append("\n")
+ .append("Hardware: ").append(Build.BOARD).append("\n")
+ .append("Revision: ")
+ .append(SystemProperties.get("ro.revision", "")).append("\n")
+ .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
+ .append("Radio: ").append(Build.getRadioVersion()).append("\n")
+ .append("Kernel: ")
+ .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"));
+
+ // If device is not using 4KB pages, add the PageSize
+ long pageSize = Os.sysconf(OsConstants._SC_PAGESIZE);
+ if (pageSize != 4096) {
+ builder.append("PageSize: ").append(pageSize).append("\n");
+ }
+ builder.append("\n");
+ return builder.toString();
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index d9e6186..ef03888 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -21,6 +21,7 @@
import static android.os.Process.SYSTEM_UID;
import static com.android.server.flags.Flags.pinWebview;
+import static com.android.server.flags.Flags.skipHomeArtPins;
import android.annotation.EnforcePermission;
import android.annotation.IntDef;
@@ -851,6 +852,9 @@
}
int apkPinSizeLimit = pinSizeLimit;
+
+ boolean shouldSkipArtPins = key == KEY_HOME && skipHomeArtPins();
+
for (String apk: apks) {
if (apkPinSizeLimit <= 0) {
Slog.w(TAG, "Reached to the pin size limit. Skipping: " + apk);
@@ -874,8 +878,8 @@
}
apkPinSizeLimit -= pf.bytesPinned;
- if (apk.equals(appInfo.sourceDir)) {
- pinOptimizedDexDependencies(pf, apkPinSizeLimit, appInfo);
+ if (apk.equals(appInfo.sourceDir) && !shouldSkipArtPins) {
+ pinOptimizedDexDependencies(pf, Integer.MAX_VALUE, appInfo);
}
}
}
@@ -921,8 +925,8 @@
}
pf.groupName = groupName != null ? groupName : "";
- maxBytesToPin -= bytesPinned;
bytesPinned += pf.bytesPinned;
+ maxBytesToPin -= bytesPinned;
synchronized (this) {
mPinnedFiles.put(pf.fileName, pf);
@@ -970,7 +974,7 @@
// Unpin if it was already pinned prior to re-pinning.
unpinFile(file);
- PinnedFile df = mInjector.pinFileInternal(file, Integer.MAX_VALUE,
+ PinnedFile df = mInjector.pinFileInternal(file, maxBytesToPin,
/*attemptPinIntrospection=*/false);
if (df == null) {
Slog.i(TAG, "Failed to pin ART file = " + file);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 00d8efa..4c8f416 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -372,6 +372,8 @@
import android.provider.Settings;
import android.server.ServerProtoEnums;
import android.sysprop.InitProperties;
+import android.system.Os;
+import android.system.OsConstants;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
@@ -5588,32 +5590,30 @@
// security checking for it above.
userId = UserHandle.USER_CURRENT;
}
- try {
- if (owningUid != 0 && owningUid != SYSTEM_UID) {
- final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
- MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(owningUid));
- if (!UserHandle.isSameApp(owningUid, uid)) {
- String msg = "Permission Denial: getIntentSender() from pid="
- + Binder.getCallingPid()
- + ", uid=" + owningUid
- + ", (need uid=" + uid + ")"
- + " is not allowed to send as package " + packageName;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- }
- if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
- return mAtmInternal.getIntentSender(type, packageName, featureId, owningUid,
- userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
- bOptions);
+ if (owningUid != 0 && owningUid != SYSTEM_UID) {
+ if (!getPackageManagerInternal().isSameApp(
+ packageName,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ owningUid,
+ UserHandle.getUserId(owningUid))) {
+ String msg = "Permission Denial: getIntentSender() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + owningUid
+ + " is not allowed to send as package " + packageName;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
}
- return mPendingIntentController.getIntentSender(type, packageName, featureId,
- owningUid, userId, token, resultWho, requestCode, intents, resolvedTypes,
- flags, bOptions);
- } catch (RemoteException e) {
- throw new SecurityException(e);
}
+
+ if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+ return mAtmInternal.getIntentSender(type, packageName, featureId, owningUid,
+ userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+ bOptions);
+ }
+ return mPendingIntentController.getIntentSender(type, packageName, featureId,
+ owningUid, userId, token, resultWho, requestCode, intents, resolvedTypes,
+ flags, bOptions);
}
@Override
@@ -9911,6 +9911,13 @@
sb.append("ErrorId: ").append(errorId.toString()).append("\n");
}
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+
+ // If device is not using 4KB pages, add the PageSize
+ long pageSize = Os.sysconf(OsConstants._SC_PAGESIZE);
+ if (pageSize != 4096) {
+ sb.append("PageSize: ").append(pageSize).append("\n");
+ }
+
if (Debug.isDebuggerConnected()) {
sb.append("Debugger: Connected\n");
}
@@ -19975,6 +19982,26 @@
addStartInfoTimestampInternal(key, timestampNs, userId, uid);
}
+
+ @Override
+ public void killApplicationSync(String pkgName, int appId, int userId,
+ String reason, int exitInfoReason) {
+ if (pkgName == null) {
+ return;
+ }
+ // Make sure the uid is valid.
+ if (appId < 0) {
+ Slog.w(TAG, "Invalid appid specified for pkg : " + pkgName);
+ return;
+ }
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.forceStopPackageLocked(pkgName, appId,
+ /* callerWillRestart= */ false, /*purgeCache= */ false,
+ /* doit= */ true, /* evenPersistent= */ false,
+ /* uninstalling= */ false, /* packageStateStopped= */ false,
+ userId, reason, exitInfoReason);
+ }
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 58732fd..7c0325e 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -124,6 +124,7 @@
import com.android.server.power.stats.BatteryStatsDumpHelperImpl;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.power.stats.BatteryUsageStatsProvider;
+import com.android.server.power.stats.BluetoothPowerStatsProcessor;
import com.android.server.power.stats.CpuPowerStatsProcessor;
import com.android.server.power.stats.MobileRadioPowerStatsProcessor;
import com.android.server.power.stats.PhoneCallPowerStatsProcessor;
@@ -502,6 +503,17 @@
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
.setProcessor(
new WifiPowerStatsProcessor(mPowerProfile));
+
+ config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
+ .setProcessor(
+ new BluetoothPowerStatsProcessor(mPowerProfile));
return config;
}
@@ -563,6 +575,12 @@
BatteryConsumer.POWER_COMPONENT_WIFI,
Flags.streamlinedConnectivityBatteryStats());
+ mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ Flags.streamlinedConnectivityBatteryStats());
+ mBatteryUsageStatsProvider.setPowerStatsExporterEnabled(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ Flags.streamlinedConnectivityBatteryStats());
+
mWorker.systemServicesReady();
mStats.systemServicesReady(mContext);
mCpuWakeupStats.systemServicesReady();
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index 9600317..a67af89 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -84,6 +84,7 @@
import java.util.Arrays;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.ToIntFunction;
/**
* A modern implementation of the oom adjuster.
@@ -271,11 +272,31 @@
// The last node besides the tail.
private final ProcessRecordNode[] mLastNode;
+ private final ToIntFunction<ProcessRecord> mSlotFunction;
+ // Cache of the most important slot with a node in it.
+ private int mFirstPopulatedSlot = 0;
+
ProcessRecordNodes(@ProcessRecordNode.NodeType int type, int size) {
mType = type;
+ final ToIntFunction<ProcessRecord> valueFunction;
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE:
+ valueFunction = (proc) -> proc.mState.getCurProcState();
+ mSlotFunction = (proc) -> processStateToSlot(proc.mState.getCurProcState());
+ break;
+ case ProcessRecordNode.NODE_TYPE_ADJ:
+ valueFunction = (proc) -> proc.mState.getCurRawAdj();
+ mSlotFunction = (proc) -> adjToSlot(proc.mState.getCurRawAdj());
+ break;
+ default:
+ valueFunction = (proc) -> 0;
+ mSlotFunction = (proc) -> 0;
+ break;
+ }
+
mProcessRecordNodes = new LinkedProcessRecordList[size];
for (int i = 0; i < size; i++) {
- mProcessRecordNodes[i] = new LinkedProcessRecordList(type);
+ mProcessRecordNodes[i] = new LinkedProcessRecordList(valueFunction);
}
mLastNode = new ProcessRecordNode[size];
resetLastNodes();
@@ -294,6 +315,11 @@
}
void resetLastNodes() {
+ if (Flags.simplifyProcessTraversal()) {
+ // Last nodes are no longer used. Just reset instead.
+ reset();
+ return;
+ }
for (int i = 0; i < mProcessRecordNodes.length; i++) {
mLastNode[i] = mProcessRecordNodes[i].getLastNodeBeforeTail();
}
@@ -308,6 +334,36 @@
final ProcessRecordNode tail = mProcessRecordNodes[slot].TAIL;
while (node != tail) {
mTmpOomAdjusterArgs.mApp = node.mApp;
+ if (node.mApp == null) {
+ // TODO(b/336178916) - Temporary logging for root causing b/336178916.
+ StringBuilder sb = new StringBuilder();
+ sb.append("Iterating null process during OomAdjuster traversal!!!\n");
+ sb.append("Type:");
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE -> sb.append(
+ "NODE_TYPE_PROC_STATE");
+ case ProcessRecordNode.NODE_TYPE_ADJ -> sb.append("NODE_TYPE_ADJ");
+ default -> sb.append("UNKNOWN");
+ }
+ sb.append(", Slot:");
+ sb.append(slot);
+ sb.append("\nLAST:");
+ ProcessRecordNode last = mLastNode[slot];
+ if (last.mApp == null) {
+ sb.append("null");
+ } else {
+ sb.append(last);
+ sb.append("\nSetProcState:");
+ sb.append(last.mApp.getSetProcState());
+ sb.append(", CurProcState:");
+ sb.append(last.mApp.mState.getCurProcState());
+ sb.append(", SetAdj:");
+ sb.append(last.mApp.getSetAdj());
+ sb.append(", CurRawAdj:");
+ sb.append(last.mApp.mState.getCurRawAdj());
+ }
+ Slog.wtfStack(TAG, sb.toString());
+ }
// Save the next before calling callback, since that may change the node.mNext.
final ProcessRecordNode next = node.mNext;
callback.accept(mTmpOomAdjusterArgs);
@@ -325,6 +381,33 @@
}
}
+ ProcessRecord poll() {
+ ProcessRecordNode node = null;
+ final int size = mProcessRecordNodes.length;
+ // Find the next node.
+ while (node == null && mFirstPopulatedSlot < size) {
+ node = mProcessRecordNodes[mFirstPopulatedSlot].poll();
+ if (node == null) {
+ // This slot is now empty, move on to the next.
+ mFirstPopulatedSlot++;
+ }
+ }
+ if (node == null) return null;
+ return node.mApp;
+ }
+
+ void offer(ProcessRecord proc) {
+ ProcessRecordNode node = proc.mLinkedNodes[mType];
+ // Find which slot to add the node to.
+ final int newSlot = mSlotFunction.applyAsInt(proc);
+ if (newSlot < mFirstPopulatedSlot) {
+ // node is being added to a more important slot.
+ mFirstPopulatedSlot = newSlot;
+ }
+ node.unlink();
+ mProcessRecordNodes[newSlot].offer(node);
+ }
+
int getNumberOfSlots() {
return mProcessRecordNodes.length;
}
@@ -423,12 +506,35 @@
// Sentinel head/tail, to make bookkeeping work easier.
final ProcessRecordNode HEAD = new ProcessRecordNode(null);
final ProcessRecordNode TAIL = new ProcessRecordNode(null);
- final @ProcessRecordNode.NodeType int mNodeType;
+ final ToIntFunction<ProcessRecord> mValueFunction;
- LinkedProcessRecordList(@ProcessRecordNode.NodeType int nodeType) {
+ LinkedProcessRecordList(ToIntFunction<ProcessRecord> valueFunction) {
HEAD.mNext = TAIL;
TAIL.mPrev = HEAD;
- mNodeType = nodeType;
+ mValueFunction = valueFunction;
+ }
+
+ ProcessRecordNode poll() {
+ final ProcessRecordNode next = HEAD.mNext;
+ if (next == TAIL) return null;
+ next.unlink();
+ return next;
+ }
+
+ void offer(@NonNull ProcessRecordNode node) {
+ final int newValue = mValueFunction.applyAsInt(node.mApp);
+
+ // Find the last node with less than or equal value to the new node.
+ ProcessRecordNode curNode = TAIL.mPrev;
+ while (curNode != HEAD && mValueFunction.applyAsInt(curNode.mApp) > newValue) {
+ curNode = curNode.mPrev;
+ }
+
+ // Insert the new node after the found node.
+ node.mPrev = curNode;
+ node.mNext = curNode.mNext;
+ curNode.mNext.mPrev = node;
+ curNode.mNext = node;
}
void append(@NonNull ProcessRecordNode node) {
@@ -727,34 +833,50 @@
private void updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj) {
if (app.mState.getCurRawAdj() != prevRawAdj) {
- final int slot = adjToSlot(app.mState.getCurRawAdj());
- final int prevSlot = adjToSlot(prevRawAdj);
- if (slot != prevSlot && slot != ADJ_SLOT_INVALID) {
- mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ if (Flags.simplifyProcessTraversal()) {
+ mProcessRecordAdjNodes.offer(app);
+ } else {
+ final int slot = adjToSlot(app.mState.getCurRawAdj());
+ final int prevSlot = adjToSlot(prevRawAdj);
+ if (slot != prevSlot && slot != ADJ_SLOT_INVALID) {
+ mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ }
}
}
}
private void updateAdjSlot(ProcessRecord app, int prevRawAdj) {
- final int slot = adjToSlot(app.mState.getCurRawAdj());
- final int prevSlot = adjToSlot(prevRawAdj);
- mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ if (Flags.simplifyProcessTraversal()) {
+ mProcessRecordAdjNodes.offer(app);
+ } else {
+ final int slot = adjToSlot(app.mState.getCurRawAdj());
+ final int prevSlot = adjToSlot(prevRawAdj);
+ mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ }
}
private void updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState) {
if (app.mState.getCurProcState() != prevProcState) {
- final int slot = processStateToSlot(app.mState.getCurProcState());
- final int prevSlot = processStateToSlot(prevProcState);
- if (slot != prevSlot) {
- mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ if (Flags.simplifyProcessTraversal()) {
+ mProcessRecordProcStateNodes.offer(app);
+ } else {
+ final int slot = processStateToSlot(app.mState.getCurProcState());
+ final int prevSlot = processStateToSlot(prevProcState);
+ if (slot != prevSlot) {
+ mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ }
}
}
}
private void updateProcStateSlot(ProcessRecord app, int prevProcState) {
- final int slot = processStateToSlot(app.mState.getCurProcState());
- final int prevSlot = processStateToSlot(prevProcState);
- mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ if (Flags.simplifyProcessTraversal()) {
+ mProcessRecordProcStateNodes.offer(app);
+ } else {
+ final int slot = processStateToSlot(app.mState.getCurProcState());
+ final int prevSlot = processStateToSlot(prevProcState);
+ mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ }
}
@Override
@@ -832,8 +954,15 @@
// Compute initial values, the procState and adj priority queues will be populated here.
computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now, false, false, oomAdjReason,
false);
- updateProcStateSlot(app, prevProcState);
- updateAdjSlot(app, prevAdj);
+
+ if (Flags.simplifyProcessTraversal()) {
+ // Just add to the procState priority queue. The adj priority queue should be
+ // empty going into the traversal step.
+ mProcessRecordProcStateNodes.offer(app);
+ } else {
+ updateProcStateSlot(app, prevProcState);
+ updateAdjSlot(app, prevAdj);
+ }
}
// Set adj last nodes now, this way a process will only be reevaluated during the adj node
@@ -851,14 +980,32 @@
*/
@GuardedBy({"mService", "mProcLock"})
private void computeConnectionsLSP() {
- // 1st pass, scan each slot in the procstate node list.
- for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) {
- mProcessRecordProcStateNodes.forEachNewNode(i, mComputeConnectionsConsumer);
- }
+ if (Flags.simplifyProcessTraversal()) {
+ // 1st pass, iterate all nodes in order of procState importance.
+ ProcessRecord proc = mProcessRecordProcStateNodes.poll();
+ while (proc != null) {
+ mTmpOomAdjusterArgs.mApp = proc;
+ mComputeConnectionsConsumer.accept(mTmpOomAdjusterArgs);
+ proc = mProcessRecordProcStateNodes.poll();
+ }
- // 2nd pass, scan each slot in the adj node list.
- for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) {
- mProcessRecordAdjNodes.forEachNewNode(i, mComputeConnectionsConsumer);
+ // 2st pass, iterate all nodes in order of procState importance.
+ proc = mProcessRecordAdjNodes.poll();
+ while (proc != null) {
+ mTmpOomAdjusterArgs.mApp = proc;
+ mComputeConnectionsConsumer.accept(mTmpOomAdjusterArgs);
+ proc = mProcessRecordAdjNodes.poll();
+ }
+ } else {
+ // 1st pass, scan each slot in the procstate node list.
+ for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) {
+ mProcessRecordProcStateNodes.forEachNewNode(i, mComputeConnectionsConsumer);
+ }
+
+ // 2nd pass, scan each slot in the adj node list.
+ for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) {
+ mProcessRecordAdjNodes.forEachNewNode(i, mComputeConnectionsConsumer);
+ }
}
}
@@ -987,8 +1134,14 @@
args.mApp = reachable;
computeOomAdjIgnoringReachablesLSP(args);
- updateProcStateSlot(reachable, prevProcState);
- updateAdjSlot(reachable, prevAdj);
+ if (Flags.simplifyProcessTraversal()) {
+ // Just add to the procState priority queue. The adj priority queue should be
+ // empty going into the traversal step.
+ mProcessRecordProcStateNodes.offer(reachable);
+ } else {
+ updateProcStateSlot(reachable, prevProcState);
+ updateAdjSlot(reachable, prevAdj);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a5449a0..6779f7a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -37,7 +37,6 @@
import static android.system.OsConstants.EAGAIN;
import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxAudit;
-import static com.android.sdksandbox.flags.Flags.selinuxSdkSandboxInputSelector;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
@@ -2066,15 +2065,11 @@
}
}
- if (selinuxSdkSandboxInputSelector()) {
- return app.info.seInfo + extraInfo + TextUtils.emptyIfNull(app.info.seInfoUser);
- } else {
- return app.info.seInfo
- + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser)
- + extraInfo;
- }
+ return app.info.seInfo
+ + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser) + extraInfo;
}
+
@GuardedBy("mService")
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 5793758..032093b 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -157,6 +157,7 @@
"car_telemetry",
"codec_fwk",
"companion",
+ "com_android_adbd",
"content_protection",
"context_hub",
"core_experiments_team_internal",
@@ -341,33 +342,29 @@
AsyncTask.THREAD_POOL_EXECUTOR,
(DeviceConfig.Properties properties) -> {
- HashMap<String, HashMap<String, String>> propsToStage =
- getStagedFlagsWithValueChange(properties);
-
- // send prop stage request to sys prop
- for (HashMap.Entry<String, HashMap<String, String>> entry : propsToStage.entrySet()) {
- String actualNamespace = entry.getKey();
- HashMap<String, String> flagValuesToStage = entry.getValue();
-
- for (String flagName : flagValuesToStage.keySet()) {
- String stagedValue = flagValuesToStage.get(flagName);
- String propertyName = "next_boot." + makeAconfigFlagPropertyName(
- actualNamespace, flagName);
-
- if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX)
- || propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) {
- logErr("unable to construct system property for " + actualNamespace
- + "/" + flagName);
- continue;
+ for (String flagName : properties.getKeyset()) {
+ String flagValue = properties.getString(flagName, null);
+ if (flagName == null || flagValue == null) {
+ continue;
}
- setProperty(propertyName, stagedValue);
- }
+ int idx = flagName.indexOf(NAMESPACE_REBOOT_STAGING_DELIMITER);
+ if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
+ logErr("invalid staged flag: " + flagName);
+ continue;
+ }
+
+ String actualNamespace = flagName.substring(0, idx);
+ String actualFlagName = flagName.substring(idx+1);
+ String propertyName = "next_boot." + makeAconfigFlagPropertyName(
+ actualNamespace, actualFlagName);
+
+ setProperty(propertyName, flagValue);
}
// send prop stage request to new storage
if (enableAconfigStorageDaemon()) {
- stageFlagsInNewStorage(propsToStage);
+ stageFlagsInNewStorage(properties);
}
});
@@ -606,25 +603,33 @@
* @param propsToStage
*/
@VisibleForTesting
- static void stageFlagsInNewStorage(HashMap<String, HashMap<String, String>> propsToStage) {
+ static void stageFlagsInNewStorage(DeviceConfig.Properties props) {
// write aconfigd requests proto to proto output stream
int num_requests = 0;
ProtoOutputStream requests = new ProtoOutputStream();
- for (HashMap.Entry<String, HashMap<String, String>> entry : propsToStage.entrySet()) {
- String actualNamespace = entry.getKey();
- HashMap<String, String> flagValuesToStage = entry.getValue();
- for (String fullFlagName : flagValuesToStage.keySet()) {
- String stagedValue = flagValuesToStage.get(fullFlagName);
- int idx = fullFlagName.lastIndexOf(".");
- if (idx == -1) {
- logErr("invalid flag name: " + fullFlagName);
- continue;
- }
- String packageName = fullFlagName.substring(0, idx);
- String flagName = fullFlagName.substring(idx+1);
- writeFlagOverrideRequest(requests, packageName, flagName, stagedValue, false);
- ++num_requests;
+ for (String flagName : props.getKeyset()) {
+ String flagValue = props.getString(flagName, null);
+ if (flagName == null || flagValue == null) {
+ continue;
}
+
+ int idx = flagName.indexOf("*");
+ if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
+ logErr("invalid local flag override: " + flagName);
+ continue;
+ }
+ String actualNamespace = flagName.substring(0, idx);
+ String fullFlagName = flagName.substring(idx+1);
+
+ idx = fullFlagName.lastIndexOf(".");
+ if (idx == -1) {
+ logErr("invalid flag name: " + fullFlagName);
+ continue;
+ }
+ String packageName = fullFlagName.substring(0, idx);
+ String realFlagName = fullFlagName.substring(idx+1);
+ writeFlagOverrideRequest(requests, packageName, realFlagName, flagValue, false);
+ ++num_requests;
}
if (num_requests == 0) {
@@ -636,7 +641,7 @@
// deserialize back using proto input stream
try {
- parseAndLogAconfigdReturn(returns);
+ parseAndLogAconfigdReturn(returns);
} catch (IOException ioe) {
logErr("failed to parse aconfigd return", ioe);
}
@@ -664,63 +669,6 @@
return propertyName;
}
- /**
- * Get the flags that need to be staged in sys prop, only these with a real value
- * change needs to be staged in sys prop. Otherwise, the flag stage is useless and
- * create performance problem at sys prop side.
- * @param properties
- * @return a hash map of namespace name to actual flags to stage
- */
- @VisibleForTesting
- static HashMap<String, HashMap<String, String>> getStagedFlagsWithValueChange(
- DeviceConfig.Properties properties) {
-
- // sort flags by actual namespace of the flag
- HashMap<String, HashMap<String, String>> stagedProps = new HashMap<>();
- for (String flagName : properties.getKeyset()) {
- int idx = flagName.indexOf(NAMESPACE_REBOOT_STAGING_DELIMITER);
- if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
- logErr("invalid staged flag: " + flagName);
- continue;
- }
- String actualNamespace = flagName.substring(0, idx);
- String actualFlagName = flagName.substring(idx+1);
- HashMap<String, String> flagStagedValues = stagedProps.get(actualNamespace);
- if (flagStagedValues == null) {
- flagStagedValues = new HashMap<String, String>();
- stagedProps.put(actualNamespace, flagStagedValues);
- }
- flagStagedValues.put(actualFlagName, properties.getString(flagName, null));
- }
-
- // for each namespace, find flags with real flag value change
- HashMap<String, HashMap<String, String>> propsToStage = new HashMap<>();
- for (HashMap.Entry<String, HashMap<String, String>> entry : stagedProps.entrySet()) {
- String actualNamespace = entry.getKey();
- HashMap<String, String> flagStagedValues = entry.getValue();
- Map<String, String> flagCurrentValues = Settings.Config.getStrings(
- actualNamespace, new ArrayList<String>(flagStagedValues.keySet()));
-
- HashMap<String, String> flagsToStage = new HashMap<>();
- for (String flagName : flagStagedValues.keySet()) {
- String stagedValue = flagStagedValues.get(flagName);
- String currentValue = flagCurrentValues.get(flagName);
- if (stagedValue == null) {
- continue;
- }
- if (currentValue == null || !stagedValue.equalsIgnoreCase(currentValue)) {
- flagsToStage.put(flagName, stagedValue);
- }
- }
-
- if (!flagsToStage.isEmpty()) {
- propsToStage.put(actualNamespace, flagsToStage);
- }
- }
-
- return propsToStage;
- }
-
private void setProperty(String key, String value) {
// Check if need to clear the property
if (value == null) {
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index b7108df..afde4f7 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -123,3 +123,14 @@
description: "Avoid OomAdjuster calculations for connections that won't change importance"
bug: "323376416"
}
+
+flag {
+ name: "simplify_process_traversal"
+ namespace: "backstage_power"
+ description: "Simplify the OomAdjuster's process traversal mechanism."
+ bug: "336178916"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index ad93f6f..1acd300 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1110,12 +1110,12 @@
final String changedPkg = changedPkgs[i];
// We trust packagemanager to insert matching uid and packageNames in the
// extras
- Set<String> devices;
+ Set<String> devices = new ArraySet<>();
+ devices.add(PERSISTENT_DEVICE_ID_DEFAULT);
+
if (mVirtualDeviceManagerInternal != null) {
- devices = mVirtualDeviceManagerInternal.getAllPersistentDeviceIds();
- } else {
- devices = new ArraySet<>();
- devices.add(PERSISTENT_DEVICE_ID_DEFAULT);
+ devices.addAll(
+ mVirtualDeviceManagerInternal.getAllPersistentDeviceIds());
}
for (String device: devices) {
notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg,
@@ -1549,6 +1549,9 @@
final SparseLongArray chainsToFinish = new SparseLongArray();
doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> {
attributedOp.doForAllInProgressStartOpEvents((event) -> {
+ if (event == null) {
+ return;
+ }
int chainId = event.getAttributionChainId();
if (chainId != ATTRIBUTION_CHAIN_ID_NONE) {
long currentEarliestStartTime =
@@ -2609,12 +2612,10 @@
ArrayList<ChangeRec> reports = ent.getValue();
for (int i=0; i<reports.size(); i++) {
ChangeRec rep = reports.get(i);
- Set<String> devices;
+ Set<String> devices = new ArraySet<>();
+ devices.add(PERSISTENT_DEVICE_ID_DEFAULT);
if (mVirtualDeviceManagerInternal != null) {
- devices = mVirtualDeviceManagerInternal.getAllPersistentDeviceIds();
- } else {
- devices = new ArraySet<>();
- devices.add(PERSISTENT_DEVICE_ID_DEFAULT);
+ devices.addAll(mVirtualDeviceManagerInternal.getAllPersistentDeviceIds());
}
for (String device: devices) {
mHandler.sendMessage(PooledLambda.obtainMessage(
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 02fc993..8cf47d0 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LongSparseArray;
import android.util.Pools;
import android.util.Slog;
@@ -265,8 +266,9 @@
}
int numStartedOps = events.size();
+ ArraySet<IBinder> keys = new ArraySet<>(events.keySet());
for (int i = 0; i < numStartedOps; i++) {
- action.accept(events.valueAt(i));
+ action.accept(events.get(keys.valueAt(i)));
}
}
@@ -649,7 +651,7 @@
accessEvents.append(makeKey(event.getUidState(), event.getFlags()),
new AppOpsManager.NoteOpEvent(event.getStartTime(),
- now - event.getStartElapsedTime(),
+ Math.max(now - event.getStartElapsedTime(), 0),
event.getProxy()));
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 475334c..1dc1846 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1439,7 +1439,6 @@
sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
}
- @GuardedBy("mDeviceStateLock")
/*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) {
sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 15c5c10..7deef2f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7897,7 +7897,7 @@
+ previousDevice + " -> " + newDevice + ". Got: " + profile);
}
- sDeviceLogger.enqueue(new EventLogger.StringEvent("BlutoothActiveDeviceChanged for "
+ sDeviceLogger.enqueue(new EventLogger.StringEvent("BluetoothActiveDeviceChanged for "
+ BluetoothProfile.getProfileName(profile) + ", device update " + previousDevice
+ " -> " + newDevice).printLog(TAG));
AudioDeviceBroker.BtDeviceChangedData data =
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index a649d34..07daecd 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -289,6 +289,7 @@
Log.e(TAG, "Exception while getting status of " + device, e);
}
if (btCodecStatus == null) {
+ Log.e(TAG, "getCodec, null A2DP codec status for device: " + device);
mA2dpCodecConfig = null;
return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
@@ -316,6 +317,7 @@
Log.e(TAG, "Exception while getting status of " + device, e);
}
if (btLeCodecStatus == null) {
+ Log.e(TAG, "getCodec, null LE codec status for device: " + device);
mLeAudioCodecConfig = null;
return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
@@ -363,6 +365,7 @@
return new Pair<>(profile == BluetoothProfile.A2DP
? AudioSystem.AUDIO_FORMAT_SBC : AudioSystem.AUDIO_FORMAT_LC3, true);
}
+
return codecAndChanged;
}
@@ -653,7 +656,7 @@
// Not a valid profile to connect
Log.e(TAG, "onBtProfileConnected: Not a valid profile to connect "
+ BluetoothProfile.getProfileName(profile));
- break;
+ return;
}
// this part is only for A2DP, LE Audio unicast and Hearing aid
@@ -664,17 +667,65 @@
return;
}
List<BluetoothDevice> activeDevices = adapter.getActiveDevices(profile);
- BluetoothProfileConnectionInfo bpci = new BluetoothProfileConnectionInfo(profile);
- for (BluetoothDevice device : activeDevices) {
- if (device == null) {
- continue;
- }
- AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData(
- device, null, bpci, "mBluetoothProfileServiceListener");
- AudioDeviceBroker.BtDeviceInfo info = mDeviceBroker.createBtDeviceInfo(
- data, device, BluetoothProfile.STATE_CONNECTED);
- mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */);
+ if (activeDevices.isEmpty() || activeDevices.get(0) == null) {
+ return;
}
+ BluetoothDevice device = activeDevices.get(0);
+ switch (profile) {
+ case BluetoothProfile.A2DP: {
+ BluetoothProfileConnectionInfo bpci =
+ BluetoothProfileConnectionInfo.createA2dpInfo(false, -1);
+ postBluetoothActiveDevice(device, bpci);
+ } break;
+ case BluetoothProfile.HEARING_AID: {
+ BluetoothProfileConnectionInfo bpci =
+ BluetoothProfileConnectionInfo.createHearingAidInfo(false);
+ postBluetoothActiveDevice(device, bpci);
+ } break;
+ case BluetoothProfile.LE_AUDIO: {
+ int groupId = mLeAudio.getGroupId(device);
+ BluetoothLeAudioCodecStatus btLeCodecStatus = null;
+ try {
+ btLeCodecStatus = mLeAudio.getCodecStatus(groupId);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting status of " + device, e);
+ }
+ if (btLeCodecStatus == null) {
+ Log.i(TAG, "onBtProfileConnected null LE codec status for groupId: "
+ + groupId + ", device: " + device);
+ break;
+ }
+ List<BluetoothLeAudioCodecConfig> outputCodecConfigs =
+ btLeCodecStatus.getOutputCodecSelectableCapabilities();
+ if (!outputCodecConfigs.isEmpty()) {
+ BluetoothProfileConnectionInfo bpci =
+ BluetoothProfileConnectionInfo.createLeAudioInfo(
+ false /*suppressNoisyIntent*/, true /*isLeOutput*/);
+ postBluetoothActiveDevice(device, bpci);
+ }
+ List<BluetoothLeAudioCodecConfig> inputCodecConfigs =
+ btLeCodecStatus.getInputCodecSelectableCapabilities();
+ if (!inputCodecConfigs.isEmpty()) {
+ BluetoothProfileConnectionInfo bpci =
+ BluetoothProfileConnectionInfo.createLeAudioInfo(
+ false /*suppressNoisyIntent*/, false /*isLeOutput*/);
+ postBluetoothActiveDevice(device, bpci);
+ }
+ } break;
+ default:
+ // Not a valid profile to connect
+ Log.wtf(TAG, "Invalid profile! onBtProfileConnected");
+ break;
+ }
+ }
+
+ private void postBluetoothActiveDevice(
+ BluetoothDevice device, BluetoothProfileConnectionInfo bpci) {
+ AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData(
+ device, null, bpci, "mBluetoothProfileServiceListener");
+ AudioDeviceBroker.BtDeviceInfo info = mDeviceBroker.createBtDeviceInfo(
+ data, device, BluetoothProfile.STATE_CONNECTED);
+ mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */);
}
/*package*/ synchronized boolean isProfilePoxyConnected(int profile) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index eaa5e2a..53e6bdb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -238,7 +238,7 @@
showNotificationHelper(context, name, title, content, setupPendingIntent, setupAction,
notNowAction, Notification.CATEGORY_SYSTEM, channel, tag,
- Notification.VISIBILITY_SECRET, false);
+ Notification.VISIBILITY_SECRET, false, Notification.FLAG_NO_CLEAR);
}
private static String getFingerprintDanglingContentString(Context context,
@@ -296,13 +296,13 @@
String notificationTag, int visibility, boolean listenToDismissEvent) {
showNotificationHelper(context, name, title, content, pendingIntent,
null /* positiveAction */, null /* negativeAction */, category, channelName,
- notificationTag, visibility, listenToDismissEvent);
+ notificationTag, visibility, listenToDismissEvent, 0);
}
private static void showNotificationHelper(Context context, String name, String title,
String content, PendingIntent pendingIntent, Notification.Action positiveAction,
Notification.Action negativeAction, String category, String channelName,
- String notificationTag, int visibility, boolean listenToDismissEvent) {
+ String notificationTag, int visibility, boolean listenToDismissEvent, int flags) {
Slog.v(TAG," listenToDismissEvent = " + listenToDismissEvent);
final PendingIntent dismissIntent = PendingIntent.getActivityAsUser(context,
0 /* requestCode */, DISMISS_FRR_INTENT, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -324,6 +324,9 @@
.setContentIntent(pendingIntent)
.setVisibility(visibility);
+ if (flags > 0) {
+ builder.setFlag(flags, true);
+ }
if (positiveAction != null) {
builder.addAction(positiveAction);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index d64b6c2..8dc560b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -20,6 +20,9 @@
import android.content.Context;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
+import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.fingerprint.EnrollmentProgressStep;
+import android.hardware.biometrics.fingerprint.NextEnrollment;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
@@ -46,6 +49,7 @@
class BiometricTestSessionImpl extends ITestSession.Stub {
private static final String TAG = "fp/aidl/BiometricTestSessionImpl";
+ private static final int VHAL_ENROLLMENT_ID = 9999;
@NonNull private final Context mContext;
private final int mSensorId;
@@ -140,8 +144,8 @@
super.setTestHalEnabled_enforcePermission();
- mProvider.setTestHalEnabled(enabled);
mSensor.setTestHalEnabled(enabled);
+ mProvider.setTestHalEnabled(enabled);
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@@ -157,10 +161,31 @@
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
- public void finishEnroll(int userId) {
+ public void finishEnroll(int userId) throws RemoteException {
super.finishEnroll_enforcePermission();
+ Slog.i(TAG, "finishEnroll(): useVhalForTesting=" + mProvider.useVhalForTesting());
+ if (mProvider.useVhalForTesting()) {
+ final AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes =
+ {new AcquiredInfoAndVendorCode()};
+ final EnrollmentProgressStep[] enrollmentProgressSteps =
+ {new EnrollmentProgressStep(), new EnrollmentProgressStep()};
+ enrollmentProgressSteps[0].durationMs = 100;
+ enrollmentProgressSteps[0].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes;
+ enrollmentProgressSteps[1].durationMs = 200;
+ enrollmentProgressSteps[1].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes;
+
+ final NextEnrollment nextEnrollment = new NextEnrollment();
+ nextEnrollment.id = VHAL_ENROLLMENT_ID;
+ nextEnrollment.progressSteps = enrollmentProgressSteps;
+ nextEnrollment.result = true;
+ mProvider.getVhal().setNextEnrollment(nextEnrollment);
+ mProvider.simulateVhalFingerDown(userId, mSensorId);
+ return;
+ }
+
+ //TODO (b341889971): delete the following lines when b/341889971 is resolved
int nextRandomId = mRandom.nextInt();
while (mEnrollmentIds.contains(nextRandomId)) {
nextRandomId = mRandom.nextInt();
@@ -173,11 +198,18 @@
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
- public void acceptAuthentication(int userId) {
+ public void acceptAuthentication(int userId) throws RemoteException {
// Fake authentication with any of the existing fingers
super.acceptAuthentication_enforcePermission();
+ if (mProvider.useVhalForTesting()) {
+ mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID);
+ mProvider.simulateVhalFingerDown(userId, mSensorId);
+ return;
+ }
+
+ //TODO (b341889971): delete the following lines when b/341889971 is resolved
List<Fingerprint> fingerprints = FingerprintUtils.getInstance(mSensorId)
.getBiometricsForUser(mContext, userId);
if (fingerprints.isEmpty()) {
@@ -191,10 +223,17 @@
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
- public void rejectAuthentication(int userId) {
+ public void rejectAuthentication(int userId) throws RemoteException {
super.rejectAuthentication_enforcePermission();
+ if (mProvider.useVhalForTesting()) {
+ mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID + 1);
+ mProvider.simulateVhalFingerDown(userId, mSensorId);
+ return;
+ }
+
+ //TODO (b341889971): delete the following lines when b/341889971 is resolved
mSensor.getSessionForUser(userId).getHalSessionCallback().onAuthenticationFailed();
}
@@ -220,11 +259,17 @@
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
- public void cleanupInternalState(int userId) {
+ public void cleanupInternalState(int userId) throws RemoteException {
super.cleanupInternalState_enforcePermission();
Slog.d(TAG, "cleanupInternalState: " + userId);
+
+ if (mProvider.useVhalForTesting()) {
+ Slog.i(TAG, "cleanup virtualhal configurations");
+ mProvider.getVhal().resetConfigurations(); //setEnrollments(new int[]{});
+ }
+
mProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -248,4 +293,4 @@
}
});
}
-}
+}
\ No newline at end of file
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 c0dcd49..1bddb83b 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
@@ -890,7 +890,13 @@
}
void setTestHalEnabled(boolean enabled) {
+ final boolean changed = enabled != mTestHalEnabled;
mTestHalEnabled = enabled;
+ Slog.i(getTag(), "setTestHalEnabled(): useVhalForTesting=" + Flags.useVhalForTesting()
+ + "mTestHalEnabled=" + mTestHalEnabled + " changed=" + changed);
+ if (changed && useVhalForTesting()) {
+ getHalInstance();
+ }
}
public boolean getTestHalEnabled() {
@@ -982,7 +988,7 @@
if (mVhal == null && useVhalForTesting()) {
mVhal = IVirtualHal.Stub.asInterface(mDaemon.asBinder().getExtension());
if (mVhal == null) {
- Slog.e(getTag(), "Unable to get virtual hal interface");
+ Slog.e(getTag(), "Unable to get fingerprint virtualhal interface");
}
}
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index c26118e..5690a9e 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -135,7 +135,7 @@
float[] alternativeRefreshRates,
@Display.HdrCapabilities.HdrType int[] supportedHdrTypes) {
return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate,
- vsyncRate, alternativeRefreshRates, supportedHdrTypes);
+ vsyncRate, false, alternativeRefreshRates, supportedHdrTypes);
}
public interface Listener {
diff --git a/services/core/java/com/android/server/display/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
index fa8299b..38eb416 100644
--- a/services/core/java/com/android/server/display/DisplayControl.java
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -28,9 +28,9 @@
* Calls into SurfaceFlinger for Display creation and deletion.
*/
public class DisplayControl {
- private static native IBinder nativeCreateDisplay(String name, boolean secure,
+ private static native IBinder nativeCreateVirtualDisplay(String name, boolean secure,
String uniqueId, float requestedRefreshRate);
- private static native void nativeDestroyDisplay(IBinder displayToken);
+ private static native void nativeDestroyVirtualDisplay(IBinder displayToken);
private static native void nativeOverrideHdrTypes(IBinder displayToken, int[] modes);
private static native long[] nativeGetPhysicalDisplayIds();
private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
@@ -41,21 +41,21 @@
private static native boolean nativeGetHdrOutputConversionSupport();
/**
- * Create a display in SurfaceFlinger.
+ * Create a virtual display in SurfaceFlinger.
*
- * @param name The name of the display.
+ * @param name The name of the virtual display.
* @param secure Whether this display is secure.
* @return The token reference for the display in SurfaceFlinger.
*/
- public static IBinder createDisplay(String name, boolean secure) {
+ public static IBinder createVirtualDisplay(String name, boolean secure) {
Objects.requireNonNull(name, "name must not be null");
- return nativeCreateDisplay(name, secure, "", 0.0f);
+ return nativeCreateVirtualDisplay(name, secure, "", 0.0f);
}
/**
- * Create a display in SurfaceFlinger.
+ * Create a virtual display in SurfaceFlinger.
*
- * @param name The name of the display.
+ * @param name The name of the virtual display.
* @param secure Whether this display is secure.
* @param uniqueId The unique ID for the display.
* @param requestedRefreshRate The requested refresh rate in frames per second.
@@ -65,23 +65,23 @@
* display is refreshed at the physical display refresh rate.
* @return The token reference for the display in SurfaceFlinger.
*/
- public static IBinder createDisplay(String name, boolean secure,
+ public static IBinder createVirtualDisplay(String name, boolean secure,
String uniqueId, float requestedRefreshRate) {
Objects.requireNonNull(name, "name must not be null");
Objects.requireNonNull(uniqueId, "uniqueId must not be null");
- return nativeCreateDisplay(name, secure, uniqueId, requestedRefreshRate);
+ return nativeCreateVirtualDisplay(name, secure, uniqueId, requestedRefreshRate);
}
/**
- * Destroy a display in SurfaceFlinger.
+ * Destroy a virtual display in SurfaceFlinger.
*
- * @param displayToken The display token for the display to be destroyed.
+ * @param displayToken The display token for the virtual display to be destroyed.
*/
- public static void destroyDisplay(IBinder displayToken) {
+ public static void destroyVirtualDisplay(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- nativeDestroyDisplay(displayToken);
+ nativeDestroyVirtualDisplay(displayToken);
}
/**
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 189e366..5d55d190 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -35,6 +35,7 @@
import com.android.server.display.layout.Layout;
import com.android.server.display.mode.DisplayModeDirector;
+import com.android.server.display.mode.SyntheticModeManager;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
@@ -408,7 +409,8 @@
*
* @param deviceRepo Repository of active {@link DisplayDevice}s.
*/
- public void updateLocked(DisplayDeviceRepository deviceRepo) {
+ public void updateLocked(DisplayDeviceRepository deviceRepo,
+ SyntheticModeManager syntheticModeManager) {
// Nothing to update if already invalid.
if (mPrimaryDisplayDevice == null) {
return;
@@ -426,6 +428,7 @@
// logical display that they are sharing. (eg. Adjust size for pixel-perfect
// mirroring over HDMI.)
DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
+ DisplayDeviceConfig config = mPrimaryDisplayDevice.getDisplayDeviceConfig();
if (!Objects.equals(mPrimaryDisplayDeviceInfo, deviceInfo) || mDirty) {
mBaseDisplayInfo.layerStack = mLayerStack;
mBaseDisplayInfo.flags = 0;
@@ -507,6 +510,9 @@
mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
deviceInfo.supportedModes, deviceInfo.supportedModes.length);
+ mBaseDisplayInfo.appsSupportedModes = syntheticModeManager.createAppSupportedModes(
+ config, mBaseDisplayInfo.supportedModes
+ );
mBaseDisplayInfo.colorMode = deviceInfo.colorMode;
mBaseDisplayInfo.supportedColorModes = Arrays.copyOf(
deviceInfo.supportedColorModes,
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index bca53cf..01485cb 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -45,6 +45,7 @@
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
+import com.android.server.display.mode.SyntheticModeManager;
import com.android.server.display.utils.DebugUtils;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.utils.FoldSettingProvider;
@@ -204,6 +205,7 @@
private boolean mBootCompleted = false;
private boolean mInteractive;
private final DisplayManagerFlags mFlags;
+ private final SyntheticModeManager mSyntheticModeManager;
LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
FoldGracePeriodProvider foldGracePeriodProvider,
@@ -213,7 +215,8 @@
this(context, foldSettingProvider, foldGracePeriodProvider, repo, listener, syncRoot,
handler,
new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
- : sNextNonDefaultDisplayId++, flags), flags);
+ : sNextNonDefaultDisplayId++, flags), flags,
+ new SyntheticModeManager(flags));
}
LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
@@ -221,7 +224,7 @@
@NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
@NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap,
- DisplayManagerFlags flags) {
+ DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager) {
mSyncRoot = syncRoot;
mPowerManager = context.getSystemService(PowerManager.class);
mInteractive = mPowerManager.isInteractive();
@@ -241,6 +244,7 @@
mDisplayDeviceRepo.addListener(this);
mDeviceStateToLayoutMap = deviceStateToLayoutMap;
mFlags = flags;
+ mSyntheticModeManager = syntheticModeManager;
}
@Override
@@ -737,7 +741,7 @@
mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
- display.updateLocked(mDisplayDeviceRepo);
+ display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager);
final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked();
final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW);
final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW;
@@ -1177,7 +1181,7 @@
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device,
mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(),
mFlags.isAlwaysRotateDisplayDeviceEnabled());
- display.updateLocked(mDisplayDeviceRepo);
+ display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager);
final DisplayInfo info = display.getDisplayInfoLocked();
if (info.type == Display.TYPE_INTERNAL && mDeviceStateToLayoutMap.size() > 1) {
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 22ff2d0..eb76dcb 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -309,7 +309,7 @@
mSurface.release();
mSurface = null;
}
- DisplayControl.destroyDisplay(getDisplayTokenLocked());
+ DisplayControl.destroyVirtualDisplay(getDisplayTokenLocked());
}
@Override
@@ -467,7 +467,7 @@
public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
long presentationDeadlineNanos, int state) {
synchronized (getSyncRoot()) {
- IBinder displayToken = DisplayControl.createDisplay(mName, mFlags.mSecure);
+ IBinder displayToken = DisplayControl.createVirtualDisplay(mName, mFlags.mSecure);
mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,
DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,
mFlags, state, surfaceTexture, mNumber) {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a29e852..1a5c79f 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -94,12 +94,13 @@
@Override
public IBinder createDisplay(String name, boolean secure, String uniqueId,
float requestedRefreshRate) {
- return DisplayControl.createDisplay(name, secure, uniqueId, requestedRefreshRate);
+ return DisplayControl.createVirtualDisplay(name, secure, uniqueId,
+ requestedRefreshRate);
}
@Override
public void destroyDisplay(IBinder displayToken) {
- DisplayControl.destroyDisplay(displayToken);
+ DisplayControl.destroyVirtualDisplay(displayToken);
}
}, featureFlags);
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index aa98cd8..607c5d6 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -392,9 +392,9 @@
float refreshRate = 60.0f; // TODO: get this for real
- String name = display.getFriendlyDisplayName();
- String address = display.getDeviceAddress();
- IBinder displayToken = DisplayControl.createDisplay(name, secure);
+ final String name = display.getFriendlyDisplayName();
+ final String address = display.getDeviceAddress();
+ IBinder displayToken = DisplayControl.createVirtualDisplay(name, secure);
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
refreshRate, deviceFlags, address, surface);
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
@@ -631,7 +631,7 @@
mSurface.release();
mSurface = null;
}
- DisplayControl.destroyDisplay(getDisplayTokenLocked());
+ DisplayControl.destroyVirtualDisplay(getDisplayTokenLocked());
}
public void setNameLocked(String name) {
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index f809a49..37b6931 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -165,9 +165,8 @@
public boolean isAutoBrightnessValid() {
boolean isValid = false;
if (isAutoBrightnessEnabled()) {
- float brightness = (mAutomaticBrightnessController != null)
- ? mAutomaticBrightnessController.getAutomaticScreenBrightness(null)
- : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ float brightness = getAutomaticScreenBrightness(null,
+ /* isAutomaticBrightnessAdjusted = */ false);
if (BrightnessUtils.isValidBrightnessValue(brightness)
|| brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) {
isValid = true;
@@ -274,7 +273,12 @@
BrightnessReason brightnessReason = new BrightnessReason();
brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC);
BrightnessEvent brightnessEvent = mInjector.getBrightnessEvent(mDisplayId);
- float brightness = getAutomaticScreenBrightness(brightnessEvent);
+
+ // AutoBrightness adjustments were already applied while checking the validity of this
+ // strategy. Reapplying them again will result in incorrect adjustment reason flags as we
+ // might end up assuming no adjustments are applied
+ float brightness = getAutomaticScreenBrightness(brightnessEvent,
+ /* isAutomaticBrightnessAdjusted = */ true);
return new DisplayBrightnessState.Builder()
.setBrightness(brightness)
.setSdrBrightness(brightness)
@@ -355,11 +359,14 @@
* @param brightnessEvent Event object to populate with details about why the specific
* brightness was chosen.
*/
- public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
+ public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent,
+ boolean isAutomaticBrightnessAdjusted) {
float brightness = (mAutomaticBrightnessController != null)
? mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent)
: PowerManager.BRIGHTNESS_INVALID_FLOAT;
- adjustAutomaticBrightnessStateIfValid(brightness);
+ if (!isAutomaticBrightnessAdjusted) {
+ adjustAutomaticBrightnessStateIfValid(brightness);
+ }
return brightness;
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index cd07f5a..a5414fc 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -164,6 +164,11 @@
Flags::ignoreAppPreferredRefreshRateRequest
);
+ private final FlagState mSynthetic60hzModes = new FlagState(
+ Flags.FLAG_ENABLE_SYNTHETIC_60HZ_MODES,
+ Flags::enableSynthetic60hzModes
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -333,6 +338,10 @@
return mIgnoreAppPreferredRefreshRate.isEnabled();
}
+ public boolean isSynthetic60HzModesEnabled() {
+ return mSynthetic60hzModes.isEnabled();
+ }
+
/**
* dumps all flagstates
* @param pw printWriter
@@ -365,6 +374,8 @@
pw.println(" " + mResolutionBackupRestore);
pw.println(" " + mUseFusionProxSensor);
pw.println(" " + mPeakRefreshRatePhysicalLimit);
+ pw.println(" " + mIgnoreAppPreferredRefreshRate);
+ pw.println(" " + mSynthetic60hzModes);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index a15a8e8..316b6db 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -266,3 +266,15 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_synthetic_60hz_modes"
+ namespace: "display_manager"
+ description: "Feature flag for DisplayManager to enable synthetic 60Hz modes for vrr displays"
+ bug: "338183249"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
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 846ee23..e20ac73 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -147,6 +147,9 @@
// A map from the display ID to the supported modes on that display.
private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
+ // A map from the display ID to the app supported modes on that display, might be different from
+ // mSupportedModesByDisplay for VRR displays, used in app mode requests.
+ private SparseArray<Display.Mode[]> mAppSupportedModesByDisplay;
// A map from the display ID to the default mode of that display.
private SparseArray<Display.Mode> mDefaultModeByDisplay;
// a map from display id to display device config
@@ -222,6 +225,7 @@
mVotesStatsReporter = injector.getVotesStatsReporter(
displayManagerFlags.isRefreshRateVotingTelemetryEnabled());
mSupportedModesByDisplay = new SparseArray<>();
+ mAppSupportedModesByDisplay = new SparseArray<>();
mDefaultModeByDisplay = new SparseArray<>();
mAppRequestObserver = new AppRequestObserver(displayManagerFlags);
mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());
@@ -573,6 +577,12 @@
final Display.Mode[] modes = mSupportedModesByDisplay.valueAt(i);
pw.println(" " + id + " -> " + Arrays.toString(modes));
}
+ pw.println(" mAppSupportedModesByDisplay:");
+ for (int i = 0; i < mAppSupportedModesByDisplay.size(); i++) {
+ final int id = mAppSupportedModesByDisplay.keyAt(i);
+ final Display.Mode[] modes = mAppSupportedModesByDisplay.valueAt(i);
+ pw.println(" " + id + " -> " + Arrays.toString(modes));
+ }
pw.println(" mDefaultModeByDisplay:");
for (int i = 0; i < mDefaultModeByDisplay.size(); i++) {
final int id = mDefaultModeByDisplay.keyAt(i);
@@ -638,6 +648,11 @@
}
@VisibleForTesting
+ void injectAppSupportedModesByDisplay(SparseArray<Display.Mode[]> appSupportedModesByDisplay) {
+ mAppSupportedModesByDisplay = appSupportedModesByDisplay;
+ }
+
+ @VisibleForTesting
void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
mDefaultModeByDisplay = defaultModeByDisplay;
}
@@ -1276,7 +1291,7 @@
Display.Mode[] modes;
Display.Mode defaultMode;
synchronized (mLock) {
- modes = mSupportedModesByDisplay.get(displayId);
+ modes = mAppSupportedModesByDisplay.get(displayId);
defaultMode = mDefaultModeByDisplay.get(displayId);
}
for (int i = 0; i < modes.length; i++) {
@@ -1289,7 +1304,7 @@
}
private void setAppRequestedModeLocked(int displayId, int modeId) {
- final Display.Mode requestedMode = findModeByIdLocked(displayId, modeId);
+ final Display.Mode requestedMode = findAppModeByIdLocked(displayId, modeId);
if (Objects.equals(requestedMode, mAppRequestedModeByDisplay.get(displayId))) {
return;
}
@@ -1297,10 +1312,17 @@
final Vote sizeVote;
if (requestedMode != null) {
mAppRequestedModeByDisplay.put(displayId, requestedMode);
- baseModeRefreshRateVote =
- Vote.forBaseModeRefreshRate(requestedMode.getRefreshRate());
sizeVote = Vote.forSize(requestedMode.getPhysicalWidth(),
requestedMode.getPhysicalHeight());
+ if (requestedMode.isSynthetic()) {
+ // TODO: for synthetic mode we should not limit frame rate, we must ensure
+ // that frame rate is reachable within other Votes constraints
+ baseModeRefreshRateVote = Vote.forRenderFrameRates(
+ requestedMode.getRefreshRate(), requestedMode.getRefreshRate());
+ } else {
+ baseModeRefreshRateVote =
+ Vote.forBaseModeRefreshRate(requestedMode.getRefreshRate());
+ }
} else {
mAppRequestedModeByDisplay.remove(displayId);
baseModeRefreshRateVote = null;
@@ -1344,8 +1366,8 @@
vote);
}
- private Display.Mode findModeByIdLocked(int displayId, int modeId) {
- Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
+ private Display.Mode findAppModeByIdLocked(int displayId, int modeId) {
+ Display.Mode[] modes = mAppSupportedModesByDisplay.get(displayId);
if (modes == null) {
return null;
}
@@ -1424,12 +1446,14 @@
// Populate existing displays
SparseArray<Display.Mode[]> modes = new SparseArray<>();
+ SparseArray<Display.Mode[]> appModes = new SparseArray<>();
SparseArray<Display.Mode> defaultModes = new SparseArray<>();
Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
final int displayId = d.getDisplayId();
DisplayInfo info = getDisplayInfo(displayId);
modes.put(displayId, info.supportedModes);
+ appModes.put(displayId, info.appsSupportedModes);
defaultModes.put(displayId, info.getDefaultMode());
}
DisplayDeviceConfig defaultDisplayConfig = mDisplayDeviceConfigProvider
@@ -1438,6 +1462,7 @@
final int size = modes.size();
for (int i = 0; i < size; i++) {
mSupportedModesByDisplay.put(modes.keyAt(i), modes.valueAt(i));
+ mAppSupportedModesByDisplay.put(appModes.keyAt(i), appModes.valueAt(i));
mDefaultModeByDisplay.put(defaultModes.keyAt(i), defaultModes.valueAt(i));
}
mDisplayDeviceConfigByDisplay.put(Display.DEFAULT_DISPLAY, defaultDisplayConfig);
@@ -1459,6 +1484,7 @@
public void onDisplayRemoved(int displayId) {
synchronized (mLock) {
mSupportedModesByDisplay.remove(displayId);
+ mAppSupportedModesByDisplay.remove(displayId);
mDefaultModeByDisplay.remove(displayId);
mDisplayDeviceConfigByDisplay.remove(displayId);
mSettingsObserver.removeRefreshRateSetting(displayId);
@@ -1619,6 +1645,11 @@
mSupportedModesByDisplay.put(displayId, info.supportedModes);
changed = true;
}
+ if (!Arrays.equals(mAppSupportedModesByDisplay.get(displayId),
+ info.appsSupportedModes)) {
+ mAppSupportedModesByDisplay.put(displayId, info.appsSupportedModes);
+ changed = true;
+ }
if (!Objects.equals(mDefaultModeByDisplay.get(displayId), info.getDefaultMode())) {
changed = true;
mDefaultModeByDisplay.put(displayId, info.getDefaultMode());
diff --git a/services/core/java/com/android/server/display/mode/SyntheticModeManager.java b/services/core/java/com/android/server/display/mode/SyntheticModeManager.java
new file mode 100644
index 0000000..5b6bbc5
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SyntheticModeManager.java
@@ -0,0 +1,87 @@
+/*
+ * 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.server.display.mode;
+
+import android.util.Size;
+import android.view.Display;
+
+import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.feature.DisplayManagerFlags;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * When selected by app synthetic modes will only affect render rate switch rather than mode switch
+ */
+public class SyntheticModeManager {
+ private static final float FLOAT_TOLERANCE = 0.01f;
+ private static final float SYNTHETIC_MODE_HIGH_BOUNDARY = 60f + FLOAT_TOLERANCE;
+
+ private final boolean mSynthetic60HzModesEnabled;
+
+ public SyntheticModeManager(DisplayManagerFlags flags) {
+ mSynthetic60HzModesEnabled = flags.isSynthetic60HzModesEnabled();
+ }
+
+ /**
+ * creates display supportedModes array, exposed to applications
+ */
+ public Display.Mode[] createAppSupportedModes(DisplayDeviceConfig config,
+ Display.Mode[] modes) {
+ if (!config.isVrrSupportEnabled() || !mSynthetic60HzModesEnabled) {
+ return modes;
+ }
+ List<Display.Mode> appSupportedModes = new ArrayList<>();
+ Map<Size, int[]> sizes = new LinkedHashMap<>();
+ int nextModeId = 0;
+ // exclude "real" 60Hz modes and below for VRR displays,
+ // they will be replaced with synthetic 60Hz mode
+ // for VRR display there should be "real" mode with rr > 60Hz
+ for (Display.Mode mode : modes) {
+ if (mode.getRefreshRate() > SYNTHETIC_MODE_HIGH_BOUNDARY) {
+ appSupportedModes.add(mode);
+ }
+ if (mode.getModeId() > nextModeId) {
+ nextModeId = mode.getModeId();
+ }
+
+ float divisor = mode.getVsyncRate() / 60f;
+ boolean is60HzAchievable = Math.abs(divisor - Math.round(divisor)) < FLOAT_TOLERANCE;
+ if (is60HzAchievable) {
+ sizes.put(new Size(mode.getPhysicalWidth(), mode.getPhysicalHeight()),
+ mode.getSupportedHdrTypes());
+ }
+ }
+ // even if VRR display does not have 60Hz mode, we are still adding synthetic 60Hz mode
+ // for each screen size
+ // vsync rate, alternativeRates and hdrTypes are not important for synthetic mode,
+ // only refreshRate and size are used for DisplayModeDirector votes.
+ for (Map.Entry<Size, int[]> entry: sizes.entrySet()) {
+ nextModeId++;
+ Size size = entry.getKey();
+ int[] hdrTypes = entry.getValue();
+ appSupportedModes.add(
+ new Display.Mode(nextModeId, size.getWidth(), size.getHeight(), 60f, 60f, true,
+ new float[0], hdrTypes));
+ }
+ Display.Mode[] appSupportedModesArr = new Display.Mode[appSupportedModes.size()];
+ return appSupportedModes.toArray(appSupportedModesArr);
+ }
+}
diff --git a/services/core/java/com/android/server/flags/pinner.aconfig b/services/core/java/com/android/server/flags/pinner.aconfig
index 16a45cd..2f817db 100644
--- a/services/core/java/com/android/server/flags/pinner.aconfig
+++ b/services/core/java/com/android/server/flags/pinner.aconfig
@@ -6,4 +6,11 @@
namespace: "system_performance"
description: "This flag controls if webview should be pinned in memory."
bug: "307594624"
+}
+
+flag {
+ name: "skip_home_art_pins"
+ namespace: "system_performance"
+ description: "Ablation study flag that controls if home app odex/vdex files should be pinned in memory."
+ bug: "340935152"
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8e85b81..48cccd5 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -960,12 +960,6 @@
// Binder call
@Override
- public boolean isInputDeviceEnabled(int deviceId) {
- return mNative.isInputDeviceEnabled(deviceId);
- }
-
- // Binder call
- @Override
public void enableInputDevice(int deviceId) {
if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
"enableInputDevice()")) {
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 0208a32..a9d40bb 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -183,8 +183,6 @@
void monitor();
- boolean isInputDeviceEnabled(int deviceId);
-
void enableInputDevice(int deviceId);
void disableInputDevice(int deviceId);
@@ -463,9 +461,6 @@
public native void monitor();
@Override
- public native boolean isInputDeviceEnabled(int deviceId);
-
- @Override
public native void enableInputDevice(int deviceId);
@Override
diff --git a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
index ad98b4a..0749edc 100644
--- a/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
+++ b/services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -39,7 +38,7 @@
private static final boolean DEBUG = false;
private static final String TAG = AutofillSuggestionsController.class.getSimpleName();
- @NonNull private final InputMethodManagerService mService;
+ @NonNull private final InputMethodBindingController mBindingController;
/**
* The host input token of the input method that is currently associated with this controller.
@@ -81,8 +80,8 @@
@Nullable
private InlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
- AutofillSuggestionsController(@NonNull InputMethodManagerService service) {
- mService = service;
+ AutofillSuggestionsController(@NonNull InputMethodBindingController bindingController) {
+ mBindingController = bindingController;
}
@GuardedBy("ImfLock.class")
@@ -97,31 +96,32 @@
}
@GuardedBy("ImfLock.class")
- void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
- InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback callback,
- boolean touchExplorationEnabled) {
+ void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo,
+ InlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) {
clearPendingInlineSuggestionsRequest();
mInlineSuggestionsRequestCallback = callback;
- final InputMethodInfo imi = mService.queryInputMethodForCurrentUserLocked(
- mService.getSelectedMethodIdLocked());
- if (userId == mService.getCurrentImeUserIdLocked()
- && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
- mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
- requestInfo, callback, imi.getPackageName());
- if (mService.getCurMethodLocked() != null) {
- // In the normal case when the IME is connected, we can make the request here.
- performOnCreateInlineSuggestionsRequest();
- } else {
- // Otherwise, the next time the IME connection is established,
- // InputMethodBindingController.mMainConnection#onServiceConnected() will call
- // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
- if (DEBUG) {
- Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
- }
- }
- } else {
+ // Note that current user ID is guaranteed to be userId.
+ final var imeId = mBindingController.getSelectedMethodId();
+ final InputMethodInfo imi = InputMethodSettingsRepository.get(mBindingController.mUserId)
+ .getMethodMap().get(imeId);
+ if (imi == null || !isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
callback.onInlineSuggestionsUnsupported();
+ return;
+ }
+
+ mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
+ requestInfo, callback, imi.getPackageName());
+ if (mBindingController.getCurMethod() != null) {
+ // In the normal case when the IME is connected, we can make the request here.
+ performOnCreateInlineSuggestionsRequest();
+ } else {
+ // Otherwise, the next time the IME connection is established,
+ // InputMethodBindingController.mMainConnection#onServiceConnected() will call
+ // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
+ if (DEBUG) {
+ Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
+ }
}
}
@@ -130,7 +130,7 @@
if (mPendingInlineSuggestionsRequest == null) {
return;
}
- IInputMethodInvoker curMethod = mService.getCurMethodLocked();
+ IInputMethodInvoker curMethod = mBindingController.getCurMethod();
if (DEBUG) {
Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod);
}
@@ -139,8 +139,8 @@
new InlineSuggestionsRequestCallbackDecorator(
mPendingInlineSuggestionsRequest.mCallback,
mPendingInlineSuggestionsRequest.mPackageName,
- mService.getCurTokenDisplayIdLocked(),
- mService.getCurTokenLocked());
+ mBindingController.getCurTokenDisplayId(),
+ mBindingController.getCurToken());
curMethod.onCreateInlineSuggestionsRequest(
mPendingInlineSuggestionsRequest.mRequestInfo, callback);
} else {
@@ -205,7 +205,7 @@
}
request.setHostDisplayId(mImeDisplayId);
synchronized (ImfLock.class) {
- final IBinder curImeToken = mService.getCurTokenLocked();
+ final IBinder curImeToken = mBindingController.getCurToken();
if (mImeToken == curImeToken) {
mCurHostInputToken = request.getHostInputToken();
}
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
index 7890fe0..3f28c47 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
@@ -47,6 +47,7 @@
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.InputMethodInfoSafeList;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -80,10 +81,19 @@
InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId);
- List<InputMethodInfo> getInputMethodList(@UserIdInt int userId,
+ @NonNull
+ InputMethodInfoSafeList getInputMethodList(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness);
- List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId);
+ @NonNull
+ InputMethodInfoSafeList getEnabledInputMethodList(@UserIdInt int userId);
+
+ @NonNull
+ List<InputMethodInfo> getInputMethodListLegacy(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness);
+
+ @NonNull
+ List<InputMethodInfo> getEnabledInputMethodListLegacy(@UserIdInt int userId);
List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId);
@@ -216,17 +226,32 @@
return mCallback.getCurrentInputMethodInfoAsUser(userId);
}
+ @NonNull
@Override
- public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId,
+ public InputMethodInfoSafeList getInputMethodList(@UserIdInt int userId,
int directBootAwareness) {
return mCallback.getInputMethodList(userId, directBootAwareness);
}
+ @NonNull
@Override
- public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
+ public InputMethodInfoSafeList getEnabledInputMethodList(@UserIdInt int userId) {
return mCallback.getEnabledInputMethodList(userId);
}
+ @NonNull
+ @Override
+ public List<InputMethodInfo> getInputMethodListLegacy(@UserIdInt int userId,
+ int directBootAwareness) {
+ return mCallback.getInputMethodListLegacy(userId, directBootAwareness);
+ }
+
+ @NonNull
+ @Override
+ public List<InputMethodInfo> getEnabledInputMethodListLegacy(@UserIdInt int userId) {
+ return mCallback.getEnabledInputMethodListLegacy(userId);
+ }
+
@Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index e862c7e..8191ee1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -39,6 +39,7 @@
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
+import android.view.Display;
import android.view.WindowManager;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
@@ -47,6 +48,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.IInputMethod;
+import com.android.internal.inputmethod.InlineSuggestionsRequestCallback;
+import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.UnbindReason;
import com.android.server.EventLogTags;
@@ -67,6 +70,7 @@
@UserIdInt final int mUserId;
@NonNull private final InputMethodManagerService mService;
@NonNull private final Context mContext;
+ @NonNull private final AutofillSuggestionsController mAutofillController;
@NonNull private final PackageManagerInternal mPackageManagerInternal;
@NonNull private final WindowManagerInternal mWindowManagerInternal;
@@ -78,6 +82,7 @@
@GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod;
@GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
@GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken;
+ @GuardedBy("ImfLock.class") private int mCurTokenDisplayId = Display.INVALID_DISPLAY;
@GuardedBy("ImfLock.class") private int mCurSeq;
@GuardedBy("ImfLock.class") private boolean mVisibleBound;
@GuardedBy("ImfLock.class") private boolean mSupportsStylusHw;
@@ -120,6 +125,7 @@
mUserId = userId;
mService = service;
mContext = mService.mContext;
+ mAutofillController = new AutofillSuggestionsController(this);
mPackageManagerInternal = mService.mPackageManagerInternal;
mWindowManagerInternal = mService.mWindowManagerInternal;
mImeConnectionBindFlags = imeConnectionBindFlags;
@@ -193,6 +199,17 @@
}
/**
+ * Returns the displayId associated with {@link #getCurToken()}.
+ *
+ * @return the displayId associated with {@link #getCurToken()}. {@link Display#INVALID_DISPLAY}
+ * while {@link #getCurToken()} returns {@code null}
+ */
+ @GuardedBy("ImfLock.class")
+ int getCurTokenDisplayId() {
+ return mCurTokenDisplayId;
+ }
+
+ /**
* The Intent used to connect to the current input method.
*/
@GuardedBy("ImfLock.class")
@@ -269,7 +286,7 @@
private final ServiceConnection mVisibleConnection = new ServiceConnection() {
@Override public void onBindingDied(ComponentName name) {
synchronized (ImfLock.class) {
- mService.invalidateAutofillSessionLocked();
+ mAutofillController.invalidateAutofillSession();
if (isVisibleBound()) {
unbindVisibleConnection();
}
@@ -281,7 +298,7 @@
@Override public void onServiceDisconnected(ComponentName name) {
synchronized (ImfLock.class) {
- mService.invalidateAutofillSessionLocked();
+ mAutofillController.invalidateAutofillSession();
}
}
};
@@ -326,7 +343,7 @@
mService.initializeImeLocked(mCurMethod, mCurToken);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
- mService.performOnCreateInlineSuggestionsRequestLocked();
+ mAutofillController.performOnCreateInlineSuggestionsRequest();
}
// reset Handwriting event receiver.
@@ -385,6 +402,24 @@
};
@GuardedBy("ImfLock.class")
+ void invalidateAutofillSession() {
+ mAutofillController.invalidateAutofillSession();
+ }
+
+ @GuardedBy("ImfLock.class")
+ void onCreateInlineSuggestionsRequest(InlineSuggestionsRequestInfo requestInfo,
+ InlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) {
+ mAutofillController.onCreateInlineSuggestionsRequest(requestInfo, callback,
+ touchExplorationEnabled);
+ }
+
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ IBinder getCurHostInputToken() {
+ return mAutofillController.getCurHostInputToken();
+ }
+
+ @GuardedBy("ImfLock.class")
void unbindCurrentMethod() {
if (isVisibleBound()) {
unbindVisibleConnection();
@@ -397,6 +432,7 @@
if (getCurToken() != null) {
removeCurrentToken();
mService.resetSystemUiLocked();
+ mAutofillController.onResetSystemUi();
}
mCurId = null;
@@ -412,15 +448,14 @@
@GuardedBy("ImfLock.class")
private void removeCurrentToken() {
- int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
-
if (DEBUG) {
Slog.v(TAG,
- "Removing window token: " + mCurToken + " for display: " + curTokenDisplayId);
+ "Removing window token: " + mCurToken + " for display: " + mCurTokenDisplayId);
}
mWindowManagerInternal.removeWindowToken(mCurToken, true /* removeWindows */,
- false /* animateExit */, curTokenDisplayId);
+ false /* animateExit */, mCurTokenDisplayId);
mCurToken = null;
+ mCurTokenDisplayId = Display.INVALID_DISPLAY;
}
@GuardedBy("ImfLock.class")
@@ -445,7 +480,7 @@
final int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
mCurToken = new Binder();
- mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
+ mCurTokenDisplayId = displayIdToShowIme;
if (DEBUG) {
Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
+ displayIdToShowIme);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f8dda60..976399d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -160,6 +160,7 @@
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
+import com.android.internal.inputmethod.InputMethodInfoSafeList;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -332,9 +333,6 @@
private final UserManagerInternal mUserManagerInternal;
@MultiUserUnawareField
private final InputMethodMenuController mMenuController;
- @MultiUserUnawareField
- @NonNull
- private final AutofillSuggestionsController mAutofillController;
@GuardedBy("ImfLock.class")
@MultiUserUnawareField
@@ -491,6 +489,12 @@
*/
boolean mSystemReady;
+ @GuardedBy("ImfLock.class")
+ @NonNull
+ InputMethodBindingController getInputMethodBindingController(@UserIdInt int userId) {
+ return mUserDataRepository.getOrCreate(userId).mBindingController;
+ }
+
/**
* Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
* This is to be synchronized with the secure settings keyed with
@@ -507,8 +511,7 @@
@GuardedBy("ImfLock.class")
@Nullable
String getSelectedMethodIdLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getSelectedMethodId();
+ return getInputMethodBindingController(mCurrentUserId).getSelectedMethodId();
}
@GuardedBy("ImfLock.class")
@@ -594,8 +597,7 @@
@GuardedBy("ImfLock.class")
@Nullable
IBinder getCurTokenLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getCurToken();
+ return getInputMethodBindingController(mCurrentUserId).getCurToken();
}
/**
@@ -603,18 +605,9 @@
*/
@GuardedBy("ImfLock.class")
int getCurTokenDisplayIdLocked() {
- return mCurTokenDisplayId;
+ return getInputMethodBindingController(mCurrentUserId).getCurTokenDisplayId();
}
- @GuardedBy("ImfLock.class")
- void setCurTokenDisplayIdLocked(int curTokenDisplayId) {
- mCurTokenDisplayId = curTokenDisplayId;
- }
-
- @GuardedBy("ImfLock.class")
- @MultiUserUnawareField
- private int mCurTokenDisplayId = INVALID_DISPLAY;
-
/**
* The display ID of the input method indicates the fallback display which returned by
* {@link #computeImeDisplayIdForTarget}.
@@ -628,8 +621,7 @@
@GuardedBy("ImfLock.class")
@Nullable
IInputMethodInvoker getCurMethodLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- return userData.mBindingController.getCurMethod();
+ return getInputMethodBindingController(mCurrentUserId).getCurMethod();
}
/**
@@ -862,37 +854,6 @@
final class MyPackageMonitor extends PackageMonitor {
/**
- * Package names that are known to contain {@link InputMethodService}.
- *
- * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
- * all the packages when the user is unlocked, and direct-boot awareness will not be changed
- * dynamically unless the entire package is updated, which also always triggers package
- * rescanning.</p>
- */
- @GuardedBy("ImfLock.class")
- private final ArraySet<String> mKnownImePackageNames = new ArraySet<>();
-
- /**
- * Packages that are appeared, disappeared, or modified for whatever reason.
- *
- * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
- * because 1) the number of elements is almost always 1 or so, and 2) we do not care
- * duplicate elements for our use case.</p>
- *
- * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
- * which should be bound to {@link #getRegisteredHandler()}.</p>
- */
- private final ArrayList<String> mChangedPackages = new ArrayList<>();
-
- /**
- * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
- *
- * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
- * which should be bound to {@link #getRegisteredHandler()}.</p>
- */
- private boolean mImePackageAppeared = false;
-
- /**
* Remembers package names passed to {@link #onPackageDataCleared(String, int)}.
*
* <p>This field must be accessed only from callback methods in {@link PackageMonitor},
@@ -905,16 +866,6 @@
}
@GuardedBy("ImfLock.class")
- void clearKnownImePackageNamesLocked() {
- mKnownImePackageNames.clear();
- }
-
- @GuardedBy("ImfLock.class")
- void addKnownImePackageNameLocked(@NonNull String packageName) {
- mKnownImePackageNames.add(packageName);
- }
-
- @GuardedBy("ImfLock.class")
private boolean isChangingPackagesOfCurrentUserLocked() {
final int userId = getChangingUserId();
final boolean retval = userId == mCurrentUserId;
@@ -964,52 +915,7 @@
}
@Override
- public void onPackageAppeared(String packageName, int reason) {
- if (!mImePackageAppeared) {
- final PackageManager pm = mContext.getPackageManager();
- final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
- new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
- PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
- // No need to lock this because we access it only on getRegisteredHandler().
- if (!services.isEmpty()) {
- mImePackageAppeared = true;
- }
- }
- // No need to lock this because we access it only on getRegisteredHandler().
- mChangedPackages.add(packageName);
- }
-
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- // No need to lock this because we access it only on getRegisteredHandler().
- mChangedPackages.add(packageName);
- }
-
- @Override
- public void onPackageModified(String packageName) {
- // No need to lock this because we access it only on getRegisteredHandler().
- mChangedPackages.add(packageName);
- }
-
- @Override
- public void onPackagesSuspended(String[] packages) {
- // No need to lock this because we access it only on getRegisteredHandler().
- for (String packageName : packages) {
- mChangedPackages.add(packageName);
- }
- }
-
- @Override
- public void onPackagesUnsuspended(String[] packages) {
- // No need to lock this because we access it only on getRegisteredHandler().
- for (String packageName : packages) {
- mChangedPackages.add(packageName);
- }
- }
-
- @Override
public void onPackageDataCleared(String packageName, int uid) {
- mChangedPackages.add(packageName);
mDataClearedPackages.add(packageName);
}
@@ -1021,32 +927,7 @@
private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler().
- mChangedPackages.clear();
mDataClearedPackages.clear();
- mImePackageAppeared = false;
- }
-
- @GuardedBy("ImfLock.class")
- private boolean shouldRebuildInputMethodListLocked() {
- // This method is guaranteed to be called only by getRegisteredHandler().
-
- // If there is any new package that contains at least one IME, then rebuilt the list
- // of IMEs.
- if (mImePackageAppeared) {
- return true;
- }
-
- // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
- // TODO: Consider to create a utility method to do the following test. List.retainAll()
- // is an option, but it may still do some extra operations that we do not need here.
- final int numPackages = mChangedPackages.size();
- for (int i = 0; i < numPackages; ++i) {
- final String packageName = mChangedPackages.get(i);
- if (mKnownImePackageNames.contains(packageName)) {
- return true;
- }
- }
- return false;
}
private void onFinishPackageChangesInternal() {
@@ -1107,12 +988,15 @@
AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,
settings.getMethodMap());
}
- if (isCurrentUser
- && !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
- return;
- }
+
final var newMethodMap = newMethodMapWithoutAdditionalSubtypes
.applyAdditionalSubtypes(newAdditionalSubtypeMap);
+
+ if (InputMethodMap.areSame(settings.getMethodMap(), newMethodMap)) {
+ // No update in the actual IME map.
+ return;
+ }
+
final InputMethodSettings newSettings =
InputMethodSettings.create(newMethodMap, userId);
InputMethodSettingsRepository.put(userId, newSettings);
@@ -1243,6 +1127,11 @@
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
// Called on ActivityManager thread.
synchronized (ImfLock.class) {
+ if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ // In concurrent multi-user mode, we in general do not rely on the concept of
+ // current user.
+ return;
+ }
mService.scheduleSwitchUserTaskLocked(to.getUserIdentifier(),
/* clientToBeReset= */ null);
}
@@ -1268,9 +1157,15 @@
@Override
public void onUserStarting(TargetUser user) {
// Called on ActivityManager thread.
- SecureSettingsWrapper.onUserStarting(user.getUserIdentifier());
+ final int userId = user.getUserIdentifier();
+ SecureSettingsWrapper.onUserStarting(userId);
synchronized (ImfLock.class) {
- mService.mUserDataRepository.getOrCreate(user.getUserIdentifier());
+ mService.mUserDataRepository.getOrCreate(userId);
+ if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mCurrentUserId != userId) {
+ mService.experimentalInitializeVisibleBackgroundUserLocked(userId);
+ }
+ }
}
}
@@ -1291,6 +1186,8 @@
// We need to rebuild IMEs.
postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */);
updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ } else if (mExperimentalConcurrentMultiUserModeEnabled) {
+ experimentalInitializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1397,7 +1294,6 @@
new HardwareKeyboardShortcutController(settings.getMethodMap(),
settings.getUserId());
mMenuController = new InputMethodMenuController(this);
- mAutofillController = new AutofillSuggestionsController(this);
mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
mVisibilityApplier = new DefaultImeVisibilityApplier(this);
@@ -1530,8 +1426,7 @@
// Note that in b/197848765 we want to see if we can keep the binding alive for better
// profile switching.
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
bindingController.unbindCurrentMethod();
unbindCurrentClientLocked(UnbindReason.SWITCH_USER);
@@ -1691,7 +1586,58 @@
@BinderThread
@NonNull
@Override
- public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId,
+ public InputMethodInfoSafeList getInputMethodList(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness) {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ }
+ synchronized (ImfLock.class) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+ mCurrentUserId, null);
+ if (resolvedUserIds.length != 1) {
+ return InputMethodInfoSafeList.empty();
+ }
+ final int callingUid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return InputMethodInfoSafeList.create(getInputMethodListLocked(
+ resolvedUserIds[0], directBootAwareness, callingUid));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @BinderThread
+ @NonNull
+ @Override
+ public InputMethodInfoSafeList getEnabledInputMethodList(@UserIdInt int userId) {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ }
+ synchronized (ImfLock.class) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+ mCurrentUserId, null);
+ if (resolvedUserIds.length != 1) {
+ return InputMethodInfoSafeList.empty();
+ }
+ final int callingUid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return InputMethodInfoSafeList.create(
+ getEnabledInputMethodListLocked(resolvedUserIds[0], callingUid));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @BinderThread
+ @NonNull
+ @Override
+ public List<InputMethodInfo> getInputMethodListLegacy(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission(
@@ -1714,8 +1660,10 @@
}
}
+ @BinderThread
+ @NonNull
@Override
- public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
+ public List<InputMethodInfo> getEnabledInputMethodListLegacy(@UserIdInt int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
@@ -1751,8 +1699,7 @@
// Check if selected IME of current user supports handwriting.
if (userId == mCurrentUserId) {
- final var userData = mUserDataRepository.getOrCreate(userId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(userId);
return bindingController.supportsStylusHandwriting()
&& (!connectionless
|| bindingController.supportsConnectionlessStylusHandwriting());
@@ -1808,11 +1755,6 @@
return methodList;
}
- @GuardedBy("ImfLock.class")
- void performOnCreateInlineSuggestionsRequestLocked() {
- mAutofillController.performOnCreateInlineSuggestionsRequest();
- }
-
/**
* Gets enabled subtypes of the specified {@link InputMethodInfo}.
*
@@ -1952,8 +1894,7 @@
// TODO(b/325515685): make binding controller user independent. Before this change, the
// following dependencies also need to be user independent: mCurClient, mBoundToMethod,
// getCurMethodLocked(), and mMenuController.
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
mCurClient.mClient.onUnbindMethod(bindingController.getSequenceNumber(),
unbindClientReason);
mCurClient.mSessionRequested = false;
@@ -2033,8 +1974,7 @@
final boolean restarting = !initial;
final Binder startInputToken = new Binder();
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
final StartInputInfo info = new StartInputInfo(mCurrentUserId,
getCurTokenLocked(),
getCurTokenDisplayIdLocked(), bindingController.getCurId(), startInputReason,
@@ -2140,7 +2080,7 @@
@StartInputReason int startInputReason,
int unverifiedTargetSdkVersion,
@NonNull ImeOnBackInvokedDispatcher imeDispatcher,
- @NonNull UserDataRepository.UserData userData) {
+ @NonNull InputMethodBindingController bindingController) {
// Compute the final shown display ID with validated cs.selfReportedDisplayId for this
// session & other conditions.
@@ -2154,8 +2094,9 @@
// Potentially override the selected input method if the new display belongs to a virtual
// device with a custom IME.
- String selectedMethodId = getSelectedMethodIdLocked();
- final String deviceMethodId = computeCurrentDeviceMethodIdLocked(selectedMethodId);
+ String selectedMethodId = bindingController.getSelectedMethodId();
+ final String deviceMethodId = computeCurrentDeviceMethodIdLocked(bindingController.mUserId,
+ selectedMethodId);
if (deviceMethodId == null) {
mVisibilityStateComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
} else if (!Objects.equals(deviceMethodId, selectedMethodId)) {
@@ -2181,7 +2122,6 @@
final boolean connectionWasActive = mCurInputConnection != null;
// Bump up the sequence for this client and attach it.
- final var bindingController = userData.mBindingController;
bindingController.advanceSequenceNumber();
mCurClient = cs;
@@ -2212,7 +2152,7 @@
if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
- invalidateAutofillSessionLocked();
+ bindingController.invalidateAutofillSession();
bindingController.unbindCurrentMethod();
return InputBindResult.NO_EDITOR;
}
@@ -2241,7 +2181,7 @@
(startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
}
- InputBindResult bindResult = tryReuseConnectionLocked(userData, cs);
+ InputBindResult bindResult = tryReuseConnectionLocked(bindingController, cs);
if (bindResult != null) {
return bindResult;
}
@@ -2262,7 +2202,8 @@
* <p>4. Otherwise keep the current imeId.</p>
*/
@GuardedBy("ImfLock.class")
- private String computeCurrentDeviceMethodIdLocked(String currentMethodId) {
+ private String computeCurrentDeviceMethodIdLocked(@UserIdInt int userId,
+ String currentMethodId) {
if (mVdmInternal == null) {
mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
}
@@ -2270,7 +2211,7 @@
return currentMethodId;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final int oldDeviceId = mDeviceIdToShowIme;
mDeviceIdToShowIme = mVdmInternal.getDeviceIdForDisplayId(mDisplayIdToShowIme);
if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
@@ -2312,11 +2253,6 @@
}
@GuardedBy("ImfLock.class")
- void invalidateAutofillSessionLocked() {
- mAutofillController.invalidateAutofillSession();
- }
-
- @GuardedBy("ImfLock.class")
private boolean shouldPreventImeStartupLocked(
@NonNull String selectedMethodId,
@StartInputFlags int startInputFlags,
@@ -2355,9 +2291,8 @@
@GuardedBy("ImfLock.class")
@Nullable
- private InputBindResult tryReuseConnectionLocked(@NonNull UserDataRepository.UserData userData,
- @NonNull ClientState cs) {
- final var bindingController = userData.mBindingController;
+ private InputBindResult tryReuseConnectionLocked(
+ @NonNull InputMethodBindingController bindingController, @NonNull ClientState cs) {
if (bindingController.hasMainConnection()) {
if (getCurMethodLocked() != null) {
// Return to client, and we will get back with it when
@@ -2505,8 +2440,6 @@
mImeWindowVis = 0;
mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
- mCurTokenDisplayId = INVALID_DISPLAY;
- mAutofillController.onResetSystemUi();
}
@GuardedBy("ImfLock.class")
@@ -2740,8 +2673,9 @@
// When the IME switcher dialog is shown, the IME switcher button should be hidden.
if (mMenuController.getSwitchingDialogLocked() != null) return false;
// When we are switching IMEs, the IME switcher button should be hidden.
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- if (!Objects.equals(userData.mBindingController.getCurId(), getSelectedMethodIdLocked())) {
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ if (!Objects.equals(bindingController.getCurId(),
+ bindingController.getSelectedMethodId())) {
return false;
}
if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
@@ -2903,8 +2837,7 @@
} else {
vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
}
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var curId = userData.mBindingController.getCurId();
+ final var curId = getInputMethodBindingController(mCurrentUserId).getCurId();
if (mMenuController.getSwitchingDialogLocked() != null
|| !Objects.equals(curId, getSelectedMethodIdLocked())) {
// When the IME switcher dialog is shown, or we are switching IMEs,
@@ -2927,6 +2860,48 @@
mMenuController.updateKeyboardFromSettingsLocked();
}
+ /**
+ * This is an experimental implementation used when and only when
+ * {@link #mExperimentalConcurrentMultiUserModeEnabled}.
+ *
+ * <p>Never assume what this method is doing is officially supported. For the canonical and
+ * desired behaviors always refer to single-user code paths such as
+ * {@link #updateInputMethodsFromSettingsLocked(boolean)}.</p>
+ *
+ * <p>Here are examples of missing features.</p>
+ * <ul>
+ * <li>Subtypes are not supported at all!</li>
+ * <li>Profiles are not supported.</li>
+ * <li>
+ * {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED} is not updated.
+ * </li>
+ * <li>{@link #mDeviceIdToShowIme} is ignored.</li>
+ * <li>{@link #mSwitchingController} is ignored.</li>
+ * <li>{@link #mHardwareKeyboardShortcutController} is ignored.</li>
+ * <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
+ * <li>and so on.</li>
+ * </ul>
+ */
+ @GuardedBy("ImfLock.class")
+ void experimentalInitializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
+ if (!mUserManagerInternal.isUserVisible(userId)) {
+ return;
+ }
+ final var settings = InputMethodSettingsRepository.get(userId);
+ String id = settings.getSelectedInputMethod();
+ if (TextUtils.isEmpty(id)) {
+ final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
+ settings.getEnabledInputMethodList());
+ if (imi == null) {
+ return;
+ }
+ id = imi.getId();
+ settings.putSelectedInputMethod(id);
+ }
+ final var bindingController = getInputMethodBindingController(userId);
+ bindingController.setSelectedMethodId(id);
+ }
+
@GuardedBy("ImfLock.class")
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
@@ -3099,8 +3074,7 @@
// mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
// because mCurMethodId is stored as a history in
// setSelectedInputMethodAndSubtypeLocked().
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- userData.mBindingController.setSelectedMethodId(id);
+ getInputMethodBindingController(mCurrentUserId).setSelectedMethodId(id);
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -3155,8 +3129,8 @@
@Nullable String delegatorPackageName,
@NonNull IConnectionlessHandwritingCallback callback) {
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(userId);
- if (!userData.mBindingController.supportsConnectionlessStylusHandwriting()) {
+ final var bindingController = getInputMethodBindingController(userId);
+ if (!bindingController.supportsConnectionlessStylusHandwriting()) {
Slog.w(TAG, "Connectionless stylus handwriting mode unsupported by IME.");
try {
callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED);
@@ -3239,8 +3213,8 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- if (!userData.mBindingController.supportsStylusHandwriting()) {
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ if (!bindingController.supportsStylusHandwriting()) {
Slog.w(TAG,
"Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
return false;
@@ -3423,8 +3397,8 @@
mVisibilityStateComputer.requestImeVisibility(windowToken, true);
// Ensure binding the connection when IME is going to show.
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- userData.mBindingController.setCurrentMethodVisible();
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ bindingController.setCurrentMethodVisible();
final IInputMethodInvoker curMethod = getCurMethodLocked();
ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
final boolean readyToDispatchToIme;
@@ -3532,8 +3506,8 @@
} else {
ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
}
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- userData.mBindingController.setCurrentMethodNotVisible();
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ bindingController.setCurrentMethodNotVisible();
mVisibilityStateComputer.clearImeShowFlags();
// Cancel existing statsToken for show IME as we got a hide request.
ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
@@ -3601,8 +3575,7 @@
"InputMethodManagerService#startInputOrWindowGainedFocus", mDumper);
final InputBindResult result;
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(userId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(userId);
// If the system is not yet ready, we shouldn't be running third party code.
if (!mSystemReady) {
return new InputBindResult(
@@ -3619,7 +3592,8 @@
final long ident = Binder.clearCallingIdentity();
try {
// Verify if IMMS is in the process of switching user.
- if (mUserSwitchHandlerTask != null) {
+ if (!mExperimentalConcurrentMultiUserModeEnabled
+ && mUserSwitchHandlerTask != null) {
// There is already an on-going pending user switch task.
final int nextUserId = mUserSwitchHandlerTask.mToUserId;
if (userId == nextUserId) {
@@ -3673,7 +3647,7 @@
}
// Verify if caller is a background user.
- if (userId != mCurrentUserId) {
+ if (!mExperimentalConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
if (ArrayUtils.contains(
mUserManagerInternal.getProfileIds(mCurrentUserId, false),
userId)) {
@@ -3701,7 +3675,7 @@
result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
client, windowToken, startInputFlags, softInputMode, windowFlags,
editorInfo, inputConnection, remoteAccessibilityInputConnection,
- unverifiedTargetSdkVersion, userData, imeDispatcher, cs);
+ unverifiedTargetSdkVersion, bindingController, imeDispatcher, cs);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3729,7 +3703,7 @@
@SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo editorInfo,
IRemoteInputConnection inputContext,
@Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
- int unverifiedTargetSdkVersion, @NonNull UserDataRepository.UserData userData,
+ int unverifiedTargetSdkVersion, @NonNull InputMethodBindingController bindingController,
@NonNull ImeOnBackInvokedDispatcher imeDispatcher, @NonNull ClientState cs) {
if (DEBUG) {
Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
@@ -3742,7 +3716,7 @@
+ " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
+ " windowFlags=#" + Integer.toHexString(windowFlags)
+ " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion
- + " userData=" + userData
+ + " bindingController=" + bindingController
+ " imeDispatcher=" + imeDispatcher
+ " cs=" + cs);
}
@@ -3771,15 +3745,16 @@
if (editorInfo != null) {
return startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, editorInfo, startInputFlags,
- startInputReason, unverifiedTargetSdkVersion, imeDispatcher, userData);
+ startInputReason, unverifiedTargetSdkVersion, imeDispatcher,
+ bindingController);
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, null, -1, false);
}
- mImeBindingState = new ImeBindingState(userData.mUserId, windowToken, softInputMode, cs,
- editorInfo);
+ mImeBindingState = new ImeBindingState(bindingController.mUserId, windowToken,
+ softInputMode, cs, editorInfo);
mFocusedWindowPerceptible.put(windowToken, true);
// We want to start input before showing the IME, but after closing
@@ -3804,7 +3779,7 @@
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, editorInfo, startInputFlags,
startInputReason, unverifiedTargetSdkVersion,
- imeDispatcher, userData);
+ imeDispatcher, bindingController);
didStart = true;
}
break;
@@ -3819,7 +3794,7 @@
// 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 != getCurTokenDisplayIdLocked()) {
- userData.mBindingController.unbindCurrentMethod();
+ bindingController.unbindCurrentMethod();
}
}
}
@@ -3828,7 +3803,7 @@
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, editorInfo, startInputFlags,
startInputReason, unverifiedTargetSdkVersion,
- imeDispatcher, userData);
+ imeDispatcher, bindingController);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -3869,8 +3844,7 @@
if (mCurrentUserId != UserHandle.getUserId(uid)) {
return false;
}
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var curIntent = userData.mBindingController.getCurIntent();
+ final var curIntent = getInputMethodBindingController(mCurrentUserId).getCurIntent();
if (curIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
mPackageManagerInternal, uid, curIntent.getComponent().getPackageName())) {
return true;
@@ -4279,8 +4253,7 @@
mStylusIds.add(deviceId);
// a new Stylus is detected. If IME supports handwriting, and we don't have
// handwriting initialized, lets do it now.
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
if (!mHwController.getCurrentRequestId().isPresent()
&& bindingController.supportsStylusHandwriting()) {
scheduleResetStylusHandwriting();
@@ -4372,11 +4345,8 @@
private static IntArray getStylusInputDeviceIds(InputManager im) {
IntArray stylusIds = new IntArray();
for (int id : im.getInputDeviceIds()) {
- if (!im.isInputDeviceEnabled(id)) {
- continue;
- }
InputDevice device = im.getInputDevice(id);
- if (device != null && isStylusDevice(device)) {
+ if (device != null && device.isEnabled() && isStylusDevice(device)) {
stylusIds.add(id);
}
}
@@ -4464,8 +4434,7 @@
private void dumpDebug(ProtoOutputStream proto, long fieldId) {
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
final long token = proto.start(fieldId);
proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
proto.write(CUR_SEQ, bindingController.getSequenceNumber());
@@ -4855,8 +4824,7 @@
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
if (bindingController.supportsStylusHandwriting()
&& getCurMethodLocked() != null && hasSupportedStylusLocked()) {
Slog.d(TAG, "Initializing Handwriting Spy");
@@ -4882,8 +4850,7 @@
if (curMethod == null || mImeBindingState.mFocusedWindow == null) {
return true;
}
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
final HandwritingModeController.HandwritingSession session =
mHwController.startHandwritingSession(
msg.arg1 /*requestId*/,
@@ -4939,8 +4906,7 @@
return;
}
// TODO(b/325515685): user data must be retrieved by a userId parameter
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(
bindingController.getCurMethodUid())) {
// Handle IME visibility when interactive changed before finishing the input to
@@ -5007,8 +4973,8 @@
new Intent(InputMethod.SERVICE_INTERFACE),
PackageManager.ResolveInfoFlags.of(flags));
- // Note: This is a temporary solution for Bug 261723412. If there is any better solution,
- // we should remove this data dependency.
+ // Note: This is a temporary solution for Bug 261723412.
+ // TODO(b/339761278): Remove this workaround after switching to InputMethodInfoSafeList.
final List<String> enabledInputMethodList =
InputMethodUtils.getEnabledInputMethodIdsForFiltering(context, userId);
@@ -5077,30 +5043,9 @@
return;
}
mMethodMapUpdateCount++;
- mMyPackageMonitor.clearKnownImePackageNamesLocked();
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
- // Construct the set of possible IME packages for onPackageChanged() to avoid false
- // negatives when the package state remains to be the same but only the component state is
- // changed.
- {
- // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
- // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
- // conservative, but it seems we cannot use it for now (Issue 35176630).
- final List<ResolveInfo> allInputMethodServices =
- mContext.getPackageManager().queryIntentServicesAsUser(
- new Intent(InputMethod.SERVICE_INTERFACE),
- PackageManager.MATCH_DISABLED_COMPONENTS, settings.getUserId());
- final int numImes = allInputMethodServices.size();
- for (int i = 0; i < numImes; ++i) {
- final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
- if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
- mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
- }
- }
- }
-
boolean reenableMinimumNonAuxSystemImes = false;
// TODO: The following code should find better place to live.
if (!resetDefaultEnabledIme) {
@@ -5186,8 +5131,7 @@
@GuardedBy("ImfLock.class")
void sendOnNavButtonFlagsChangedLocked() {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
final IInputMethodInvoker curMethod = bindingController.getCurMethod();
if (curMethod == null) {
// No need to send the data if the IME is not yet bound.
@@ -5557,8 +5501,8 @@
.isTouchExplorationEnabled(userId);
synchronized (ImfLock.class) {
- mAutofillController.onCreateInlineSuggestionsRequest(userId, requestInfo, cb,
- touchExplorationEnabled);
+ getInputMethodBindingController(userId).onCreateInlineSuggestionsRequest(
+ requestInfo, cb, touchExplorationEnabled);
}
}
@@ -5626,7 +5570,7 @@
if (displayId != getCurTokenDisplayIdLocked()) {
return false;
}
- curHostInputToken = mAutofillController.getCurHostInputToken();
+ curHostInputToken = getInputMethodBindingController(userId).getCurHostInputToken();
if (curHostInputToken == null) {
return false;
}
@@ -5674,8 +5618,7 @@
public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
IAccessibilityInputMethodSession session, @UserIdInt int userId) {
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
// TODO(b/305829876): Implement user ID verification
if (mCurClient != null) {
clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
@@ -5710,8 +5653,7 @@
public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId,
@UserIdInt int userId) {
synchronized (ImfLock.class) {
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
// TODO(b/305829876): Implement user ID verification
if (mCurClient != null) {
if (DEBUG) {
@@ -5943,8 +5885,7 @@
p.println(" pid=" + c.mPid);
};
mClientController.forAllClients(clientControllerDump);
- final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
p.println(" mCurrentUserId=" + mCurrentUserId);
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
@@ -5971,7 +5912,7 @@
p.println(" mCurToken=" + getCurTokenLocked());
p.println(" mCurTokenDisplayId=" + getCurTokenDisplayIdLocked());
- p.println(" mCurHostInputToken=" + mAutofillController.getCurHostInputToken());
+ p.println(" mCurHostInputToken=" + bindingController.getCurHostInputToken());
p.println(" mCurIntent=" + bindingController.getCurIntent());
method = getCurMethodLocked();
p.println(" mCurMethod=" + getCurMethodLocked());
@@ -6456,8 +6397,8 @@
continue;
}
// Skip on headless user
- if (USER_TYPE_SYSTEM_HEADLESS.equals(
- mUserManagerInternal.getUserInfo(userId).userType)) {
+ final var userInfo = mUserManagerInternal.getUserInfo(userId);
+ if (userInfo != null && USER_TYPE_SYSTEM_HEADLESS.equals(userInfo.userType)) {
continue;
}
final String nextIme;
@@ -6466,8 +6407,7 @@
if (userId == mCurrentUserId) {
hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
- final var userData = mUserDataRepository.getOrCreate(userId);
- final var bindingController = userData.mBindingController;
+ final var bindingController = getInputMethodBindingController(userId);
bindingController.unbindCurrentMethod();
// Enable default IMEs, disable others
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index 1cd1ddc..189c1a7 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -64,6 +64,7 @@
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.InputMethodInfoSafeList;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -139,17 +140,28 @@
}
@Override
- public List<InputMethodInfo> getInputMethodList(
+ public InputMethodInfoSafeList getInputMethodList(
int userId, @DirectBootAwareness int directBootAwareness) {
return mInner.getInputMethodList(userId, directBootAwareness);
}
@Override
- public List<InputMethodInfo> getEnabledInputMethodList(int userId) {
+ public InputMethodInfoSafeList getEnabledInputMethodList(int userId) {
return mInner.getEnabledInputMethodList(userId);
}
@Override
+ public List<InputMethodInfo> getInputMethodListLegacy(
+ int userId, @DirectBootAwareness int directBootAwareness) {
+ return mInner.getInputMethodListLegacy(userId, directBootAwareness);
+ }
+
+ @Override
+ public List<InputMethodInfo> getEnabledInputMethodListLegacy(int userId) {
+ return mInner.getEnabledInputMethodListLegacy(userId);
+ }
+
+ @Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlyEnabledSubtypes, int userId) {
return mInner.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes,
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 17f8abe..b3fb147 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -317,9 +317,6 @@
*/
private static final int MAX_PROBABILITY_PERCENT = 100;
- /**
- * Random number generator.
- */
private Random mRandom = new Random();
/**
@@ -998,50 +995,75 @@
return;
}
- if (message.isReliable()) {
- byte errorCode = ErrorCode.OK;
- synchronized (mReliableMessageRecordQueue) {
- Optional<ReliableMessageRecord> record = Optional.empty();
- for (ReliableMessageRecord r: mReliableMessageRecordQueue) {
- if (r.getContextHubId() == contextHubId
- && r.getMessageSequenceNumber() == message.getMessageSequenceNumber()) {
- record = Optional.of(r);
- break;
- }
- }
-
- if (record.isPresent()) {
- errorCode = record.get().getErrorCode();
- if (errorCode == ErrorCode.TRANSIENT_ERROR) {
- Log.w(TAG, "Found duplicate reliable message with message sequence number: "
- + record.get().getMessageSequenceNumber() + ": retrying");
- errorCode = mClientManager.onMessageFromNanoApp(
- contextHubId, hostEndpointId, message,
- nanoappPermissions, messagePermissions);
- record.get().setErrorCode(errorCode);
- } else {
- Log.w(TAG, "Found duplicate reliable message with message sequence number: "
- + record.get().getMessageSequenceNumber());
- }
- } else {
- errorCode = mClientManager.onMessageFromNanoApp(
- contextHubId, hostEndpointId, message,
- nanoappPermissions, messagePermissions);
- mReliableMessageRecordQueue.add(
- new ReliableMessageRecord(contextHubId,
- SystemClock.elapsedRealtimeNanos(),
- message.getMessageSequenceNumber(),
- errorCode));
- }
- }
- sendMessageDeliveryStatusToContextHub(contextHubId,
- message.getMessageSequenceNumber(), errorCode);
- } else {
+ if (!message.isReliable()) {
mClientManager.onMessageFromNanoApp(
contextHubId, hostEndpointId, message,
nanoappPermissions, messagePermissions);
+ cleanupReliableMessageRecordQueue();
+ return;
}
+ byte errorCode = ErrorCode.OK;
+ synchronized (mReliableMessageRecordQueue) {
+ Optional<ReliableMessageRecord> record =
+ findReliableMessageRecord(contextHubId,
+ message.getMessageSequenceNumber());
+
+ if (record.isPresent()) {
+ errorCode = record.get().getErrorCode();
+ if (errorCode == ErrorCode.TRANSIENT_ERROR) {
+ Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+ + record.get().getMessageSequenceNumber() + ": retrying");
+ errorCode = mClientManager.onMessageFromNanoApp(
+ contextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
+ record.get().setErrorCode(errorCode);
+ } else {
+ Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+ + record.get().getMessageSequenceNumber());
+ }
+ } else {
+ errorCode = mClientManager.onMessageFromNanoApp(
+ contextHubId, hostEndpointId, message,
+ nanoappPermissions, messagePermissions);
+ mReliableMessageRecordQueue.add(
+ new ReliableMessageRecord(contextHubId,
+ SystemClock.elapsedRealtimeNanos(),
+ message.getMessageSequenceNumber(),
+ errorCode));
+ }
+ }
+
+ sendMessageDeliveryStatusToContextHub(contextHubId,
+ message.getMessageSequenceNumber(), errorCode);
+ cleanupReliableMessageRecordQueue();
+ }
+
+ /**
+ * Finds a reliable message record in the queue that matches the given
+ * context hub ID and message sequence number. This function assumes
+ * the caller is synchronized on mReliableMessageRecordQueue.
+ *
+ * @param contextHubId the ID of the hub
+ * @param messageSequenceNumber the message sequence number
+ *
+ * @return the record if found, or empty if not found
+ */
+ private Optional<ReliableMessageRecord> findReliableMessageRecord(
+ int contextHubId, int messageSequenceNumber) {
+ for (ReliableMessageRecord record: mReliableMessageRecordQueue) {
+ if (record.getContextHubId() == contextHubId
+ && record.getMessageSequenceNumber() == messageSequenceNumber) {
+ return Optional.of(record);
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Removes old entries from the reliable message record queue.
+ */
+ private void cleanupReliableMessageRecordQueue() {
synchronized (mReliableMessageRecordQueue) {
while (mReliableMessageRecordQueue.peek() != null
&& mReliableMessageRecordQueue.peek().isExpired()) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index dbdb155..b14702d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -737,12 +737,13 @@
!mUserManager.isQuietModeEnabled(userHandle)) {
// Only show notifications for managed profiles once their parent
// user is unlocked.
- showEncryptionNotificationForProfile(userHandle, reason);
+ showEncryptionNotificationForProfile(userHandle, parent.getUserHandle(), reason);
}
}
}
- private void showEncryptionNotificationForProfile(UserHandle user, String reason) {
+ private void showEncryptionNotificationForProfile(UserHandle user, UserHandle parent,
+ String reason) {
CharSequence title = getEncryptionNotificationTitle();
CharSequence message = getEncryptionNotificationMessage();
CharSequence detail = getEncryptionNotificationDetail();
@@ -759,8 +760,15 @@
unlockIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent intent;
+ if (android.app.admin.flags.Flags.hsumUnlockNotificationFix()) {
+ intent = PendingIntent.getActivityAsUser(mContext, 0, unlockIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED,
+ null, parent);
+ } else {
+ intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ }
Slogf.d(TAG, "Showing encryption notification for user %d; reason: %s",
user.getIdentifier(), reason);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index a7fd750..386657e 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -81,6 +81,7 @@
MediaRoute2ProviderServiceProxy(
@NonNull Context context,
+ @NonNull Looper looper,
@NonNull ComponentName componentName,
boolean isSelfScanOnlyProvider,
int userId) {
@@ -88,7 +89,7 @@
mContext = Objects.requireNonNull(context, "Context must not be null.");
mIsSelfScanOnlyProvider = isSelfScanOnlyProvider;
mUserId = userId;
- mHandler = new Handler(Looper.myLooper());
+ mHandler = new Handler(looper);
}
public void setManagerScanning(boolean managerScanning) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 178eb71..7c1a5e1 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -142,6 +142,7 @@
MediaRoute2ProviderServiceProxy proxy =
new MediaRoute2ProviderServiceProxy(
mContext,
+ mHandler.getLooper(),
new ComponentName(serviceInfo.packageName, serviceInfo.name),
isSelfScanOnlyProvider,
mUserId);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e1f8939..c03497e 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -404,37 +404,17 @@
long managerRequestId,
@NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route,
- Bundle sessionHints,
- @Nullable UserHandle transferInitiatorUserHandle,
- @Nullable String transferInitiatorPackageName) {
+ Bundle sessionHints) {
Objects.requireNonNull(router, "router must not be null");
Objects.requireNonNull(oldSession, "oldSession must not be null");
Objects.requireNonNull(route, "route must not be null");
- synchronized (mLock) {
- if (managerRequestId == MediaRoute2ProviderService.REQUEST_ID_NONE
- || transferInitiatorUserHandle == null
- || transferInitiatorPackageName == null) {
- final IBinder binder = router.asBinder();
- final RouterRecord routerRecord = mAllRouterRecords.get(binder);
-
- transferInitiatorUserHandle = Binder.getCallingUserHandle();
- if (routerRecord != null) {
- transferInitiatorPackageName = routerRecord.mPackageName;
- } else {
- transferInitiatorPackageName = mContext.getPackageName();
- }
- }
- }
-
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
requestCreateSessionWithRouter2Locked(
requestId,
managerRequestId,
- transferInitiatorUserHandle,
- transferInitiatorPackageName,
router,
oldSession,
route,
@@ -1281,8 +1261,6 @@
private void requestCreateSessionWithRouter2Locked(
int requestId,
long managerRequestId,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName,
@NonNull IMediaRouter2 router,
@NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route,
@@ -1355,8 +1333,6 @@
userHandler,
uniqueRequestId,
managerRequestId,
- transferInitiatorUserHandle,
- transferInitiatorPackageName,
routerRecord,
oldSession,
route,
@@ -2695,11 +2671,7 @@
route = mSystemProvider.getDefaultRoute();
}
routerRecord.mRouter.requestCreateSessionByManager(
- uniqueRequestId,
- oldSession,
- route,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ uniqueRequestId, oldSession, route);
} catch (RemoteException ex) {
Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
+ "Failed to request. Router probably died.", ex);
@@ -2711,8 +2683,6 @@
private void requestCreateSessionWithRouter2OnHandler(
long uniqueRequestId,
long managerRequestId,
- @NonNull UserHandle transferInitiatorUserHandle,
- @NonNull String transferInitiatorPackageName,
@NonNull RouterRecord routerRecord,
@NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route,
@@ -2732,10 +2702,10 @@
managerRequestId, oldSession, route);
mSessionCreationRequests.add(request);
- int transferReason = RoutingSessionInfo.TRANSFER_REASON_APP;
- if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
- transferReason = RoutingSessionInfo.TRANSFER_REASON_SYSTEM_REQUEST;
- }
+ int transferReason =
+ managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE
+ ? RoutingSessionInfo.TRANSFER_REASON_SYSTEM_REQUEST
+ : RoutingSessionInfo.TRANSFER_REASON_APP;
provider.requestCreateSession(
uniqueRequestId,
@@ -2743,8 +2713,8 @@
route.getOriginalId(),
sessionHints,
transferReason,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ UserHandle.of(routerRecord.mUserRecord.mUserId),
+ routerRecord.mPackageName);
}
// routerRecord can be null if the session is system's or RCN.
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 064443c..192ac62 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -495,18 +495,9 @@
long managerRequestId,
RoutingSessionInfo oldSession,
MediaRoute2Info route,
- Bundle sessionHints,
- @Nullable UserHandle transferInitiatorUserHandle,
- @Nullable String transferInitiatorPackageName) {
+ Bundle sessionHints) {
mService2.requestCreateSessionWithRouter2(
- router,
- requestId,
- managerRequestId,
- oldSession,
- route,
- sessionHints,
- transferInitiatorUserHandle,
- transferInitiatorPackageName);
+ router, requestId, managerRequestId, oldSession, route, sessionHints);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index a20de31..bea71dc 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.Context;
import android.media.MediaMetadata;
@@ -247,7 +248,7 @@
}
@Override
- public void onAudioInfoChanged(MediaController.PlaybackInfo info) {
+ public void onAudioInfoChanged(@NonNull MediaController.PlaybackInfo info) {
mWriter.println("onAudioInfoChanged " + info);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b589f49..2fce295 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1446,6 +1446,7 @@
if (Flags.modesApi()) {
azr = new AutomaticZenRule.Builder(rule.name, rule.conditionId)
.setManualInvocationAllowed(rule.allowManualInvocation)
+ .setPackage(rule.pkg)
.setCreationTime(rule.creationTime)
.setIconResId(drawableResNameToResId(rule.pkg, rule.iconResName))
.setType(rule.type)
@@ -1464,8 +1465,8 @@
rule.conditionId, rule.zenPolicy,
NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
rule.enabled, rule.creationTime);
+ azr.setPackageName(rule.pkg);
}
- azr.setPackageName(rule.pkg);
return azr;
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index ac73382..dd76037 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.ondeviceintelligence;
+import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.DEVICE_CONFIG_UPDATE_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BUNDLE_KEY;
import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY;
@@ -115,9 +116,10 @@
/** Handler message to {@link #resetTemporaryServices()} */
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
-
/** Handler message to clean up temporary broadcast keys. */
private static final int MSG_RESET_BROADCAST_KEYS = 1;
+ /** Handler message to clean up temporary config namespace. */
+ private static final int MSG_RESET_CONFIG_NAMESPACE = 2;
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
@@ -129,6 +131,7 @@
private final Executor resourceClosingExecutor = Executors.newCachedThreadPool();
private final Executor callbackExecutor = Executors.newCachedThreadPool();
private final Executor broadcastExecutor = Executors.newCachedThreadPool();
+ private final Executor mConfigExecutor = Executors.newCachedThreadPool();
private final Context mContext;
@@ -145,6 +148,12 @@
private String[] mTemporaryBroadcastKeys;
@GuardedBy("mLock")
private String mBroadcastPackageName;
+ @GuardedBy("mLock")
+ private String mTemporaryConfigNamespace;
+
+ private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+ this::sendUpdatedConfig;
+
/**
* Handler used to reset the temporary service names.
@@ -593,12 +602,14 @@
@NonNull IOnDeviceSandboxedInferenceService service) {
try {
ensureRemoteIntelligenceServiceInitialized();
+ service.registerRemoteStorageService(
+ getIRemoteStorageService());
mRemoteOnDeviceIntelligenceService.run(
IOnDeviceIntelligenceService::notifyInferenceServiceConnected);
broadcastExecutor.execute(
() -> registerModelLoadingBroadcasts(service));
- service.registerRemoteStorageService(
- getIRemoteStorageService());
+ mConfigExecutor.execute(
+ () -> registerDeviceConfigChangeListener());
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to send connected event", ex);
}
@@ -658,6 +669,56 @@
}
}
+ private void registerDeviceConfigChangeListener() {
+ Log.d(TAG, "registerDeviceConfigChangeListener");
+ String configNamespace = getConfigNamespace();
+ if (configNamespace.isEmpty()) {
+ Slog.e(TAG, "config_defaultOnDeviceIntelligenceDeviceConfigNamespace is empty");
+ return;
+ }
+ DeviceConfig.addOnPropertiesChangedListener(
+ configNamespace,
+ mConfigExecutor,
+ mOnPropertiesChangedListener);
+ }
+
+ private String getConfigNamespace() {
+ synchronized (mLock) {
+ if (mTemporaryConfigNamespace != null) {
+ return mTemporaryConfigNamespace;
+ }
+
+ return mContext.getResources().getString(
+ R.string.config_defaultOnDeviceIntelligenceDeviceConfigNamespace);
+ }
+ }
+
+ private void sendUpdatedConfig(
+ DeviceConfig.Properties props) {
+ Log.d(TAG, "sendUpdatedConfig");
+
+ PersistableBundle persistableBundle = new PersistableBundle();
+ for (String key : props.getKeyset()) {
+ persistableBundle.putString(key, props.getString(key, ""));
+ }
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(DEVICE_CONFIG_UPDATE_BUNDLE_KEY, persistableBundle);
+ ensureRemoteInferenceServiceInitialized();
+ mRemoteInferenceService.run(service -> service.updateProcessingState(bundle,
+ new IProcessingUpdateStatusCallback.Stub() {
+ @Override
+ public void onSuccess(PersistableBundle result) {
+ Slog.d(TAG, "Config update successful." + result);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage) {
+ Slog.e(TAG, "Config update failed with code ["
+ + String.valueOf(errorCode) + "] and message = " + errorMessage);
+ }
+ }));
+ }
+
@NonNull
private IRemoteStorageService.Stub getIRemoteStorageService() {
return new IRemoteStorageService.Stub() {
@@ -849,6 +910,22 @@
}
@RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+ public void setTemporaryDeviceConfigNamespace(@NonNull String configNamespace,
+ int durationMs) {
+ Objects.requireNonNull(configNamespace);
+ enforceShellOnly(Binder.getCallingUid(), "setTemporaryDeviceConfigNamespace");
+ mContext.enforceCallingPermission(
+ Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+ synchronized (mLock) {
+ mTemporaryConfigNamespace = configNamespace;
+ if (durationMs != -1) {
+ getTemporaryHandler().sendEmptyMessageDelayed(MSG_RESET_CONFIG_NAMESPACE,
+ durationMs);
+ }
+ }
+ }
+
+ @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
public void resetTemporaryServices() {
mContext.enforceCallingPermission(
Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
@@ -936,17 +1013,17 @@
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
- if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
resetTemporaryServices();
- }
- } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
- synchronized (mLock) {
+ } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
mTemporaryBroadcastKeys = null;
mBroadcastPackageName = SYSTEM_PACKAGE;
+ } else if (msg.what == MSG_RESET_CONFIG_NAMESPACE) {
+ mTemporaryConfigNamespace = null;
+ } else {
+ Slog.wtf(TAG, "invalid handler msg: " + msg);
}
- } else {
- Slog.wtf(TAG, "invalid handler msg: " + msg);
}
}
};
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
index b52812f..d2c84fa 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
@@ -46,6 +46,8 @@
return getConfiguredServices();
case "set-model-broadcasts":
return setBroadcastKeys();
+ case "set-deviceconfig-namespace":
+ return setDeviceConfigNamespace();
default:
return handleDefaultCommands(cmd);
}
@@ -70,6 +72,10 @@
+ "[ReceiverPackageName] "
+ "[DURATION] To set the names of broadcast intent keys that are to be "
+ "emitted for cts tests.");
+ pw.println(
+ " set-deviceconfig-namespace [DeviceConfigNamespace] "
+ + "[DURATION] To set the device config namespace "
+ + "to use for cts tests.");
}
private int setTemporaryServices() {
@@ -123,4 +129,16 @@
return 0;
}
+ private int setDeviceConfigNamespace() {
+ final PrintWriter out = getOutPrintWriter();
+ final String configNamespace = getNextArg();
+
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryDeviceConfigNamespace(configNamespace, duration);
+ out.println("OnDeviceIntelligence DeviceConfig Namespace temporarily set to "
+ + configNamespace
+ + " for " + duration + "ms");
+ return 0;
+ }
+
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 71a7d0d..f07b710 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.os;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+import static android.app.admin.flags.Flags.onboardingConsentlessBugreports;
import android.Manifest;
import android.annotation.NonNull;
@@ -31,6 +32,7 @@
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
+import android.os.Build;
import android.os.Environment;
import android.os.IDumpstate;
import android.os.IDumpstateListener;
@@ -69,12 +71,14 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Implementation of the service that provides a privileged API to capture and consume bugreports.
@@ -98,6 +102,9 @@
private static final String BUGREPORT_SERVICE = "bugreportd";
private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
+ private static final long DEFAULT_BUGREPORT_CONSENTLESS_GRACE_PERIOD_MILLIS =
+ TimeUnit.MINUTES.toMillis(2);
+
private final Object mLock = new Object();
private final Injector mInjector;
private final Context mContext;
@@ -132,6 +139,10 @@
private ArrayMap<Pair<Integer, String>, ArraySet<String>> mBugreportFiles =
new ArrayMap<>();
+ // Map of <CallerPackage, Pair<TimestampOfLastConsent, skipConsentForFullReport>>
+ @GuardedBy("mLock")
+ private Map<String, Pair<Long, Boolean>> mConsentGranted = new HashMap<>();
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@GuardedBy("mLock")
final Set<String> mBugreportFilesToPersist = new HashSet<>();
@@ -238,6 +249,64 @@
}
}
+ /**
+ * Logs an entry with a timestamp of a consent being granted by the user to the calling
+ * {@code packageName}.
+ */
+ void logConsentGrantedForCaller(
+ String packageName, boolean consentGranted, boolean isDeferredReport) {
+ if (!onboardingConsentlessBugreports() || !Build.IS_DEBUGGABLE) {
+ return;
+ }
+ synchronized (mLock) {
+ // Adds an entry with the timestamp of the consent being granted by the user, and
+ // whether the consent can be skipped for a full bugreport, because a single
+ // consent can be used for multiple deferred reports but only one full report.
+ if (consentGranted) {
+ mConsentGranted.put(packageName, new Pair<>(
+ System.currentTimeMillis(),
+ isDeferredReport));
+ } else if (!isDeferredReport) {
+ if (!mConsentGranted.containsKey(packageName)) {
+ Slog.e(TAG, "Previous consent from package: " + packageName + " should"
+ + "have been logged.");
+ return;
+ }
+ mConsentGranted.put(packageName, new Pair<>(
+ mConsentGranted.get(packageName).first,
+ /* second = */ false
+ ));
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if user consent be skippeb because a previous consens has been
+ * granted to the caller within the allowed time period.
+ */
+ boolean canSkipConsentScreen(String packageName, boolean isFullReport) {
+ if (!onboardingConsentlessBugreports() || !Build.IS_DEBUGGABLE) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (!mConsentGranted.containsKey(packageName)) {
+ return false;
+ }
+ long currentTime = System.currentTimeMillis();
+ long consentGrantedTime = mConsentGranted.get(packageName).first;
+ if (consentGrantedTime + DEFAULT_BUGREPORT_CONSENTLESS_GRACE_PERIOD_MILLIS
+ < currentTime) {
+ mConsentGranted.remove(packageName);
+ return false;
+ }
+ boolean skipConsentForFullReport = mConsentGranted.get(packageName).second;
+ if (isFullReport && !skipConsentForFullReport) {
+ return false;
+ }
+ return true;
+ }
+ }
+
private void addBugreportMapping(Pair<Integer, String> caller, String bugreportFile) {
synchronized (mLock) {
if (!mBugreportFiles.containsKey(caller)) {
@@ -418,7 +487,7 @@
public void startBugreport(int callingUidUnused, String callingPackage,
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
int bugreportMode, int bugreportFlags, IDumpstateListener listener,
- boolean isScreenshotRequested) {
+ boolean isScreenshotRequested, boolean skipUserConsentUnused) {
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(bugreportFd);
Objects.requireNonNull(listener);
@@ -509,7 +578,8 @@
@RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
FileDescriptor bugreportFd, String bugreportFile,
- boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
+ boolean keepBugreportOnRetrievalUnused, boolean skipUserConsentUnused,
+ IDumpstateListener listener) {
int callingUid = Binder.getCallingUid();
enforcePermission(callingPackage, callingUid, false);
@@ -540,9 +610,13 @@
return;
}
+ boolean skipUserConsent = mBugreportFileManager.canSkipConsentScreen(
+ callingPackage, /* isFullReport = */ false);
+
// Wrap the listener so we can intercept binder events directly.
DumpstateListener myListener = new DumpstateListener(listener, ds,
- new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true);
+ new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true,
+ !skipUserConsent, /* isDeferredReport = */ true);
boolean keepBugreportOnRetrieval = false;
if (onboardingBugreportV2Enabled()) {
@@ -553,7 +627,7 @@
setCurrentDumpstateListenerLocked(myListener);
try {
ds.retrieveBugreport(callingUid, callingPackage, userId, bugreportFd,
- bugreportFile, keepBugreportOnRetrieval, myListener);
+ bugreportFile, keepBugreportOnRetrieval, skipUserConsent, myListener);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException in retrieveBugreport", e);
}
@@ -754,7 +828,7 @@
}
}
- boolean reportFinishedFile =
+ boolean isDeferredConsentReport =
(bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0;
boolean keepBugreportOnRetrieval =
@@ -766,14 +840,17 @@
reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
return;
}
-
+ boolean skipUserConsent = mBugreportFileManager.canSkipConsentScreen(
+ callingPackage, !isDeferredConsentReport);
DumpstateListener myListener = new DumpstateListener(listener, ds,
- new Pair<>(callingUid, callingPackage), reportFinishedFile,
- keepBugreportOnRetrieval);
+ new Pair<>(callingUid, callingPackage),
+ /* reportFinishedFile = */ isDeferredConsentReport, keepBugreportOnRetrieval,
+ !isDeferredConsentReport && !skipUserConsent,
+ isDeferredConsentReport);
setCurrentDumpstateListenerLocked(myListener);
try {
ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode,
- bugreportFlags, myListener, isScreenshotRequested);
+ bugreportFlags, myListener, isScreenshotRequested, skipUserConsent);
} catch (RemoteException e) {
// dumpstate service is already started now. We need to kill it to manage the
// lifecycle correctly. If we don't subsequent callers will get
@@ -930,14 +1007,21 @@
private boolean mDone;
private boolean mKeepBugreportOnRetrieval;
+ private boolean mConsentGranted;
+
+ private boolean mIsDeferredReport;
+
DumpstateListener(IDumpstateListener listener, IDumpstate ds,
- Pair<Integer, String> caller, boolean reportFinishedFile) {
- this(listener, ds, caller, reportFinishedFile, /* keepBugreportOnRetrieval= */ false);
+ Pair<Integer, String> caller, boolean reportFinishedFile,
+ boolean consentGranted, boolean isDeferredReport) {
+ this(listener, ds, caller, reportFinishedFile, /* keepBugreportOnRetrieval= */ false,
+ consentGranted, isDeferredReport);
}
DumpstateListener(IDumpstateListener listener, IDumpstate ds,
Pair<Integer, String> caller, boolean reportFinishedFile,
- boolean keepBugreportOnRetrieval) {
+ boolean keepBugreportOnRetrieval, boolean consentGranted,
+ boolean isDeferredReport) {
if (DEBUG) {
Slogf.d(TAG, "Starting DumpstateListener(id=%d) for caller %s", mId, caller);
}
@@ -946,6 +1030,8 @@
mCaller = caller;
mReportFinishedFile = reportFinishedFile;
mKeepBugreportOnRetrieval = keepBugreportOnRetrieval;
+ mConsentGranted = consentGranted;
+ mIsDeferredReport = isDeferredReport;
try {
mDs.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -985,6 +1071,8 @@
} else if (DEBUG) {
Slog.d(TAG, "Not reporting finished file");
}
+ mBugreportFileManager.logConsentGrantedForCaller(
+ mCaller.second, mConsentGranted, mIsDeferredReport);
mListener.onFinished(bugreportFile);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 472f228..6cfa09f 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -511,14 +511,13 @@
// metadata file on the system image. Do not reset the path and source if this is the
// case.
if (pkgSetting.getAppMetadataFilePath() == null) {
- File dir = new File(pkg.getPath());
+ String dir = pkg.getPath();
if (pkgSetting.isSystem()) {
- dir = new File(Environment.getDataDirectory(),
- "app-metadata/" + pkg.getPackageName());
+ dir = Environment.getDataDirectoryPath() + "/app-metadata/" + pkg.getPackageName();
}
- File appMetadataFile = new File(dir, APP_METADATA_FILE_NAME);
- if (appMetadataFile.exists()) {
- pkgSetting.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+ String appMetadataFilePath = dir + "/" + APP_METADATA_FILE_NAME;
+ if (request.hasAppMetadataFile()) {
+ pkgSetting.setAppMetadataFilePath(appMetadataFilePath);
if (Flags.aslInApkAppMetadataSource()) {
pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
}
@@ -526,7 +525,7 @@
Map<String, PackageManager.Property> properties = pkg.getProperties();
if (properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL)) {
// ASL file extraction is done in post-install
- pkgSetting.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+ pkgSetting.setAppMetadataFilePath(appMetadataFilePath);
pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_APK);
}
}
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 6d38517..8f51e36 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -167,6 +167,8 @@
private int mInstallerUidForInstallExisting = INVALID_UID;
+ private final boolean mHasAppMetadataFileFromInstaller;
+
// New install
InstallRequest(InstallingSession params) {
mUserId = params.getUser().getIdentifier();
@@ -185,6 +187,7 @@
mSessionId = params.mSessionId;
mRequireUserAction = params.mRequireUserAction;
mPreVerifiedDomains = params.mPreVerifiedDomains;
+ mHasAppMetadataFileFromInstaller = params.mHasAppMetadataFile;
}
// Install existing package as user
@@ -203,6 +206,7 @@
mAppId = appId;
mInstallerUidForInstallExisting = installerUid;
mSystem = isSystem;
+ mHasAppMetadataFileFromInstaller = false;
}
// addForInit
@@ -224,6 +228,7 @@
mSessionId = -1;
mRequireUserAction = USER_ACTION_UNSPECIFIED;
mDisabledPs = disabledPs;
+ mHasAppMetadataFileFromInstaller = false;
}
@Nullable
@@ -371,6 +376,10 @@
return PackageInstallerSession.isArchivedInstallation(getInstallFlags());
}
+ public boolean hasAppMetadataFile() {
+ return mHasAppMetadataFileFromInstaller;
+ }
+
@Nullable
public String getRemovedPackage() {
return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 4cbd3ad..b06c7cb 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -101,6 +101,7 @@
final boolean mApplicationEnabledSettingPersistent;
@Nullable
final DomainSet mPreVerifiedDomains;
+ final boolean mHasAppMetadataFile;
// For move install
InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
@@ -134,12 +135,14 @@
mRequireUserAction = USER_ACTION_UNSPECIFIED;
mApplicationEnabledSettingPersistent = false;
mPreVerifiedDomains = null;
+ mHasAppMetadataFile = false;
}
InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer,
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
UserHandle user, SigningDetails signingDetails, int installerUid,
- PackageLite packageLite, DomainSet preVerifiedDomains, PackageManagerService pm) {
+ PackageLite packageLite, DomainSet preVerifiedDomains, PackageManagerService pm,
+ boolean hasAppMetadatafile) {
mPm = pm;
mUser = user;
mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
@@ -168,6 +171,7 @@
mRequireUserAction = sessionParams.requireUserAction;
mApplicationEnabledSettingPersistent = sessionParams.applicationEnabledSettingPersistent;
mPreVerifiedDomains = preVerifiedDomains;
+ mHasAppMetadataFile = hasAppMetadatafile;
}
@Override
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 4c95e83..563cfa4 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1239,6 +1239,8 @@
@NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser) {
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
+ Log.e(TAG, "return empty shortcuts because callingPackage " + callingPackage
+ + " cannot access user " + targetUser.getIdentifier());
return new ParceledListSlice<>(Collections.EMPTY_LIST);
}
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index 7c56157..0afda45 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import dalvik.system.CloseGuard;
@@ -76,8 +77,13 @@
ps = mPm.mSettings.getPackageLPr(mPackageName);
}
if (ps != null) {
- mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
- exitInfoReason);
+ if (Flags.waitApplicationKilled()) {
+ mPm.killApplicationSync(ps.getPackageName(), ps.getAppId(), userId, killReason,
+ exitInfoReason);
+ } else {
+ mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
+ exitInfoReason);
+ }
}
mCloseGuard.open("close");
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 80a5f3a..57f6d27 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -601,6 +601,9 @@
@GuardedBy("mLock")
private String mSessionErrorMessage;
+ @GuardedBy("mLock")
+ private boolean mHasAppMetadataFile = false;
+
@Nullable
final StagedSession mStagedSession;
@@ -1814,7 +1817,7 @@
assertCallerIsOwnerOrRoot();
synchronized (mLock) {
assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd");
- if (!getStagedAppMetadataFile().exists()) {
+ if (!mHasAppMetadataFile) {
return null;
}
try {
@@ -1827,9 +1830,11 @@
@Override
public void removeAppMetadata() {
- File file = getStagedAppMetadataFile();
- if (file.exists()) {
- file.delete();
+ synchronized (mLock) {
+ if (mHasAppMetadataFile) {
+ getStagedAppMetadataFile().delete();
+ mHasAppMetadataFile = false;
+ }
}
}
@@ -1850,8 +1855,12 @@
assertPreparedAndNotSealedLocked("openWriteAppMetadata");
}
try {
- return doWriteInternal(APP_METADATA_FILE_NAME, /* offsetBytes= */ 0,
+ ParcelFileDescriptor fd = doWriteInternal(APP_METADATA_FILE_NAME, /* offsetBytes= */ 0,
/* lengthBytes= */ -1, null);
+ synchronized (mLock) {
+ mHasAppMetadataFile = true;
+ }
+ return fd;
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
@@ -2145,18 +2154,21 @@
}
}
- File appMetadataFile = getStagedAppMetadataFile();
- if (appMetadataFile.exists()) {
- long sizeLimit = getAppMetadataSizeLimit();
- if (appMetadataFile.length() > sizeLimit) {
- appMetadataFile.delete();
- throw new IllegalArgumentException(
- "App metadata size exceeds the maximum allowed limit of " + sizeLimit);
- }
- if (isIncrementalInstallation()) {
- // Incremental requires stageDir to be empty so move the app metadata file to a
- // temporary location and move back after commit.
- appMetadataFile.renameTo(getTmpAppMetadataFile());
+ synchronized (mLock) {
+ if (mHasAppMetadataFile) {
+ File appMetadataFile = getStagedAppMetadataFile();
+ long sizeLimit = getAppMetadataSizeLimit();
+ if (appMetadataFile.length() > sizeLimit) {
+ appMetadataFile.delete();
+ mHasAppMetadataFile = false;
+ throw new IllegalArgumentException(
+ "App metadata size exceeds the maximum allowed limit of " + sizeLimit);
+ }
+ if (isIncrementalInstallation()) {
+ // Incremental requires stageDir to be empty so move the app metadata file to a
+ // temporary location and move back after commit.
+ appMetadataFile.renameTo(getTmpAppMetadataFile());
+ }
}
}
@@ -3207,7 +3219,8 @@
synchronized (mLock) {
return new InstallingSession(sessionId, stageDir, localObserver, params, mInstallSource,
- user, mSigningDetails, mInstallerUid, mPackageLite, mPreVerifiedDomains, mPm);
+ user, mSigningDetails, mInstallerUid, mPackageLite, mPreVerifiedDomains, mPm,
+ mHasAppMetadataFile);
}
}
@@ -3445,9 +3458,14 @@
}
}
+ if (mHasAppMetadataFile && !getStagedAppMetadataFile().exists()) {
+ throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE,
+ "App metadata file expected but not found in " + stageDir.getAbsolutePath());
+ }
+
final List<ApkLite> addedFiles = getAddedApkLitesLocked();
if (addedFiles.isEmpty()
- && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) {
+ && (removeSplitList.size() == 0 || mHasAppMetadataFile)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
stageDir.getAbsolutePath()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fda8535..f8fceda 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -53,6 +53,7 @@
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.ApplicationExitInfo;
import android.app.ApplicationPackageManager;
@@ -3132,6 +3133,20 @@
}
}
+ void killApplicationSync(String pkgName, @AppIdInt int appId,
+ @UserIdInt int userId, String reason, int exitInfoReason) {
+ ActivityManagerInternal mAmi = LocalServices.getService(ActivityManagerInternal.class);
+ if (mAmi != null) {
+ if (Thread.holdsLock(mLock)) {
+ // holds PM's lock, go back killApplication to avoid it run into watchdog reset.
+ Slog.e(TAG, "Holds PM's locker, unable kill application synchronized");
+ killApplication(pkgName, appId, userId, reason, exitInfoReason);
+ } else {
+ mAmi.killApplicationSync(pkgName, appId, userId, reason, exitInfoReason);
+ }
+ }
+ }
+
@Override
public void notifyPackageAdded(String packageName, int uid) {
mPackageObserverHelper.notifyAdded(packageName, uid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 23ae983..6700f00 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1252,7 +1252,7 @@
}
final ParsedMainComponent comp = componentInfoToComponent(
resolveInfo.getComponentInfo(), resolver, isReceiver);
- if (!comp.getIntents().isEmpty() && intent.getAction() == null) {
+ if (comp != null && !comp.getIntents().isEmpty() && intent.getAction() == null) {
match = false;
}
} else if (c instanceof IntentFilter) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index c929c1f..84674b2 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -850,6 +850,8 @@
@Nullable Predicate<ShortcutInfo> filter, int cloneFlag,
@Nullable String callingLauncher, int launcherUserId, boolean getPinnedByAnyLauncher) {
if (getPackageInfo().isShadow()) {
+ Log.d(TAG, "findAll() returned empty results because " + getPackageName()
+ + " isn't installed yet");
// Restored and the app not installed yet, so don't return any.
return;
}
@@ -877,6 +879,8 @@
if (!getPinnedByAnyLauncher) {
if (si.isFloating() && !si.isCached()) {
if (!isPinnedByCaller) {
+ Log.d(TAG, si.getId() + " ignored because it isn't pinned by "
+ + callingLauncher);
return;
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 9edf3b1..1cd77ff 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3029,6 +3029,10 @@
final ShortcutUser user = getUserShortcutsLocked(userId);
final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
if (p == null) {
+ if (DEBUG_REBOOT) {
+ Log.d(TAG, "getShortcutsInnerLocked() returned empty results because "
+ + packageName + " isn't loaded");
+ }
return; // No need to instantiate ShortcutPackage.
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5fa8856..11b9e77 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -64,6 +64,7 @@
import com.android.server.input.InputManagerInternal;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.feature.PowerManagerFlags;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
@@ -187,11 +188,16 @@
private final AtomicBoolean mIsPlayingChargingStartedFeedback = new AtomicBoolean(false);
+ private final Injector mInjector;
+
+ private final PowerManagerFlags mFlags;
+
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
- Executor backgroundExecutor) {
+ Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) {
mContext = context;
+ mFlags = powerManagerFlags;
mBatteryStats = batteryStats;
mAppOps = mContext.getSystemService(AppOpsManager.class);
mSuspendBlocker = suspendBlocker;
@@ -224,8 +230,8 @@
mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
- mWakeLockLog = new WakeLockLog(context);
-
+ mInjector = (injector == null) ? new RealInjector() : injector;
+ mWakeLockLog = mInjector.getWakeLockLog(context);
// Initialize interactive state for battery stats.
try {
mBatteryStats.noteInteractive(true);
@@ -267,7 +273,7 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, true);
+ notifyWakeLockListener(callback, tag, true, ownerUid, flags);
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
if (monitorType >= 0) {
try {
@@ -287,8 +293,9 @@
}
}
- mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags);
-
+ if (!mFlags.improveWakelockLatency()) {
+ mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
+ }
mWakefulnessSessionObserver.onWakeLockAcquired(flags);
}
@@ -406,7 +413,7 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, false);
+ notifyWakeLockListener(callback, tag, false, ownerUid, flags);
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
if (monitorType >= 0) {
try {
@@ -422,8 +429,9 @@
// Ignore
}
}
- mWakeLockLog.onWakeLockReleased(tag, ownerUid);
-
+ if (!mFlags.improveWakelockLatency()) {
+ mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
+ }
mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
}
@@ -1040,10 +1048,19 @@
return enabled && dndOff;
}
- private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled) {
+ private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled,
+ int ownerUid, int flags) {
if (callback != null) {
+ long currentTime = mInjector.currentTimeMillis();
mHandler.post(() -> {
try {
+ if (mFlags.improveWakelockLatency()) {
+ if (isEnabled) {
+ mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+ } else {
+ mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
+ }
+ }
callback.onStateChanged(isEnabled);
} catch (RemoteException e) {
Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
@@ -1057,6 +1074,7 @@
public NotifierHandler(Looper looper) {
super(looper, null, true /*async*/);
}
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -1085,4 +1103,28 @@
}
}
}
+
+ public interface Injector {
+ /**
+ * Gets the current time in millis
+ */
+ long currentTimeMillis();
+
+ /**
+ * Gets the WakeLockLog object
+ */
+ WakeLockLog getWakeLockLog(Context context);
+ }
+
+ static class RealInjector implements Injector {
+ @Override
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ @Override
+ public WakeLockLog getWakeLockLog(Context context) {
+ return new WakeLockLog(context);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 76cedd8..ce0120c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -988,10 +988,10 @@
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
- Executor backgroundExecutor) {
+ Executor backgroundExecutor, PowerManagerFlags powerManagerFlags) {
return new Notifier(
looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
- screenUndimDetector, backgroundExecutor);
+ screenUndimDetector, backgroundExecutor, powerManagerFlags, /*injector=*/ null);
}
SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -1373,7 +1373,7 @@
mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
mPolicy, mFaceDownDetector, mScreenUndimDetector,
- BackgroundThread.getExecutor());
+ BackgroundThread.getExecutor(), mFeatureFlags);
mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP,
new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener,
diff --git a/services/core/java/com/android/server/power/WakeLockLog.java b/services/core/java/com/android/server/power/WakeLockLog.java
index b131311..968ff59 100644
--- a/services/core/java/com/android/server/power/WakeLockLog.java
+++ b/services/core/java/com/android/server/power/WakeLockLog.java
@@ -154,9 +154,10 @@
* @param tag The wake lock tag
* @param ownerUid The owner UID of the wake lock.
* @param flags Flags used for the wake lock.
+ * @param eventTime The time at which the event occurred
*/
- public void onWakeLockAcquired(String tag, int ownerUid, int flags) {
- onWakeLockEvent(TYPE_ACQUIRE, tag, ownerUid, flags);
+ public void onWakeLockAcquired(String tag, int ownerUid, int flags, long eventTime) {
+ onWakeLockEvent(TYPE_ACQUIRE, tag, ownerUid, flags, eventTime);
}
/**
@@ -164,9 +165,10 @@
*
* @param tag The wake lock tag
* @param ownerUid The owner UID of the wake lock.
+ * @param eventTime The time at which the event occurred
*/
- public void onWakeLockReleased(String tag, int ownerUid) {
- onWakeLockEvent(TYPE_RELEASE, tag, ownerUid, 0 /* flags */);
+ public void onWakeLockReleased(String tag, int ownerUid, long eventTime) {
+ onWakeLockEvent(TYPE_RELEASE, tag, ownerUid, 0 /* flags */, eventTime);
}
/**
@@ -242,9 +244,10 @@
* @param tag The wake lock's identifying tag.
* @param ownerUid The owner UID of the wake lock.
* @param flags The flags used with the wake lock.
+ * @param eventTime The time at which the event occurred
*/
private void onWakeLockEvent(int eventType, String tag, int ownerUid,
- int flags) {
+ int flags, long eventTime) {
if (tag == null) {
Slog.w(TAG, "Insufficient data to log wakelock [tag: " + tag
+ ", ownerUid: " + ownerUid
@@ -252,7 +255,8 @@
return;
}
- final long time = mInjector.currentTimeMillis();
+ final long time = (eventTime == -1) ? mInjector.currentTimeMillis() : eventTime;
+
final int translatedFlags = eventType == TYPE_ACQUIRE
? translateFlagsFromPowerManager(flags)
: 0;
diff --git a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
index a5a7069..ff1d2e4 100644
--- a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
+++ b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
@@ -35,18 +35,31 @@
Flags.FLAG_ENABLE_EARLY_SCREEN_TIMEOUT_DETECTOR,
Flags::enableEarlyScreenTimeoutDetector);
+ private final FlagState mImproveWakelockLatency = new FlagState(
+ Flags.FLAG_IMPROVE_WAKELOCK_LATENCY,
+ Flags::improveWakelockLatency
+ );
+
/** Returns whether early-screen-timeout-detector is enabled on not. */
public boolean isEarlyScreenTimeoutDetectorEnabled() {
return mEarlyScreenTimeoutDetectorFlagState.isEnabled();
}
/**
+ * @return Whether to improve the wakelock acquire/release latency or not
+ */
+ public boolean improveWakelockLatency() {
+ return mImproveWakelockLatency.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
public void dump(PrintWriter pw) {
pw.println("PowerManagerFlags:");
pw.println(" " + mEarlyScreenTimeoutDetectorFlagState);
+ pw.println(" " + mImproveWakelockLatency);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/power/feature/power_flags.aconfig b/services/core/java/com/android/server/power/feature/power_flags.aconfig
index ca58153..3581b2f 100644
--- a/services/core/java/com/android/server/power/feature/power_flags.aconfig
+++ b/services/core/java/com/android/server/power/feature/power_flags.aconfig
@@ -10,3 +10,11 @@
bug: "309861917"
is_fixed_read_only: true
}
+
+flag {
+ name: "improve_wakelock_latency"
+ namespace: "power"
+ description: "Feature flag for tracking the optimizations to improve the latency of acquiring and releasing a wakelock."
+ bug: "339590565"
+ is_fixed_read_only: true
+}
\ No newline at end of file
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 267ddd0..df502eb 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -371,6 +371,7 @@
if (tokenMap == null) {
return;
}
+ Slog.d(TAG, "Uid gone for " + uid);
for (int i = tokenMap.size() - 1; i >= 0; i--) {
// Will remove the session from tokenMap
ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(i);
@@ -400,27 +401,31 @@
public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
FgThread.getHandler().post(() -> {
synchronized (mLock) {
+ boolean shouldCleanup = false;
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);
+ int prevProcState = mProcStatesCache.get(uid, Integer.MAX_VALUE);
+ shouldCleanup =
+ prevProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ && procState
+ > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
- boolean shouldAllowUpdate = isUidForeground(uid);
+
+ mProcStatesCache.put(uid, procState);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(uid);
if (tokenMap == null) {
return;
}
+ if (shouldCleanup && powerhintThreadCleanup()) {
+ final Message msg = mCleanUpHandler.obtainMessage(EVENT_CLEAN_UP_UID,
+ uid);
+ mCleanUpHandler.sendMessageDelayed(msg, CLEAN_UP_UID_DELAY_MILLIS);
+ Slog.d(TAG, "Sent cleanup message for uid " + uid);
+ }
+ boolean shouldAllowUpdate = isUidForeground(uid);
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);
+ sessionSet.valueAt(j).updateHintAllowedByProcState(shouldAllowUpdate);
}
}
}
@@ -552,8 +557,10 @@
removeEqualMessages(msg.what, msg.obj);
final Message newMsg = obtainMessage(msg.what, msg.obj);
sendMessageDelayed(newMsg, CLEAN_UP_UID_DELAY_MILLIS);
+ Slog.d(TAG, "Duplicate messages for " + msg.obj);
return;
}
+ Slog.d(TAG, "Starts cleaning for " + msg.obj);
final int uid = (int) msg.obj;
boolean isForeground = mUidObserver.isUidForeground(uid);
// store all sessions in a list and release the global lock
@@ -621,7 +628,7 @@
FrameworkStatsLog.write(FrameworkStatsLog.ADPF_HINT_SESSION_TID_CLEANUP, uid,
totalDurationUs, maxDurationUs, totalTidCnt, totalInvalidTidCnt,
maxInvalidTidCnt, sessionCnt, isForeground);
- Slog.d(TAG,
+ Slog.w(TAG,
"Invalid tid found for UID" + uid + " in " + totalDurationUs + "us:\n\t"
+ "count("
+ " session: " + sessionCnt
@@ -643,7 +650,7 @@
// 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()) {
+ if (session.isClosed() || session.isForcePaused()) {
return 0;
}
final int pid = session.mPid;
@@ -705,7 +712,7 @@
final int[] filteredTids = filtered.toArray();
if (filteredTids.length == 0) {
session.mShouldForcePause = true;
- if (session.mUpdateAllowed) {
+ if (session.mUpdateAllowedByProcState) {
session.pause();
}
} else {
@@ -951,7 +958,7 @@
protected final IBinder mToken;
protected long mHalSessionPtr;
protected long mTargetDurationNanos;
- protected boolean mUpdateAllowed;
+ protected boolean mUpdateAllowedByProcState;
protected int[] mNewThreadIds;
protected boolean mPowerEfficient;
protected boolean mShouldForcePause;
@@ -969,11 +976,11 @@
mThreadIds = threadIds;
mHalSessionPtr = halSessionPtr;
mTargetDurationNanos = durationNanos;
- mUpdateAllowed = true;
+ mUpdateAllowedByProcState = true;
mPowerEfficient = false;
mShouldForcePause = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
- updateHintAllowed(allowed);
+ updateHintAllowedByProcState(allowed);
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -983,19 +990,23 @@
}
@VisibleForTesting
- boolean updateHintAllowed(boolean allowed) {
+ boolean updateHintAllowedByProcState(boolean allowed) {
synchronized (this) {
- if (allowed && !mUpdateAllowed && !mShouldForcePause) resume();
- if (!allowed && mUpdateAllowed) pause();
- mUpdateAllowed = allowed;
- return mUpdateAllowed;
+ if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) resume();
+ if (!allowed && mUpdateAllowedByProcState) pause();
+ mUpdateAllowedByProcState = allowed;
+ return mUpdateAllowedByProcState;
}
}
+ boolean isHintAllowed() {
+ return mHalSessionPtr != 0 && mUpdateAllowedByProcState && !mShouldForcePause;
+ }
+
@Override
public void updateTargetWorkDuration(long targetDurationNanos) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
+ if (!isHintAllowed()) {
return;
}
Preconditions.checkArgument(targetDurationNanos > 0, "Expected"
@@ -1008,7 +1019,7 @@
@Override
public void reportActualWorkDuration(long[] actualDurationNanos, long[] timeStampNanos) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
+ if (!isHintAllowed()) {
return;
}
Preconditions.checkArgument(actualDurationNanos.length != 0, "the count"
@@ -1073,7 +1084,7 @@
@Override
public void sendHint(@PerformanceHintManager.Session.Hint int hint) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
+ if (!isHintAllowed()) {
return;
}
Preconditions.checkArgument(hint >= 0, "the hint ID value should be"
@@ -1095,7 +1106,7 @@
if (mHalSessionPtr == 0) {
return;
}
- if (!mUpdateAllowed) {
+ if (!mUpdateAllowedByProcState) {
Slogf.v(TAG, "update hint not allowed, storing tids.");
mNewThreadIds = tids;
mShouldForcePause = false;
@@ -1160,10 +1171,15 @@
}
}
+ boolean isForcePaused() {
+ synchronized (this) {
+ return mShouldForcePause;
+ }
+ }
@Override
public void setMode(int mode, boolean enabled) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
+ if (!isHintAllowed()) {
return;
}
Preconditions.checkArgument(mode >= 0, "the mode Id value should be"
@@ -1178,7 +1194,7 @@
@Override
public void reportActualWorkDuration2(WorkDuration[] workDurations) {
synchronized (this) {
- if (mHalSessionPtr == 0 || !mUpdateAllowed || mShouldForcePause) {
+ if (!isHintAllowed()) {
return;
}
Preconditions.checkArgument(workDurations.length != 0, "the count"
@@ -1241,10 +1257,6 @@
}
}
- private void onProcStateChanged(boolean updateAllowed) {
- updateHintAllowed(updateAllowed);
- }
-
private void pause() {
synchronized (this) {
if (mHalSessionPtr == 0) return;
@@ -1270,7 +1282,7 @@
pw.println(prefix + "SessionUID: " + mUid);
pw.println(prefix + "SessionTIDs: " + Arrays.toString(mThreadIds));
pw.println(prefix + "SessionTargetDurationNanos: " + mTargetDurationNanos);
- pw.println(prefix + "SessionAllowed: " + mUpdateAllowed);
+ pw.println(prefix + "SessionAllowedByProcState: " + mUpdateAllowedByProcState);
pw.println(prefix + "SessionForcePaused: " + mShouldForcePause);
pw.println(prefix + "PowerEfficient: " + (mPowerEfficient ? "true" : "false"));
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index cb10da9..2f16419 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -572,34 +572,41 @@
}
if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
- // We were asked to fetch Bluetooth data.
- final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null) {
- SynchronousResultReceiver resultReceiver =
- new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(
- Runnable::run,
- new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() {
- @Override
- public void onBluetoothActivityEnergyInfoAvailable(
- BluetoothActivityEnergyInfo info) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(
- BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
- resultReceiver.send(0, bundle);
- }
+ @SuppressWarnings("GuardedBy")
+ PowerStatsCollector collector = mStats.getPowerStatsCollector(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
+ if (collector.isEnabled()) {
+ collector.schedule();
+ } else {
+ // We were asked to fetch Bluetooth data.
+ final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ SynchronousResultReceiver resultReceiver =
+ new SynchronousResultReceiver("bluetooth");
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() {
+ @Override
+ public void onBluetoothActivityEnergyInfoAvailable(
+ BluetoothActivityEnergyInfo info) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ resultReceiver.send(0, bundle);
+ }
- @Override
- public void onBluetoothActivityEnergyInfoError(int errorCode) {
- Slog.w(TAG, "error reading Bluetooth stats: " + errorCode);
- Bundle bundle = new Bundle();
- bundle.putParcelable(
- BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, null);
- resultReceiver.send(0, bundle);
+ @Override
+ public void onBluetoothActivityEnergyInfoError(int errorCode) {
+ Slog.w(TAG, "error reading Bluetooth stats: " + errorCode);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, null);
+ resultReceiver.send(0, bundle);
+ }
}
- }
- );
- bluetoothReceiver = resultReceiver;
+ );
+ bluetoothReceiver = resultReceiver;
+ }
}
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 9a41551..1b6af71 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -32,6 +32,8 @@
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
import android.bluetooth.UidTraffic;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -172,6 +174,7 @@
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -294,6 +297,7 @@
private final CpuPowerStatsCollector mCpuPowerStatsCollector;
private final MobileRadioPowerStatsCollector mMobileRadioPowerStatsCollector;
private final WifiPowerStatsCollector mWifiPowerStatsCollector;
+ private final BluetoothPowerStatsCollector mBluetoothPowerStatsCollector;
private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray();
private final WifiPowerStatsCollector.WifiStatsRetriever mWifiStatsRetriever =
new WifiPowerStatsCollector.WifiStatsRetriever() {
@@ -313,6 +317,38 @@
}
};
+ private class BluetoothStatsRetrieverImpl implements
+ BluetoothPowerStatsCollector.BluetoothStatsRetriever {
+ private final BluetoothManager mBluetoothManager;
+
+ BluetoothStatsRetrieverImpl(BluetoothManager bluetoothManager) {
+ mBluetoothManager = bluetoothManager;
+ }
+
+ @Override
+ public void retrieveBluetoothScanTimes(Callback callback) {
+ synchronized (BatteryStatsImpl.this) {
+ retrieveBluetoothScanTimesLocked(callback);
+ }
+ }
+
+ @Override
+ public boolean requestControllerActivityEnergyInfo(Executor executor,
+ BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback) {
+ if (mBluetoothManager == null) {
+ return false;
+ }
+
+ BluetoothAdapter adapter = mBluetoothManager.getAdapter();
+ if (adapter == null) {
+ return false;
+ }
+
+ adapter.requestControllerActivityEnergyInfo(executor, callback);
+ return true;
+ }
+ }
+
public LongSparseArray<SamplingTimer> getKernelMemoryStats() {
return mKernelMemoryStats;
}
@@ -1926,12 +1962,14 @@
}
private class PowerStatsCollectorInjector implements CpuPowerStatsCollector.Injector,
- MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector {
+ MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector,
+ BluetoothPowerStatsCollector.Injector {
private PackageManager mPackageManager;
private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
private NetworkStatsManager mNetworkStatsManager;
private TelephonyManager mTelephonyManager;
private WifiManager mWifiManager;
+ private BluetoothPowerStatsCollector.BluetoothStatsRetriever mBluetoothStatsRetriever;
void setContext(Context context) {
mPackageManager = context.getPackageManager();
@@ -1940,6 +1978,8 @@
mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class);
mTelephonyManager = context.getSystemService(TelephonyManager.class);
mWifiManager = context.getSystemService(WifiManager.class);
+ mBluetoothStatsRetriever = new BluetoothStatsRetrieverImpl(
+ context.getSystemService(BluetoothManager.class));
}
@Override
@@ -2018,6 +2058,11 @@
}
@Override
+ public BluetoothPowerStatsCollector.BluetoothStatsRetriever getBluetoothStatsRetriever() {
+ return mBluetoothStatsRetriever;
+ }
+
+ @Override
public LongSupplier getCallDurationSupplier() {
return () -> mPhoneOnTimer.getTotalTimeLocked(mClock.elapsedRealtime() * 1000,
STATS_SINCE_CHARGED);
@@ -6774,6 +6819,24 @@
}
}
+ private void retrieveBluetoothScanTimesLocked(
+ BluetoothPowerStatsCollector.BluetoothStatsRetriever.Callback callback) {
+ long elapsedTimeUs = mClock.elapsedRealtime() * 1000;
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ Uid uidStats = mUidStats.valueAt(i);
+ if (uidStats.mBluetoothScanTimer == null) {
+ continue;
+ }
+
+ long scanTimeUs = mBluetoothScanTimer.getTotalTimeLocked(elapsedTimeUs,
+ STATS_SINCE_CHARGED);
+ if (scanTimeUs != 0) {
+ int uid = mUidStats.keyAt(i);
+ callback.onBluetoothScanTime(uid, (scanTimeUs + 500) / 1000);
+ }
+ }
+ }
+
@GuardedBy("this")
private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis,
final long uptimeMillis, int uid) {
@@ -11202,6 +11265,10 @@
mWifiPowerStatsCollector = new WifiPowerStatsCollector(mPowerStatsCollectorInjector);
mWifiPowerStatsCollector.addConsumer(this::recordPowerStats);
+ mBluetoothPowerStatsCollector = new BluetoothPowerStatsCollector(
+ mPowerStatsCollectorInjector);
+ mBluetoothPowerStatsCollector.addConsumer(this::recordPowerStats);
+
mStartCount++;
initTimersAndCounters();
mOnBattery = mOnBatteryInternal = false;
@@ -13146,6 +13213,10 @@
@GuardedBy("this")
public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info,
final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
+ if (mBluetoothPowerStatsCollector.isEnabled()) {
+ return;
+ }
+
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating bluetooth stats: " + info);
}
@@ -13153,6 +13224,7 @@
if (info == null) {
return;
}
+
if (!mOnBatteryInternal || mIgnoreNextExternalStats) {
mLastBluetoothActivityInfo.set(info);
return;
@@ -13187,7 +13259,6 @@
(mGlobalEnergyConsumerStats != null
&& mBluetoothPowerCalculator != null && consumedChargeUC > 0) ?
new SparseDoubleArray() : null;
-
long totalScanTimeMs = 0;
final int uidCount = mUidStats.size();
@@ -14616,6 +14687,10 @@
mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI));
mWifiPowerStatsCollector.schedule();
+ mBluetoothPowerStatsCollector.setEnabled(
+ mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH));
+ mBluetoothPowerStatsCollector.schedule();
+
mSystemReady = true;
}
@@ -14632,6 +14707,8 @@
return mMobileRadioPowerStatsCollector;
case BatteryConsumer.POWER_COMPONENT_WIFI:
return mWifiPowerStatsCollector;
+ case BatteryConsumer.POWER_COMPONENT_BLUETOOTH:
+ return mBluetoothPowerStatsCollector;
}
return null;
}
@@ -16168,6 +16245,7 @@
mCpuPowerStatsCollector.forceSchedule();
mMobileRadioPowerStatsCollector.forceSchedule();
mWifiPowerStatsCollector.forceSchedule();
+ mBluetoothPowerStatsCollector.forceSchedule();
}
/**
@@ -16187,6 +16265,7 @@
mCpuPowerStatsCollector.collectAndDump(pw);
mMobileRadioPowerStatsCollector.collectAndDump(pw);
mWifiPowerStatsCollector.collectAndDump(pw);
+ mBluetoothPowerStatsCollector.collectAndDump(pw);
}
private final Runnable mWriteAsyncRunnable = () -> {
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 0d5eabc..b252395 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -90,7 +90,9 @@
if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI)) {
mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
}
- mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
+ if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)) {
+ mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
+ }
mPowerCalculators.add(new SensorPowerCalculator(
mContext.getSystemService(SensorManager.class)));
mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
diff --git a/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java
new file mode 100644
index 0000000..8a5085b
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java
@@ -0,0 +1,332 @@
+/*
+ * 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.server.power.stats;
+
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.UidTraffic;
+import android.content.pm.PackageManager;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerStats;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.IntSupplier;
+
+public class BluetoothPowerStatsCollector extends PowerStatsCollector {
+ private static final String TAG = "BluetoothPowerStatsCollector";
+
+ private static final long BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT = 20000;
+
+ private static final long ENERGY_UNSPECIFIED = -1;
+
+ interface BluetoothStatsRetriever {
+ interface Callback {
+ void onBluetoothScanTime(int uid, long scanTimeMs);
+ }
+
+ void retrieveBluetoothScanTimes(Callback callback);
+
+ boolean requestControllerActivityEnergyInfo(Executor executor,
+ BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback);
+ }
+
+ interface Injector {
+ Handler getHandler();
+ Clock getClock();
+ PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
+ PackageManager getPackageManager();
+ ConsumedEnergyRetriever getConsumedEnergyRetriever();
+ IntSupplier getVoltageSupplier();
+ BluetoothStatsRetriever getBluetoothStatsRetriever();
+ }
+
+ private final Injector mInjector;
+
+ private BluetoothPowerStatsLayout mLayout;
+ private boolean mIsInitialized;
+ private PowerStats mPowerStats;
+ private long[] mDeviceStats;
+ private BluetoothStatsRetriever mBluetoothStatsRetriever;
+ private ConsumedEnergyRetriever mConsumedEnergyRetriever;
+ private IntSupplier mVoltageSupplier;
+ private int[] mEnergyConsumerIds = new int[0];
+ private long[] mLastConsumedEnergyUws;
+ private int mLastVoltageMv;
+
+ private long mLastRxTime;
+ private long mLastTxTime;
+ private long mLastIdleTime;
+
+ private static class UidStats {
+ public long rxCount;
+ public long lastRxCount;
+ public long txCount;
+ public long lastTxCount;
+ public long scanTime;
+ public long lastScanTime;
+ }
+
+ private final SparseArray<UidStats> mUidStats = new SparseArray<>();
+
+ BluetoothPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH)),
+ injector.getUidResolver(),
+ injector.getClock());
+ mInjector = injector;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (enabled) {
+ PackageManager packageManager = mInjector.getPackageManager();
+ super.setEnabled(packageManager != null
+ && packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH));
+ } else {
+ super.setEnabled(false);
+ }
+ }
+
+ private boolean ensureInitialized() {
+ if (mIsInitialized) {
+ return true;
+ }
+
+ if (!isEnabled()) {
+ return false;
+ }
+
+ mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever();
+ mVoltageSupplier = mInjector.getVoltageSupplier();
+ mBluetoothStatsRetriever = mInjector.getBluetoothStatsRetriever();
+ mEnergyConsumerIds =
+ mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH);
+ mLastConsumedEnergyUws = new long[mEnergyConsumerIds.length];
+ Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED);
+
+ mLayout = new BluetoothPowerStatsLayout();
+ mLayout.addDeviceBluetoothControllerActivity();
+ mLayout.addDeviceSectionEnergyConsumers(mEnergyConsumerIds.length);
+ mLayout.addDeviceSectionUsageDuration();
+ mLayout.addDeviceSectionPowerEstimate();
+ mLayout.addUidTrafficStats();
+ mLayout.addUidSectionPowerEstimate();
+
+ PersistableBundle extras = new PersistableBundle();
+ mLayout.toExtras(extras);
+ PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH, mLayout.getDeviceStatsArrayLength(),
+ null, 0, mLayout.getUidStatsArrayLength(),
+ extras);
+ mPowerStats = new PowerStats(powerStatsDescriptor);
+ mDeviceStats = mPowerStats.stats;
+
+ mIsInitialized = true;
+ return true;
+ }
+
+ @Override
+ protected PowerStats collectStats() {
+ if (!ensureInitialized()) {
+ return null;
+ }
+
+ mPowerStats.uidStats.clear();
+
+ collectBluetoothActivityInfo();
+ collectBluetoothScanStats();
+
+ if (mEnergyConsumerIds.length != 0) {
+ collectEnergyConsumers();
+ }
+
+ return mPowerStats;
+ }
+
+ private void collectBluetoothActivityInfo() {
+ CompletableFuture<BluetoothActivityEnergyInfo> immediateFuture = new CompletableFuture<>();
+ boolean success = mBluetoothStatsRetriever.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() {
+ @Override
+ public void onBluetoothActivityEnergyInfoAvailable(
+ BluetoothActivityEnergyInfo info) {
+ immediateFuture.complete(info);
+ }
+
+ @Override
+ public void onBluetoothActivityEnergyInfoError(int error) {
+ immediateFuture.completeExceptionally(
+ new RuntimeException("error: " + error));
+ }
+ });
+
+ if (!success) {
+ return;
+ }
+
+ BluetoothActivityEnergyInfo activityInfo;
+ try {
+ activityInfo = immediateFuture.get(BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT,
+ TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot acquire BluetoothActivityEnergyInfo", e);
+ activityInfo = null;
+ }
+
+ if (activityInfo == null) {
+ return;
+ }
+
+ long rxTime = activityInfo.getControllerRxTimeMillis();
+ long rxTimeDelta = Math.max(0, rxTime - mLastRxTime);
+ mLayout.setDeviceRxTime(mDeviceStats, rxTimeDelta);
+ mLastRxTime = rxTime;
+
+ long txTime = activityInfo.getControllerTxTimeMillis();
+ long txTimeDelta = Math.max(0, txTime - mLastTxTime);
+ mLayout.setDeviceTxTime(mDeviceStats, txTimeDelta);
+ mLastTxTime = txTime;
+
+ long idleTime = activityInfo.getControllerIdleTimeMillis();
+ long idleTimeDelta = Math.max(0, idleTime - mLastIdleTime);
+ mLayout.setDeviceIdleTime(mDeviceStats, idleTimeDelta);
+ mLastIdleTime = idleTime;
+
+ mPowerStats.durationMs = rxTimeDelta + txTimeDelta + idleTimeDelta;
+
+ List<UidTraffic> uidTraffic = activityInfo.getUidTraffic();
+ for (int i = uidTraffic.size() - 1; i >= 0; i--) {
+ UidTraffic ut = uidTraffic.get(i);
+ int uid = mUidResolver.mapUid(ut.getUid());
+ UidStats counts = mUidStats.get(uid);
+ if (counts == null) {
+ counts = new UidStats();
+ mUidStats.put(uid, counts);
+ }
+ counts.rxCount += ut.getRxBytes();
+ counts.txCount += ut.getTxBytes();
+ }
+
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ UidStats counts = mUidStats.valueAt(i);
+ long rxDelta = Math.max(0, counts.rxCount - counts.lastRxCount);
+ counts.lastRxCount = counts.rxCount;
+ counts.rxCount = 0;
+
+ long txDelta = Math.max(0, counts.txCount - counts.lastTxCount);
+ counts.lastTxCount = counts.txCount;
+ counts.txCount = 0;
+
+ if (rxDelta != 0 || txDelta != 0) {
+ int uid = mUidStats.keyAt(i);
+ long[] stats = mPowerStats.uidStats.get(uid);
+ if (stats == null) {
+ stats = new long[mLayout.getUidStatsArrayLength()];
+ mPowerStats.uidStats.put(uid, stats);
+ }
+
+ mLayout.setUidRxBytes(stats, rxDelta);
+ mLayout.setUidTxBytes(stats, txDelta);
+ }
+ }
+ }
+
+ private void collectBluetoothScanStats() {
+ mBluetoothStatsRetriever.retrieveBluetoothScanTimes((uid, scanTimeMs) -> {
+ uid = mUidResolver.mapUid(uid);
+ UidStats uidStats = mUidStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new UidStats();
+ mUidStats.put(uid, uidStats);
+ }
+ uidStats.scanTime += scanTimeMs;
+ });
+
+ long totalScanTime = 0;
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ UidStats counts = mUidStats.valueAt(i);
+ if (counts.scanTime == 0) {
+ continue;
+ }
+
+ long delta = Math.max(0, counts.scanTime - counts.lastScanTime);
+ counts.lastScanTime = counts.scanTime;
+ counts.scanTime = 0;
+
+ if (delta != 0) {
+ int uid = mUidStats.keyAt(i);
+ long[] stats = mPowerStats.uidStats.get(uid);
+ if (stats == null) {
+ stats = new long[mLayout.getUidStatsArrayLength()];
+ mPowerStats.uidStats.put(uid, stats);
+ }
+
+ mLayout.setUidScanTime(stats, delta);
+ totalScanTime += delta;
+ }
+ }
+
+ mLayout.setDeviceScanTime(mDeviceStats, totalScanTime);
+ }
+
+ private void collectEnergyConsumers() {
+ int voltageMv = mVoltageSupplier.getAsInt();
+ if (voltageMv <= 0) {
+ Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
+ + " mV) when querying energy consumers");
+ return;
+ }
+
+ int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;
+ mLastVoltageMv = voltageMv;
+
+ long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds);
+ if (energyUws == null) {
+ return;
+ }
+
+ for (int i = energyUws.length - 1; i >= 0; i--) {
+ long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED
+ ? energyUws[i] - mLastConsumedEnergyUws[i] : 0;
+ if (energyDelta < 0) {
+ // Likely, restart of powerstats HAL
+ energyDelta = 0;
+ }
+ mLayout.setConsumedEnergy(mPowerStats.stats, i, uJtoUc(energyDelta, averageVoltage));
+ mLastConsumedEnergyUws[i] = energyUws[i];
+ }
+ }
+
+ @Override
+ protected void onUidRemoved(int uid) {
+ super.onUidRemoved(uid);
+ mUidStats.remove(uid);
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/BluetoothPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsLayout.java
new file mode 100644
index 0000000..9358b5e
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsLayout.java
@@ -0,0 +1,143 @@
+/*
+ * 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.server.power.stats;
+
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+import com.android.internal.os.PowerStats;
+
+public class BluetoothPowerStatsLayout extends PowerStatsLayout {
+ private static final String EXTRA_DEVICE_RX_TIME_POSITION = "dt-rx";
+ private static final String EXTRA_DEVICE_TX_TIME_POSITION = "dt-tx";
+ private static final String EXTRA_DEVICE_IDLE_TIME_POSITION = "dt-idle";
+ private static final String EXTRA_DEVICE_SCAN_TIME_POSITION = "dt-scan";
+ private static final String EXTRA_UID_RX_BYTES_POSITION = "ub-rx";
+ private static final String EXTRA_UID_TX_BYTES_POSITION = "ub-tx";
+ private static final String EXTRA_UID_SCAN_TIME_POSITION = "ut-scan";
+
+ private int mDeviceRxTimePosition;
+ private int mDeviceTxTimePosition;
+ private int mDeviceIdleTimePosition;
+ private int mDeviceScanTimePosition;
+ private int mUidRxBytesPosition;
+ private int mUidTxBytesPosition;
+ private int mUidScanTimePosition;
+
+ BluetoothPowerStatsLayout() {
+ }
+
+ BluetoothPowerStatsLayout(@NonNull PowerStats.Descriptor descriptor) {
+ super(descriptor);
+ }
+
+ void addDeviceBluetoothControllerActivity() {
+ mDeviceRxTimePosition = addDeviceSection(1, "rx");
+ mDeviceTxTimePosition = addDeviceSection(1, "tx");
+ mDeviceIdleTimePosition = addDeviceSection(1, "idle");
+ mDeviceScanTimePosition = addDeviceSection(1, "scan", FLAG_OPTIONAL);
+ }
+
+ void addUidTrafficStats() {
+ mUidRxBytesPosition = addUidSection(1, "rx-B");
+ mUidTxBytesPosition = addUidSection(1, "tx-B");
+ mUidScanTimePosition = addUidSection(1, "scan", FLAG_OPTIONAL);
+ }
+
+ public void setDeviceRxTime(long[] stats, long durationMillis) {
+ stats[mDeviceRxTimePosition] = durationMillis;
+ }
+
+ public long getDeviceRxTime(long[] stats) {
+ return stats[mDeviceRxTimePosition];
+ }
+
+ public void setDeviceTxTime(long[] stats, long durationMillis) {
+ stats[mDeviceTxTimePosition] = durationMillis;
+ }
+
+ public long getDeviceTxTime(long[] stats) {
+ return stats[mDeviceTxTimePosition];
+ }
+
+ public void setDeviceIdleTime(long[] stats, long durationMillis) {
+ stats[mDeviceIdleTimePosition] = durationMillis;
+ }
+
+ public long getDeviceIdleTime(long[] stats) {
+ return stats[mDeviceIdleTimePosition];
+ }
+
+ public void setDeviceScanTime(long[] stats, long durationMillis) {
+ stats[mDeviceScanTimePosition] = durationMillis;
+ }
+
+ public long getDeviceScanTime(long[] stats) {
+ return stats[mDeviceScanTimePosition];
+ }
+
+ public void setUidRxBytes(long[] stats, long count) {
+ stats[mUidRxBytesPosition] = count;
+ }
+
+ public long getUidRxBytes(long[] stats) {
+ return stats[mUidRxBytesPosition];
+ }
+
+ public void setUidTxBytes(long[] stats, long count) {
+ stats[mUidTxBytesPosition] = count;
+ }
+
+ public long getUidTxBytes(long[] stats) {
+ return stats[mUidTxBytesPosition];
+ }
+
+ public void setUidScanTime(long[] stats, long count) {
+ stats[mUidScanTimePosition] = count;
+ }
+
+ public long getUidScanTime(long[] stats) {
+ return stats[mUidScanTimePosition];
+ }
+
+ /**
+ * Copies the elements of the stats array layout into <code>extras</code>
+ */
+ public void toExtras(PersistableBundle extras) {
+ super.toExtras(extras);
+ extras.putInt(EXTRA_DEVICE_RX_TIME_POSITION, mDeviceRxTimePosition);
+ extras.putInt(EXTRA_DEVICE_TX_TIME_POSITION, mDeviceTxTimePosition);
+ extras.putInt(EXTRA_DEVICE_IDLE_TIME_POSITION, mDeviceIdleTimePosition);
+ extras.putInt(EXTRA_DEVICE_SCAN_TIME_POSITION, mDeviceScanTimePosition);
+ extras.putInt(EXTRA_UID_RX_BYTES_POSITION, mUidRxBytesPosition);
+ extras.putInt(EXTRA_UID_TX_BYTES_POSITION, mUidTxBytesPosition);
+ extras.putInt(EXTRA_UID_SCAN_TIME_POSITION, mUidScanTimePosition);
+ }
+
+ /**
+ * Retrieves elements of the stats array layout from <code>extras</code>
+ */
+ public void fromExtras(PersistableBundle extras) {
+ super.fromExtras(extras);
+ mDeviceRxTimePosition = extras.getInt(EXTRA_DEVICE_RX_TIME_POSITION);
+ mDeviceTxTimePosition = extras.getInt(EXTRA_DEVICE_TX_TIME_POSITION);
+ mDeviceIdleTimePosition = extras.getInt(EXTRA_DEVICE_IDLE_TIME_POSITION);
+ mDeviceScanTimePosition = extras.getInt(EXTRA_DEVICE_SCAN_TIME_POSITION);
+ mUidRxBytesPosition = extras.getInt(EXTRA_UID_RX_BYTES_POSITION);
+ mUidTxBytesPosition = extras.getInt(EXTRA_UID_TX_BYTES_POSITION);
+ mUidScanTimePosition = extras.getInt(EXTRA_UID_SCAN_TIME_POSITION);
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/BluetoothPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsProcessor.java
new file mode 100644
index 0000000..4d6db97
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsProcessor.java
@@ -0,0 +1,304 @@
+/*
+ * 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.server.power.stats;
+
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BluetoothPowerStatsProcessor extends PowerStatsProcessor {
+ private static final String TAG = "BluetoothPowerStatsProcessor";
+
+ private final UsageBasedPowerEstimator mRxPowerEstimator;
+ private final UsageBasedPowerEstimator mTxPowerEstimator;
+ private final UsageBasedPowerEstimator mIdlePowerEstimator;
+
+ private PowerStats.Descriptor mLastUsedDescriptor;
+ private BluetoothPowerStatsLayout mStatsLayout;
+ // Sequence of steps for power estimation and intermediate results.
+ private PowerEstimationPlan mPlan;
+
+ private long[] mTmpDeviceStatsArray;
+ private long[] mTmpUidStatsArray;
+
+ public BluetoothPowerStatsProcessor(PowerProfile powerProfile) {
+ mRxPowerEstimator = new UsageBasedPowerEstimator(
+ powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX));
+ mTxPowerEstimator = new UsageBasedPowerEstimator(
+ powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX));
+ mIdlePowerEstimator = new UsageBasedPowerEstimator(
+ powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE));
+ }
+
+ private static class Intermediates {
+ /**
+ * Number of received bytes
+ */
+ public long rxBytes;
+ /**
+ * Duration of receiving
+ */
+ public long rxTime;
+ /**
+ * Estimated power for the RX state.
+ */
+ public double rxPower;
+ /**
+ * Number of transmitted bytes
+ */
+ public long txBytes;
+ /**
+ * Duration of transmitting
+ */
+ public long txTime;
+ /**
+ * Estimated power for the TX state.
+ */
+ public double txPower;
+ /**
+ * Estimated power for IDLE, SCAN states.
+ */
+ public double idlePower;
+ /**
+ * Total scan time.
+ */
+ public long scanTime;
+ /**
+ * Measured consumed energy from power monitoring hardware (micro-coulombs)
+ */
+ public long consumedEnergy;
+ }
+
+ @Override
+ void finish(PowerComponentAggregatedPowerStats stats) {
+ if (stats.getPowerStatsDescriptor() == null) {
+ return;
+ }
+
+ unpackPowerStatsDescriptor(stats.getPowerStatsDescriptor());
+
+ if (mPlan == null) {
+ mPlan = new PowerEstimationPlan(stats.getConfig());
+ }
+
+ for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i);
+ Intermediates intermediates = new Intermediates();
+ estimation.intermediates = intermediates;
+ computeDevicePowerEstimates(stats, estimation.stateValues, intermediates);
+ }
+
+ double ratio = 1.0;
+ if (mStatsLayout.getEnergyConsumerCount() != 0) {
+ ratio = computeEstimateAdjustmentRatioUsingConsumedEnergy();
+ if (ratio != 1) {
+ for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i);
+ adjustDevicePowerEstimates(stats, estimation.stateValues,
+ (Intermediates) estimation.intermediates, ratio);
+ }
+ }
+ }
+
+ combineDeviceStateEstimates();
+
+ ArrayList<Integer> uids = new ArrayList<>();
+ stats.collectUids(uids);
+ if (!uids.isEmpty()) {
+ for (int uid : uids) {
+ for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
+ computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(i));
+ }
+ }
+
+ for (int uid : uids) {
+ for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) {
+ computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i));
+ }
+ }
+ }
+ mPlan.resetIntermediates();
+ }
+
+ private void unpackPowerStatsDescriptor(PowerStats.Descriptor descriptor) {
+ if (descriptor.equals(mLastUsedDescriptor)) {
+ return;
+ }
+
+ mLastUsedDescriptor = descriptor;
+ mStatsLayout = new BluetoothPowerStatsLayout(descriptor);
+ mTmpDeviceStatsArray = new long[descriptor.statsArrayLength];
+ mTmpUidStatsArray = new long[descriptor.uidStatsArrayLength];
+ }
+
+ /**
+ * Compute power estimates using the power profile.
+ */
+ private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats,
+ int[] deviceStates, Intermediates intermediates) {
+ if (!stats.getDeviceStats(mTmpDeviceStatsArray, deviceStates)) {
+ return;
+ }
+
+ for (int i = mStatsLayout.getEnergyConsumerCount() - 1; i >= 0; i--) {
+ intermediates.consumedEnergy += mStatsLayout.getConsumedEnergy(mTmpDeviceStatsArray, i);
+ }
+
+ intermediates.rxTime = mStatsLayout.getDeviceRxTime(mTmpDeviceStatsArray);
+ intermediates.txTime = mStatsLayout.getDeviceTxTime(mTmpDeviceStatsArray);
+ intermediates.scanTime = mStatsLayout.getDeviceScanTime(mTmpDeviceStatsArray);
+ long idleTime = mStatsLayout.getDeviceIdleTime(mTmpDeviceStatsArray);
+
+ intermediates.rxPower = mRxPowerEstimator.calculatePower(intermediates.rxTime);
+ intermediates.txPower = mTxPowerEstimator.calculatePower(intermediates.txTime);
+ intermediates.idlePower = mIdlePowerEstimator.calculatePower(idleTime);
+ mStatsLayout.setDevicePowerEstimate(mTmpDeviceStatsArray,
+ intermediates.rxPower + intermediates.txPower + intermediates.idlePower);
+ stats.setDeviceStats(deviceStates, mTmpDeviceStatsArray);
+ }
+
+ /**
+ * Compute an adjustment ratio using the total power estimated using the power profile
+ * and the total power measured by hardware.
+ */
+ private double computeEstimateAdjustmentRatioUsingConsumedEnergy() {
+ long totalConsumedEnergy = 0;
+ double totalPower = 0;
+
+ for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ Intermediates intermediates =
+ (Intermediates) mPlan.deviceStateEstimations.get(i).intermediates;
+ totalPower += intermediates.rxPower + intermediates.txPower + intermediates.idlePower;
+ totalConsumedEnergy += intermediates.consumedEnergy;
+ }
+
+ if (totalPower == 0) {
+ return 1;
+ }
+
+ return uCtoMah(totalConsumedEnergy) / totalPower;
+ }
+
+ /**
+ * Uniformly apply the same adjustment to all power estimates in order to ensure that the total
+ * estimated power matches the measured consumed power. We are not claiming that all
+ * averages captured in the power profile have to be off by the same percentage in reality.
+ */
+ private void adjustDevicePowerEstimates(PowerComponentAggregatedPowerStats stats,
+ int[] deviceStates, Intermediates intermediates, double ratio) {
+ double adjutedPower;
+ intermediates.rxPower *= ratio;
+ intermediates.txPower *= ratio;
+ intermediates.idlePower *= ratio;
+ adjutedPower = intermediates.rxPower + intermediates.txPower + intermediates.idlePower;
+
+ if (!stats.getDeviceStats(mTmpDeviceStatsArray, deviceStates)) {
+ return;
+ }
+
+ mStatsLayout.setDevicePowerEstimate(mTmpDeviceStatsArray, adjutedPower);
+ stats.setDeviceStats(deviceStates, mTmpDeviceStatsArray);
+ }
+
+ /**
+ * Combine power estimates before distributing them proportionally to UIDs.
+ */
+ private void combineDeviceStateEstimates() {
+ for (int i = mPlan.combinedDeviceStateEstimations.size() - 1; i >= 0; i--) {
+ CombinedDeviceStateEstimate cdse = mPlan.combinedDeviceStateEstimations.get(i);
+ Intermediates cdseIntermediates = new Intermediates();
+ cdse.intermediates = cdseIntermediates;
+ List<DeviceStateEstimation> deviceStateEstimations = cdse.deviceStateEstimations;
+ for (int j = deviceStateEstimations.size() - 1; j >= 0; j--) {
+ DeviceStateEstimation dse = deviceStateEstimations.get(j);
+ Intermediates intermediates = (Intermediates) dse.intermediates;
+ cdseIntermediates.rxTime += intermediates.rxTime;
+ cdseIntermediates.rxBytes += intermediates.rxBytes;
+ cdseIntermediates.rxPower += intermediates.rxPower;
+ cdseIntermediates.txTime += intermediates.txTime;
+ cdseIntermediates.txBytes += intermediates.txBytes;
+ cdseIntermediates.txPower += intermediates.txPower;
+ cdseIntermediates.idlePower += intermediates.idlePower;
+ cdseIntermediates.scanTime += intermediates.scanTime;
+ cdseIntermediates.consumedEnergy += intermediates.consumedEnergy;
+ }
+ }
+ }
+
+ private void computeUidActivityTotals(PowerComponentAggregatedPowerStats stats, int uid,
+ UidStateEstimate uidStateEstimate) {
+ Intermediates intermediates =
+ (Intermediates) uidStateEstimate.combinedDeviceStateEstimate.intermediates;
+ for (UidStateProportionalEstimate proportionalEstimate :
+ uidStateEstimate.proportionalEstimates) {
+ if (!stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) {
+ continue;
+ }
+
+ intermediates.rxBytes += mStatsLayout.getUidRxBytes(mTmpUidStatsArray);
+ intermediates.txBytes += mStatsLayout.getUidTxBytes(mTmpUidStatsArray);
+ }
+ }
+
+ private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, int uid,
+ UidStateEstimate uidStateEstimate) {
+ Intermediates intermediates =
+ (Intermediates) uidStateEstimate.combinedDeviceStateEstimate.intermediates;
+
+ // Scan is more expensive than data transfer, so in the presence of large
+ // of scanning duration, blame apps according to the time they spent scanning.
+ // This may disproportionately blame apps that do a lot of scanning, which is
+ // the tread-off we are making in the absence of more detailed metrics.
+ boolean normalizeRxByScanTime = intermediates.scanTime > intermediates.rxTime;
+ boolean normalizeTxByScanTime = intermediates.scanTime > intermediates.txTime;
+
+ for (UidStateProportionalEstimate proportionalEstimate :
+ uidStateEstimate.proportionalEstimates) {
+ if (!stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) {
+ continue;
+ }
+
+ double power = 0;
+ if (normalizeRxByScanTime) {
+ if (intermediates.scanTime != 0) {
+ power += intermediates.rxPower * mStatsLayout.getUidScanTime(mTmpUidStatsArray)
+ / intermediates.scanTime;
+ }
+ } else {
+ if (intermediates.rxBytes != 0) {
+ power += intermediates.rxPower * mStatsLayout.getUidRxBytes(mTmpUidStatsArray)
+ / intermediates.rxBytes;
+ }
+ }
+ if (normalizeTxByScanTime) {
+ if (intermediates.scanTime != 0) {
+ power += intermediates.txPower * mStatsLayout.getUidScanTime(mTmpUidStatsArray)
+ / intermediates.scanTime;
+ }
+ } else {
+ if (intermediates.txBytes != 0) {
+ power += intermediates.txPower * mStatsLayout.getUidTxBytes(mTmpUidStatsArray)
+ / intermediates.txBytes;
+ }
+ }
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
index ad2c3e8..3579246 100644
--- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
@@ -225,7 +225,7 @@
@NonNull TimeConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) {
Objects.requireNonNull(requestedConfiguration);
- TimeCapabilitiesAndConfig capabilitiesAndConfig = getCurrentUserConfigurationInternal()
+ TimeCapabilitiesAndConfig capabilitiesAndConfig = getConfigurationInternal(userId)
.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
index dd3d512..80f1125 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -150,7 +150,7 @@
Rect landscapeCrop = getCrop(rotatedDisplaySize, bitmapSize, suggestedCrops, rtl);
landscapeCrop = noParallax(landscapeCrop, rotatedDisplaySize, bitmapSize, rtl);
// compute the crop on portrait at the center of the landscape crop
- crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, rtl, ADD);
+ crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, ADD);
// add some parallax (until the border of the landscape crop without parallax)
if (rtl) {
@@ -160,7 +160,7 @@
}
}
- return getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD);
+ return getAdjustedCrop(crop, bitmapSize, displaySize, true, ADD);
}
// If any suggested crop is invalid, fallback to case 1
@@ -176,7 +176,7 @@
// Case 2: if the orientation exists in the suggested crops, adjust the suggested crop
Rect suggestedCrop = suggestedCrops.get(orientation);
if (suggestedCrop != null) {
- return getAdjustedCrop(suggestedCrop, bitmapSize, displaySize, true, rtl, ADD);
+ return getAdjustedCrop(suggestedCrop, bitmapSize, displaySize, true, ADD);
}
// Case 3: if we have the 90° rotated orientation in the suggested crops, reuse it and
@@ -188,7 +188,7 @@
if (suggestedCrop != null) {
// only keep the visible part (without parallax)
Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl);
- return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, BALANCE);
+ return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, BALANCE);
}
// Case 4: if the device is a foldable, if we're looking for a folded orientation and have
@@ -200,13 +200,13 @@
// compute the visible part (without parallax) of the unfolded screen
Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl);
// compute the folded crop, at the center of the crop of the unfolded screen
- Rect res = getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, REMOVE);
+ Rect res = getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, REMOVE);
// if we removed some width, add it back to add a parallax effect
if (res.width() < adjustedCrop.width()) {
if (rtl) res.left = Math.min(res.left, adjustedCrop.left);
else res.right = Math.max(res.right, adjustedCrop.right);
// use getAdjustedCrop(parallax=true) to make sure we don't exceed MAX_PARALLAX
- res = getAdjustedCrop(res, bitmapSize, displaySize, true, rtl, ADD);
+ res = getAdjustedCrop(res, bitmapSize, displaySize, true, ADD);
}
return res;
}
@@ -220,7 +220,7 @@
if (suggestedCrop != null) {
// only keep the visible part (without parallax)
Rect adjustedCrop = noParallax(suggestedCrop, suggestedDisplaySize, bitmapSize, rtl);
- return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, rtl, ADD);
+ return getAdjustedCrop(adjustedCrop, bitmapSize, displaySize, false, ADD);
}
// Case 6: for a foldable device, try to combine case 3 + case 4 or 5:
@@ -255,7 +255,7 @@
@VisibleForTesting
static Rect noParallax(Rect crop, Point displaySize, Point bitmapSize, boolean rtl) {
if (displaySize == null) return crop;
- Rect adjustedCrop = getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD);
+ Rect adjustedCrop = getAdjustedCrop(crop, bitmapSize, displaySize, true, ADD);
// only keep the visible part (without parallax)
float suggestedDisplayRatio = 1f * displaySize.x / displaySize.y;
int widthToRemove = (int) (adjustedCrop.width()
@@ -272,7 +272,7 @@
* Adjust a given crop:
* <ul>
* <li>If parallax = true, make sure we have a parallax of at most {@link #MAX_PARALLAX},
- * by removing content from the right (or left if RTL layout) if necessary.
+ * by removing content from both sides if necessary.
* <li>If parallax = false, make sure we do not have additional width for parallax. If we
* have additional width for parallax, remove half of the additional width on both sides.
* <li>Make sure the crop fills the screen, i.e. that the width/height ratio of the crop
@@ -282,7 +282,7 @@
*/
@VisibleForTesting
static Rect getAdjustedCrop(Rect crop, Point bitmapSize, Point screenSize,
- boolean parallax, boolean rtl, int mode) {
+ boolean parallax, int mode) {
Rect adjustedCrop = new Rect(crop);
float cropRatio = ((float) crop.width()) / crop.height();
float screenRatio = ((float) screenSize.x) / screenSize.y;
@@ -297,8 +297,7 @@
Rect rotatedCrop = new Rect(newLeft, newTop, newRight, newBottom);
Point rotatedBitmap = new Point(bitmapSize.y, bitmapSize.x);
Point rotatedScreen = new Point(screenSize.y, screenSize.x);
- Rect rect = getAdjustedCrop(rotatedCrop, rotatedBitmap, rotatedScreen, false, rtl,
- mode);
+ Rect rect = getAdjustedCrop(rotatedCrop, rotatedBitmap, rotatedScreen, false, mode);
int resultLeft = rect.top;
int resultRight = resultLeft + rect.height();
int resultTop = rotatedBitmap.x - rect.right;
@@ -318,9 +317,8 @@
// total surface of W * H. In other words it is the width to add to get the desired
// aspect ratio R, while preserving the total number of pixels W * H.
int widthToAdd = mode == REMOVE ? 0
- : mode == ADD ? (int) (0.5 + crop.height() * screenRatio - crop.width())
- : (int) (0.5 - crop.width()
- + Math.sqrt(crop.width() * crop.height() * screenRatio));
+ : mode == ADD ? (int) (crop.height() * screenRatio - crop.width())
+ : (int) (-crop.width() + Math.sqrt(crop.width() * crop.height() * screenRatio));
int availableWidth = bitmapSize.x - crop.width();
if (availableWidth >= widthToAdd) {
int widthToAddLeft = widthToAdd / 2;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e280bdc..5be5bc5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -984,36 +984,26 @@
Region touchableRegion = mTempRegion3;
windowState.getTouchableRegion(touchableRegion);
Region windowBounds = mTempRegion2;
- 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);
- }
+
+ // 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);
+
// Only update new regions
Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76e7f53..f3d0b00 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -77,7 +77,6 @@
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -87,6 +86,7 @@
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
@@ -121,6 +121,7 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
+import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -128,7 +129,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED;
import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING;
-import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_UNSET;
@@ -339,6 +339,7 @@
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
+import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -660,6 +661,8 @@
private final TaskFragment.ConfigOverrideHint mResolveConfigHint;
+ private final boolean mOptOutEdgeToEdge;
+
private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig;
boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
@@ -682,6 +685,12 @@
// it references to gets removed. This should also be cleared when we move out of pip.
private Task mLastParentBeforePip;
+ // The token of the previous TaskFragment parent of this embedded ActivityRecord when it is
+ // reparented to a new Task due to picture-in-picture.
+ // Note that the TaskFragment may be finished and no longer attached in WM hierarchy.
+ @Nullable
+ private IBinder mLastEmbeddedParentTfTokenBeforePip;
+
// Only set if this instance is a launch-into-pip Activity, points to the
// host Activity the launch-into-pip Activity is originated from.
private ActivityRecord mLaunchIntoPipHostActivity;
@@ -1806,6 +1815,11 @@
mLastTaskFragmentOrganizerBeforePip = organizedTf != null
? organizedTf.getTaskFragmentOrganizer()
: null;
+ if (organizedTf != null
+ // Not necessary for content pip.
+ && launchIntoPipHostActivity == null) {
+ mLastEmbeddedParentTfTokenBeforePip = organizedTf.getFragmentToken();
+ }
}
void clearLastParentBeforePip() {
@@ -1815,12 +1829,17 @@
}
mLaunchIntoPipHostActivity = null;
mLastTaskFragmentOrganizerBeforePip = null;
+ mLastEmbeddedParentTfTokenBeforePip = null;
}
@Nullable Task getLastParentBeforePip() {
return mLastParentBeforePip;
}
+ @Nullable IBinder getLastEmbeddedParentTfTokenBeforePip() {
+ return mLastEmbeddedParentTfTokenBeforePip;
+ }
+
@Nullable ActivityRecord getLaunchIntoPipHostActivity() {
return mLaunchIntoPipHostActivity;
}
@@ -2122,14 +2141,14 @@
if (mWmService.mFlags.mInsetsDecoupledConfiguration) {
// When the stable configuration is the default behavior, override for the legacy apps
// without forward override flag.
- mResolveConfigHint.mUseOverrideInsetsForConfig =
+ mResolveConfigHint.mUseOverrideInsetsForStableBounds =
!info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
&& !info.isChangeEnabled(
OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
} else {
// When the stable configuration is not the default behavior, forward overriding the
// listed apps.
- mResolveConfigHint.mUseOverrideInsetsForConfig =
+ mResolveConfigHint.mUseOverrideInsetsForStableBounds =
info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
}
@@ -2163,9 +2182,12 @@
|| ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
mStyleFillsParent = mOccludesParent;
noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
+ mOptOutEdgeToEdge = ent.array.getBoolean(
+ R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false);
} else {
mStyleFillsParent = mOccludesParent = true;
noDisplay = false;
+ mOptOutEdgeToEdge = false;
}
if (options != null) {
@@ -2617,70 +2639,21 @@
return true;
}
- void scheduleAddStartingWindow() {
- mAddStartingWindow.run();
- }
+ private void scheduleAddStartingWindow() {
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s",
+ this, mStartingData);
- private class AddStartingWindow implements Runnable {
-
- @Override
- public void run() {
- // Can be accessed without holding the global lock
- final StartingData startingData;
- synchronized (mWmService.mGlobalLock) {
- // There can only be one adding request, silly caller!
-
- if (mStartingData == null) {
- // Animation has been canceled... do nothing.
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
- "startingData was nulled out before handling"
- + " mAddStartingWindow: %s", ActivityRecord.this);
- return;
- }
- startingData = mStartingData;
- }
-
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s",
- this, startingData);
-
- StartingSurfaceController.StartingSurface surface = null;
- try {
- surface = startingData.createStartingSurface(ActivityRecord.this);
- } catch (Exception e) {
- Slog.w(TAG, "Exception when adding starting window", e);
- }
- if (surface != null) {
- boolean abort = false;
- synchronized (mWmService.mGlobalLock) {
- // If the window was successfully added, then we need to remove it.
- if (mStartingData == null) {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Aborted starting %s: startingData=%s",
- ActivityRecord.this, mStartingData);
-
- mStartingWindow = null;
- mStartingData = null;
- abort = true;
- } else {
- mStartingSurface = surface;
- }
- if (!abort) {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
- "Added starting %s: startingWindow=%s startingView=%s",
- ActivityRecord.this, mStartingWindow, mStartingSurface);
- }
- }
- if (abort) {
- surface.remove(false /* prepareAnimation */, false /* hasImeSurface */);
- }
- } else {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
- ActivityRecord.this);
- }
+ mStartingSurface = mStartingData.createStartingSurface(ActivityRecord.this);
+ if (mStartingSurface != null) {
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+ "Added starting %s: startingWindow=%s startingView=%s",
+ ActivityRecord.this, mStartingWindow, mStartingSurface);
+ } else {
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
+ ActivityRecord.this);
}
}
- private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
-
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn,
TaskSnapshot snapshot) {
@@ -8491,7 +8464,7 @@
mCompatDisplayInsets =
new CompatDisplayInsets(
mDisplayContent, this, letterboxedContainerBounds,
- mResolveConfigHint.mUseOverrideInsetsForConfig);
+ mResolveConfigHint.mUseOverrideInsetsForStableBounds);
}
private void clearSizeCompatModeAttributes() {
@@ -8571,6 +8544,8 @@
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
+ applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+
// Bubble activities should always fill their parent and should not be letterboxed.
final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
&& (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
@@ -8670,8 +8645,6 @@
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
-
logAppCompatState();
}
@@ -8690,13 +8663,14 @@
if (mDisplayContent == null) {
return;
}
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
int rotation = newParentConfiguration.windowConfiguration.getRotation();
if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
rotation = mDisplayContent.getRotation();
}
- if (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()
- || isFloating(parentWindowingMode) || rotation == ROTATION_UNDEFINED) {
+ if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForStableBounds
+ || getCompatDisplayInsets() != null || isFloating(parentWindowingMode)
+ || rotation == ROTATION_UNDEFINED)) {
// If the insets configuration decoupled logic is not enabled for the app, or the app
// already has a compat override, or the context doesn't contain enough info to
// calculate the override, skip the override.
@@ -8713,7 +8687,53 @@
}
// Override starts here.
- computeConfigByResolveHint(inOutConfig, newParentConfiguration);
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
+ : mDisplayContent.mBaseDisplayWidth;
+ final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
+ : mDisplayContent.mBaseDisplayHeight;
+ final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
+ .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
+ // This should be the only place override the configuration for ActivityRecord. Override
+ // the value if not calculated yet.
+ Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds == null || outAppBounds.isEmpty()) {
+ inOutConfig.windowConfiguration.setAppBounds(parentBounds);
+ outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ outAppBounds.inset(nonDecorInsets);
+ }
+ float density = inOutConfig.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = newParentConfiguration.densityDpi;
+ }
+ density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ final int overrideScreenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
+ inOutConfig.screenWidthDp = overrideScreenWidthDp;
+ }
+ if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ final int overrideScreenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
+ inOutConfig.screenHeightDp = overrideScreenHeightDp;
+ }
+ if (inOutConfig.smallestScreenWidthDp
+ == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+ && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // For the case of PIP transition and multi-window environment, the
+ // smallestScreenWidthDp is handled already. Override only if the app is in
+ // fullscreen.
+ final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
+ mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
+ mDisplayContent.getDisplayMetrics().density,
+ inOutConfig, true /* overrideConfig */);
+ }
+
+ // It's possible that screen size will be considered in different orientation with or
+ // without considering the system bar insets. Override orientation as well.
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+ inOutConfig.orientation =
+ (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ }
}
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@@ -8969,7 +8989,7 @@
if (mDisplayContent == null) {
return true;
}
- if (!mResolveConfigHint.mUseOverrideInsetsForConfig) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds) {
// No insets should be considered any more.
return true;
}
@@ -8988,7 +9008,7 @@
final Task task = getTask();
task.calculateInsetFrames(outNonDecorBounds /* outNonDecorBounds */,
outStableBounds /* outStableBounds */, parentBounds /* bounds */, di,
- mResolveConfigHint.mUseOverrideInsetsForConfig);
+ mResolveConfigHint.mUseOverrideInsetsForStableBounds);
final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// If orientation does not match the orientation with insets applied, then a
@@ -9045,7 +9065,7 @@
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
final int stableBoundsOrientation = stableBounds.width() > stableBounds.height()
? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
- final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
+ final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForStableBounds
? stableBoundsOrientation : newParentConfig.orientation;
// If the activity requires a different orientation (either by override or activityInfo),
@@ -9070,7 +9090,7 @@
return;
}
- final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForConfig
+ final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForStableBounds
? outNonDecorBounds : newParentConfig.windowConfiguration.getAppBounds();
// TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
// bounds or stable bounds to unify aspect ratio logic.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 08aeede..72b854b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1768,7 +1768,6 @@
if (!avoidMoveToFront() && (mService.mHomeProcess == null
|| mService.mHomeProcess.mUid != realCallingUid)
&& (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents())
- && !targetTask.isActivityTypeHomeOrRecents()
&& r.mTransitionController.isTransientHide(targetTask)) {
mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
}
@@ -2167,7 +2166,7 @@
// We don't need to start a new activity, and the client said not to do anything
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
- if (!mMovedToFront && mDoResume && !avoidMoveToFront()) {
+ if (!mMovedToFront && mDoResume) {
ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
targetTaskTop);
mTargetRootTask.moveToFront("intentActivityFound");
@@ -2196,7 +2195,7 @@
if (mMovedToFront) {
// We moved the task to front, use starting window to hide initial drawn delay.
targetTaskTop.showStartingWindow(true /* taskSwitch */);
- } else if (mDoResume && !avoidMoveToFront()) {
+ } else if (mDoResume) {
// Make sure the root task and its belonging display are moved to topmost.
mTargetRootTask.moveToFront("intentActivityFound");
}
@@ -2733,7 +2732,7 @@
// If a target task is specified, try to reuse that one
if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
- if (launchTask != null) {
+ if (launchTask != null && launchTask.isLeafTask()) {
return launchTask;
}
return null;
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 24d4be8..a9450c4 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -290,7 +290,7 @@
}
// The insets position may be frozen by shouldFreezeInsetsPosition(), so refresh the
// position to the latest state when it is ready to show in new rotation.
- if (mTransitionOp == OP_APP_SWITCH) {
+ if (isSeamlessTransition()) {
for (int i = windowToken.getChildCount() - 1; i >= 0; i--) {
final WindowState w = windowToken.getChildAt(i);
final InsetsSourceProvider insetsProvider = w.getControllableInsetProvider();
@@ -506,11 +506,16 @@
boolean shouldFreezeInsetsPosition(WindowState w) {
// Non-change transition (OP_APP_SWITCH) and METHOD_BLAST don't use screenshot so the
// insets should keep original position before the start transaction is applied.
- return mTransitionOp != OP_LEGACY && (mTransitionOp == OP_APP_SWITCH
+ return mTransitionOp != OP_LEGACY && (isSeamlessTransition()
|| TransitionController.SYNC_METHOD == BLASTSyncEngine.METHOD_BLAST)
&& !mIsStartTransactionCommitted && canBeAsync(w.mToken) && isTargetToken(w.mToken);
}
+ /** Returns true if there won't be a screen rotation animation (screenshot-based). */
+ private boolean isSeamlessTransition() {
+ return mTransitionOp == OP_APP_SWITCH || mTransitionOp == OP_CHANGE_MAY_SEAMLESS;
+ }
+
/**
* Returns the transaction which will be applied after the window redraws in new rotation.
* This is used to update the position of insets animation leash synchronously.
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index f7910b0..207707e 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -608,7 +608,8 @@
return mOnlyCreatorAllows;
}
- private BalVerdict setBasedOnRealCaller() {
+ @VisibleForTesting
+ BalVerdict setBasedOnRealCaller() {
mBasedOnRealCaller = true;
return this;
}
@@ -714,9 +715,6 @@
if (!state.hasRealCaller()) {
if (resultForCaller.allows()) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "Background activity start allowed. " + state);
- }
return allowBasedOnCaller(state);
}
return abortLaunch(state);
@@ -742,15 +740,9 @@
// Handle cases with explicit opt-in
if (resultForCaller.allows() && state.callerExplicitOptInOrAutoOptIn()) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "Activity start explicitly allowed by caller. " + state);
- }
return allowBasedOnCaller(state);
}
if (resultForRealCaller.allows() && state.realCallerExplicitOptInOrAutoOptIn()) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "Activity start explicitly allowed by real caller. " + state);
- }
return allowBasedOnRealCaller(state);
}
// Handle PendingIntent cases with default behavior next
@@ -1694,16 +1686,15 @@
@VisibleForTesting
boolean shouldLogStats(BalVerdict finalVerdict, BalState state) {
- if (finalVerdict.blocks()) {
- return false;
- }
- if (!state.isPendingIntent() && finalVerdict.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
- return false;
- }
- if (state.mBalAllowedByPiSender.allowsBackgroundActivityStarts()
- && state.mResultForRealCaller != null
- && state.mResultForRealCaller.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
- return false;
+ if (finalVerdict.getRawCode() == BAL_ALLOW_VISIBLE_WINDOW) {
+ if (!state.isPendingIntent()) {
+ // regular activity start by visible app
+ return false;
+ }
+ if (finalVerdict.mBasedOnRealCaller) {
+ // PendingIntent started by visible app
+ return false;
+ }
}
return true;
}
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index ca5f26a..125eb2a 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -28,7 +28,6 @@
import android.graphics.Rect;
import android.os.Message;
import android.os.Trace;
-import android.util.Log;
import android.util.Slog;
import android.view.DisplayInfo;
import android.window.DisplayAreaInfo;
@@ -391,6 +390,7 @@
|| first.defaultModeId != second.defaultModeId
|| first.userPreferredModeId != second.userPreferredModeId
|| !Arrays.equals(first.supportedModes, second.supportedModes)
+ || !Arrays.equals(first.appsSupportedModes, second.appsSupportedModes)
|| first.colorMode != second.colorMode
|| !Arrays.equals(first.supportedColorModes, second.supportedColorModes)
|| !Objects.equals(first.hdrCapabilities, second.hdrCapabilities)
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e49cb38..e2b0932 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5707,7 +5707,9 @@
// VR virtual display will be used to run and render 2D app within a VR experience.
&& mDisplayId != mWmService.mVr2dDisplayId
// Do not show system decorations on untrusted virtual display.
- && isTrusted();
+ && isTrusted()
+ // No system decoration on rear display.
+ && (mDisplay.getFlags() & Display.FLAG_REAR) == 0;
}
/**
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 72ae64c..e3827aa 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -239,8 +239,8 @@
dragSurface = mSurfaceControl;
}
}
- DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, dragSurface, null,
+ DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, x, y,
+ mThumbOffsetX, mThumbOffsetY, mFlags, null, null, null, dragSurface, null,
mDragResult);
try {
if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws);
@@ -298,7 +298,7 @@
* as a part of the dispatched event.
*/
private DragEvent createDropEvent(float x, float y, @Nullable WindowState touchedWin,
- boolean includeDragSurface) {
+ boolean includePrivateInfo) {
if (touchedWin != null) {
final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
final DragAndDropPermissionsHandler dragAndDropPermissions;
@@ -319,11 +319,16 @@
mData.fixUris(mSourceUserId);
}
}
+ final boolean targetInterceptsGlobalDrag = targetInterceptsGlobalDrag(touchedWin);
return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mData,
- targetInterceptsGlobalDrag(touchedWin), dragAndDropPermissions);
+ /* includeDragSurface= */ targetInterceptsGlobalDrag,
+ /* includeDragFlags= */ targetInterceptsGlobalDrag,
+ dragAndDropPermissions);
} else {
return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mData,
- includeDragSurface /* includeDragSurface */, null /* dragAndDropPermissions */);
+ /* includeDragSurface= */ includePrivateInfo,
+ /* includeDragFlags= */ includePrivateInfo,
+ null /* dragAndDropPermissions */);
}
}
@@ -525,7 +530,7 @@
ClipData data = interceptsGlobalDrag ? mData.copyForTransferWithActivityInfo() : null;
DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED,
newWin.translateToWindowX(touchX), newWin.translateToWindowY(touchY),
- data, false /* includeDragSurface */,
+ data, false /* includeDragSurface */, true /* includeDragFlags */,
null /* dragAndDropPermission */);
try {
newWin.mClient.dispatchDragEvent(event);
@@ -696,8 +701,10 @@
}
private DragEvent obtainDragEvent(int action, float x, float y, ClipData data,
- boolean includeDragSurface, IDragAndDropPermissions dragAndDropPermissions) {
+ boolean includeDragSurface, boolean includeDragFlags,
+ IDragAndDropPermissions dragAndDropPermissions) {
return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
+ includeDragFlags ? mFlags : 0,
null /* localState */, mDataDescription, data,
includeDragSurface ? mSurfaceControl : null,
dragAndDropPermissions, false /* result */);
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 16d7b4f..6e11e08 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1149,6 +1149,17 @@
}
boolean shouldApplyUserFullscreenOverride() {
+ // Do not override orientation to fullscreen for camera activities.
+ // Fixed-orientation activities are rarely tested in other orientations, and it often
+ // results in sideways or stretched previews. As the camera compat treatment targets
+ // fixed-orientation activities, overriding the orientation disables the treatment.
+ final DisplayContent displayContent = mActivityRecord.mDisplayContent;
+ if (displayContent != null && displayContent.mDisplayRotationCompatPolicy != null
+ && displayContent.mDisplayRotationCompatPolicy
+ .isCameraActive(mActivityRecord, /* mustBeFullscreen= */ true)) {
+ return false;
+ }
+
if (isUserFullscreenOverrideEnabled()) {
mUserAspectRatio = getUserMinAspectRatioOverrideCode();
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 03574029..8cab7d9 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -275,7 +275,7 @@
if (refreshRateSwitchingType != SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY) {
final int preferredModeId = w.mAttrs.preferredDisplayModeId;
if (preferredModeId > 0) {
- for (Display.Mode mode : mDisplayInfo.supportedModes) {
+ for (Display.Mode mode : mDisplayInfo.appsSupportedModes) {
if (preferredModeId == mode.getModeId()) {
return w.mFrameRateVote.update(mode.getRefreshRate(),
Surface.FRAME_RATE_COMPATIBILITY_EXACT,
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index 42ca7b4..16fcb09 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -348,6 +348,9 @@
+ bitmap.isMutable() + ") to (config=ARGB_8888, isMutable=false) failed.");
return false;
}
+ final int width = bitmap.getWidth();
+ final int height = bitmap.getHeight();
+ bitmap.recycle();
final File file = mPersistInfoProvider.getHighResolutionBitmapFile(mId, mUserId);
try {
@@ -365,8 +368,8 @@
}
final Bitmap lowResBitmap = Bitmap.createScaledBitmap(swBitmap,
- (int) (bitmap.getWidth() * mPersistInfoProvider.lowResScaleFactor()),
- (int) (bitmap.getHeight() * mPersistInfoProvider.lowResScaleFactor()),
+ (int) (width * mPersistInfoProvider.lowResScaleFactor()),
+ (int) (height * mPersistInfoProvider.lowResScaleFactor()),
true /* filter */);
swBitmap.recycle();
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 07ffa69e..24fb207 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -90,8 +90,7 @@
}
/**
- * Creates the actual starting window surface. DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING
- * THIS METHOD.
+ * Creates the actual starting window surface.
*
* @param activity the app to add the starting window to
* @return a class implementing {@link StartingSurface} for easy removal with
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 3032110..05eeeb3 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -81,14 +81,12 @@
}
StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, int theme) {
- synchronized (mService.mGlobalLock) {
- final Task task = activity.getTask();
- final TaskOrganizerController controller =
- mService.mAtmService.mTaskOrganizerController;
- if (task != null && controller.addStartingWindow(task, activity, theme,
- null /* taskSnapshot */)) {
- return new StartingSurface(task, controller.getTaskOrganizer());
- }
+ final Task task = activity.getTask();
+ final TaskOrganizerController controller =
+ mService.mAtmService.mTaskOrganizerController;
+ if (task != null && controller.addStartingWindow(task, activity, theme,
+ null /* taskSnapshot */)) {
+ return new StartingSurface(task, controller.getTaskOrganizer());
}
return null;
}
@@ -143,42 +141,38 @@
StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) {
final WindowState topFullscreenOpaqueWindow;
- final Task task;
- synchronized (mService.mGlobalLock) {
- task = activity.getTask();
- if (task == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
- + activity);
- return null;
- }
- final ActivityRecord topFullscreenActivity =
- activity.getTask().getTopFullscreenActivity();
- if (topFullscreenActivity == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
- + task);
- return null;
- }
- topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
- if (topFullscreenOpaqueWindow == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: no opaque window in "
- + topFullscreenActivity);
- return null;
- }
- if (activity.mDisplayContent.getRotation() != taskSnapshot.getRotation()) {
- // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
- // that the activity will be updated to the same rotation as the snapshot. Since
- // the transition is not started yet, fixed rotation transform needs to be applied
- // earlier to make the snapshot show in a rotated container.
- activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
- activity, false /* checkOpening */);
- }
- final TaskOrganizerController controller =
- mService.mAtmService.mTaskOrganizerController;
- if (controller.addStartingWindow(task, activity, 0 /* launchTheme */, taskSnapshot)) {
- return new StartingSurface(task, controller.getTaskOrganizer());
- }
+ final Task task = activity.getTask();
+ if (task == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
+ + activity);
return null;
}
+ final ActivityRecord topFullscreenActivity = task.getTopFullscreenActivity();
+ if (topFullscreenActivity == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
+ + task);
+ return null;
+ }
+ topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
+ if (topFullscreenOpaqueWindow == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: no opaque window in "
+ + topFullscreenActivity);
+ return null;
+ }
+ if (activity.mDisplayContent.getRotation() != taskSnapshot.getRotation()) {
+ // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+ // that the activity will be updated to the same rotation as the snapshot. Since
+ // the transition is not started yet, fixed rotation transform needs to be applied
+ // earlier to make the snapshot show in a rotated container.
+ activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+ activity, false /* checkOpening */);
+ }
+ final TaskOrganizerController controller =
+ mService.mAtmService.mTaskOrganizerController;
+ if (controller.addStartingWindow(task, activity, 0 /* launchTheme */, taskSnapshot)) {
+ return new StartingSurface(task, controller.getTaskOrganizer());
+ }
+ return null;
}
private static final class DeferringStartingWindowRecord {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 26e4eaa..e034584 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -40,8 +40,6 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
@@ -1241,7 +1239,7 @@
// have any running activities, not starting one and not home stack.
shouldBeVisible = hasRunningActivities
|| (starting != null && starting.isDescendantOf(this))
- || isActivityTypeHome();
+ || (isActivityTypeHome() && !isEmbedded());
break;
}
@@ -2224,7 +2222,7 @@
static class ConfigOverrideHint {
@Nullable DisplayInfo mTmpOverrideDisplayInfo;
@Nullable ActivityRecord.CompatDisplayInsets mTmpCompatInsets;
- boolean mUseOverrideInsetsForConfig;
+ boolean mUseOverrideInsetsForStableBounds;
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@@ -2257,11 +2255,11 @@
@NonNull Configuration parentConfig, @Nullable ConfigOverrideHint overrideHint) {
DisplayInfo overrideDisplayInfo = null;
ActivityRecord.CompatDisplayInsets compatInsets = null;
- boolean useOverrideInsetsForConfig = false;
+ boolean useOverrideInsetsForStableBounds = false;
if (overrideHint != null) {
overrideDisplayInfo = overrideHint.mTmpOverrideDisplayInfo;
compatInsets = overrideHint.mTmpCompatInsets;
- useOverrideInsetsForConfig = overrideHint.mUseOverrideInsetsForConfig;
+ useOverrideInsetsForStableBounds = overrideHint.mUseOverrideInsetsForStableBounds;
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided
// display info.
@@ -2325,7 +2323,6 @@
}
}
- boolean insetsOverrideApplied = false;
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
|| inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
@@ -2342,7 +2339,7 @@
// The non decor inset are areas that could never be removed in Honeycomb. See
// {@link WindowManagerPolicy#getNonDecorInsetsLw}.
calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di,
- useOverrideInsetsForConfig);
+ useOverrideInsetsForStableBounds);
} else {
// Apply the given non-decor and stable insets to calculate the corresponding bounds
// for screen size of configuration.
@@ -2359,21 +2356,8 @@
intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
compatInsets.mStableInsets[rotation]);
outAppBounds.set(mTmpNonDecorBounds);
- } else if (useOverrideInsetsForConfig) {
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final DisplayPolicy.DecorInsets.Info decorInsets = mDisplayContent
- .getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh);
- mTmpStableBounds.set(outAppBounds);
- mTmpStableBounds.inset(decorInsets.mOverrideConfigInsets);
- outAppBounds.inset(decorInsets.mOverrideNonDecorInsets);
- mTmpNonDecorBounds.set(outAppBounds);
- // Record the override apply to avoid duplicated check.
- insetsOverrideApplied = true;
} else {
+ // Set to app bounds because it excludes decor insets.
mTmpNonDecorBounds.set(outAppBounds);
mTmpStableBounds.set(outAppBounds);
}
@@ -2415,11 +2399,6 @@
// from the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
- } else if (insetsOverrideApplied) {
- // The smallest width should also consider insets. If the insets are overridden,
- // use the overridden value.
- inOutConfig.smallestScreenWidthDp =
- Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
// otherwise, it will just inherit
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 24b533a..c4e932a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -365,7 +365,8 @@
@Nullable
TaskFragmentTransaction.Change prepareActivityReparentedToTask(
- @NonNull ActivityRecord activity) {
+ @NonNull ActivityRecord activity, @Nullable ActivityRecord nextFillTaskActivity,
+ @Nullable IBinder lastParentTfToken) {
if (activity.finishing) {
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
return null;
@@ -408,10 +409,21 @@
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
activity.token, task.mTaskId);
- return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
- .setTaskId(task.mTaskId)
- .setActivityIntent(trimIntent(activity.intent))
- .setActivityToken(activityToken);
+
+ final TaskFragmentTransaction.Change change =
+ new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
+ .setTaskId(task.mTaskId)
+ .setActivityIntent(trimIntent(activity.intent))
+ .setActivityToken(activityToken);
+ if (lastParentTfToken != null) {
+ change.setTaskFragmentToken(lastParentTfToken);
+ }
+ // Only pass the activity token to the client if it belongs to the same process.
+ if (Flags.fixPipRestoreToOverlay() && nextFillTaskActivity != null
+ && nextFillTaskActivity.getPid() == mOrganizerPid) {
+ change.setOtherActivityToken(nextFillTaskActivity.token);
+ }
+ return change;
}
void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) {
@@ -733,13 +745,13 @@
}
void onActivityReparentedToTask(@NonNull ActivityRecord activity) {
+ final Task task = activity.getTask();
final ITaskFragmentOrganizer organizer;
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
// If the activity is previously embedded in an organized TaskFragment.
organizer = activity.mLastTaskFragmentOrganizerBeforePip;
} else {
// Find the topmost TaskFragmentOrganizer.
- final Task task = activity.getTask();
final TaskFragment[] organizedTf = new TaskFragment[1];
task.forAllLeafTaskFragments(tf -> {
if (tf.isOrganizedTaskFragment()) {
@@ -757,10 +769,24 @@
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
return;
}
- addPendingEvent(new PendingTaskFragmentEvent.Builder(
+
+ final IBinder parentTfTokenBeforePip = activity.getLastEmbeddedParentTfTokenBeforePip();
+ final PendingTaskFragmentEvent.Builder builder = new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK, organizer)
.setActivity(activity)
- .build());
+ .setTaskFragmentToken(activity.getLastEmbeddedParentTfTokenBeforePip());
+
+ // Sets the next activity behinds the reparented Activity that's also not in the last
+ // embedded parent TF.
+ final ActivityRecord candidateAssociatedActivity = task.getActivity(
+ ar -> ar != activity && !ar.finishing
+ && ar.getTaskFragment().getFragmentToken() != parentTfTokenBeforePip);
+ if (candidateAssociatedActivity != null && (!candidateAssociatedActivity.isEmbedded()
+ || candidateAssociatedActivity.getTaskFragment().fillsParent())) {
+ builder.setOtherActivity(candidateAssociatedActivity);
+ }
+
+ addPendingEvent(builder.build());
}
void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
@@ -889,11 +915,16 @@
@Nullable
private final TaskFragment mTaskFragment;
@Nullable
+ private final IBinder mTaskFragmentToken;
+ @Nullable
private final IBinder mErrorCallbackToken;
@Nullable
private final Throwable mException;
@Nullable
private final ActivityRecord mActivity;
+ // An additional Activity that's needed to send back to the client other than the mActivity.
+ @Nullable
+ private final ActivityRecord mOtherActivity;
@Nullable
private final Task mTask;
// Set when the event is deferred due to the host task is invisible. The defer time will
@@ -905,17 +936,21 @@
private PendingTaskFragmentEvent(@EventType int eventType,
ITaskFragmentOrganizer taskFragmentOrg,
@Nullable TaskFragment taskFragment,
+ @Nullable IBinder taskFragmentToken,
@Nullable IBinder errorCallbackToken,
@Nullable Throwable exception,
@Nullable ActivityRecord activity,
+ @Nullable ActivityRecord otherActivity,
@Nullable Task task,
@TaskFragmentOperation.OperationType int opType) {
mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg;
mTaskFragment = taskFragment;
+ mTaskFragmentToken = taskFragmentToken;
mErrorCallbackToken = errorCallbackToken;
mException = exception;
mActivity = activity;
+ mOtherActivity = otherActivity;
mTask = task;
mOpType = opType;
}
@@ -943,12 +978,16 @@
@Nullable
private TaskFragment mTaskFragment;
@Nullable
+ private IBinder mTaskFragmentToken;
+ @Nullable
private IBinder mErrorCallbackToken;
@Nullable
private Throwable mException;
@Nullable
private ActivityRecord mActivity;
@Nullable
+ private ActivityRecord mOtherActivity;
+ @Nullable
private Task mTask;
@TaskFragmentOperation.OperationType
private int mOpType;
@@ -963,6 +1002,11 @@
return this;
}
+ Builder setTaskFragmentToken(@Nullable IBinder fragmentToken) {
+ mTaskFragmentToken = fragmentToken;
+ return this;
+ }
+
Builder setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
mErrorCallbackToken = errorCallbackToken;
return this;
@@ -978,6 +1022,11 @@
return this;
}
+ Builder setOtherActivity(@NonNull ActivityRecord otherActivity) {
+ mOtherActivity = otherActivity;
+ return this;
+ }
+
Builder setTask(@NonNull Task task) {
mTask = requireNonNull(task);
return this;
@@ -990,7 +1039,8 @@
PendingTaskFragmentEvent build() {
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
- mErrorCallbackToken, mException, mActivity, mTask, mOpType);
+ mTaskFragmentToken, mErrorCallbackToken, mException, mActivity,
+ mOtherActivity, mTask, mOpType);
}
}
}
@@ -1191,7 +1241,8 @@
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
event.mOpType, event.mException);
case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK:
- return state.prepareActivityReparentedToTask(event.mActivity);
+ return state.prepareActivityReparentedToTask(event.mActivity, event.mOtherActivity,
+ event.mTaskFragmentToken);
default:
throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType);
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index ce53290..2dc439d 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -492,6 +492,27 @@
return false;
}
+ /** Returns {@code true} if the display contains a transient-launch transition. */
+ boolean hasTransientLaunch(@NonNull DisplayContent dc) {
+ if (mCollectingTransition != null && mCollectingTransition.hasTransientLaunch()
+ && mCollectingTransition.isOnDisplay(dc)) {
+ return true;
+ }
+ for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+ final Transition transition = mWaitingTransitions.get(i);
+ if (transition.hasTransientLaunch() && transition.isOnDisplay(dc)) {
+ return true;
+ }
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ final Transition transition = mPlayingTransitions.get(i);
+ if (transition.hasTransientLaunch() && transition.isOnDisplay(dc)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean isTransientHide(@NonNull Task task) {
if (mCollectingTransition != null && mCollectingTransition.isInTransientHide(task)) {
return true;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 65e1761..3e43f5a 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -165,7 +165,7 @@
|| (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
}
} else if (w.hasWallpaper() && mService.mPolicy.isKeyguardHostWindow(w.mAttrs)
- && w.mTransitionController.isTransitionOnDisplay(mDisplayContent)) {
+ && w.mTransitionController.hasTransientLaunch(mDisplayContent)) {
// If we have no candidates at all, notification shade is allowed to be the target
// of last resort even if it has not been made visible yet.
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found keyguard as wallpaper target: " + w);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8fb83fa..90c287c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -224,6 +224,7 @@
import android.view.InputChannel;
import android.view.InputWindowHandle;
import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
import android.view.Surface.Rotation;
@@ -432,6 +433,10 @@
/** @see #isLastConfigReportedToClient() */
private boolean mLastConfigReportedToClient;
+ // TODO(b/339380439): Ensure to use the same object for IWindowSession#relayout
+ private final InsetsSourceControl.Array mLastReportedActiveControls =
+ new InsetsSourceControl.Array();
+
private final Configuration mTempConfiguration = new Configuration();
/**
@@ -3813,9 +3818,9 @@
}
final InsetsStateController stateController =
getDisplayContent().getInsetsStateController();
+ mLastReportedActiveControls.set(stateController.getControlsForDispatch(this));
try {
- mClient.insetsControlChanged(getCompatInsetsState(),
- stateController.getControlsForDispatch(this));
+ mClient.insetsControlChanged(getCompatInsetsState(), mLastReportedActiveControls);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver inset control state change to w=" + this, e);
}
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index d2b7c7d..ddbc535 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -350,7 +350,7 @@
case Region::ITU_2:
return Rds::US;
default:
- ALOGE("Unexpected region: %d", region);
+ ALOGE("Unexpected region: %d", static_cast<int>(region));
return Rds::NONE;
}
}
@@ -365,7 +365,7 @@
case Region::JAPAN:
return Deemphasis::D50;
default:
- ALOGE("Unexpected region: %d", region);
+ ALOGE("Unexpected region: %d", static_cast<int>(region));
return Deemphasis::D50;
}
}
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index 22c0f73..6613a25 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -23,20 +23,22 @@
namespace android {
-static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj, jboolean secure,
- jstring uniqueIdStr, jfloat requestedRefreshRate) {
+static jobject nativeCreateVirtualDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
+ jboolean secure, jstring uniqueIdStr,
+ jfloat requestedRefreshRate) {
const ScopedUtfChars name(env, nameObj);
const ScopedUtfChars uniqueId(env, uniqueIdStr);
- sp<IBinder> token(SurfaceComposerClient::createDisplay(String8(name.c_str()), bool(secure),
- std::string(uniqueId.c_str()),
- requestedRefreshRate));
+ sp<IBinder> token(SurfaceComposerClient::createVirtualDisplay(std::string(name.c_str()),
+ bool(secure),
+ std::string(uniqueId.c_str()),
+ requestedRefreshRate));
return javaObjectForIBinder(env, token);
}
-static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static void nativeDestroyVirtualDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
- SurfaceComposerClient::destroyDisplay(token);
+ SurfaceComposerClient::destroyVirtualDisplay(token);
}
static void nativeOverrideHdrTypes(JNIEnv* env, jclass clazz, jobject tokenObject,
@@ -180,10 +182,10 @@
static const JNINativeMethod sDisplayMethods[] = {
// clang-format off
- {"nativeCreateDisplay", "(Ljava/lang/String;ZLjava/lang/String;F)Landroid/os/IBinder;",
- (void*)nativeCreateDisplay },
- {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
- (void*)nativeDestroyDisplay },
+ {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZLjava/lang/String;F)Landroid/os/IBinder;",
+ (void*)nativeCreateVirtualDisplay },
+ {"nativeDestroyVirtualDisplay", "(Landroid/os/IBinder;)V",
+ (void*)nativeDestroyVirtualDisplay },
{"nativeOverrideHdrTypes", "(Landroid/os/IBinder;[I)V",
(void*)nativeOverrideHdrTypes },
{"nativeGetPhysicalDisplayIds", "()[J",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 97f1e19..b19de18 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -601,7 +601,7 @@
// Original data: [{'inputPort1': '1'}, {'inputPort2': '2'}]
// Received data: ['inputPort1', '1', 'inputPort2', '2']
// So we unpack accordingly here.
- outConfig->portAssociations.clear();
+ outConfig->inputPortToDisplayPortAssociations.clear();
jobjectArray portAssociations = jobjectArray(env->CallObjectMethod(mServiceObj,
gServiceClassInfo.getInputPortAssociations));
if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) {
@@ -618,16 +618,16 @@
displayPortStr.c_str());
continue;
}
- outConfig->portAssociations.insert({inputPort, displayPort});
+ outConfig->inputPortToDisplayPortAssociations.insert({inputPort, displayPort});
}
env->DeleteLocalRef(portAssociations);
}
- outConfig->uniqueIdAssociationsByPort = readMapFromInterleavedJavaArray<
+ outConfig->inputPortToDisplayUniqueIdAssociations = readMapFromInterleavedJavaArray<
std::string>(gServiceClassInfo.getInputUniqueIdAssociationsByPort,
"getInputUniqueIdAssociationsByPort");
- outConfig->uniqueIdAssociationsByDescriptor = readMapFromInterleavedJavaArray<
+ outConfig->inputDeviceDescriptorToDisplayUniqueIdAssociations = readMapFromInterleavedJavaArray<
std::string>(gServiceClassInfo.getInputUniqueIdAssociationsByDescriptor,
"getInputUniqueIdAssociationsByDescriptor");
@@ -2451,12 +2451,6 @@
im->getInputManager()->getDispatcher().monitor();
}
-static jboolean nativeIsInputDeviceEnabled(JNIEnv* env, jobject nativeImplObj, jint deviceId) {
- NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
-
- return im->getInputManager()->getReader().isInputDeviceEnabled(deviceId);
-}
-
static void nativeEnableInputDevice(JNIEnv* env, jobject nativeImplObj, jint deviceId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -2798,7 +2792,6 @@
{"sysfsNodeChanged", "(Ljava/lang/String;)V", (void*)nativeSysfsNodeChanged},
{"dump", "()Ljava/lang/String;", (void*)nativeDump},
{"monitor", "()V", (void*)nativeMonitor},
- {"isInputDeviceEnabled", "(I)Z", (void*)nativeIsInputDeviceEnabled},
{"enableInputDevice", "(I)V", (void*)nativeEnableInputDevice},
{"disableInputDevice", "(I)V", (void*)nativeDisableInputDevice},
{"reloadPointerIcons", "()V", (void*)nativeReloadPointerIcons},
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 0733968..841f314 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -116,10 +116,8 @@
}
gLastEventTime[eventType] = eventTime;
}
-
- // Tell the power HAL when user activity occurs.
- setPowerBoost(Boost::INTERACTION, 0);
}
+ // Note that the below PowerManagerService method may call setPowerBoost.
JNIEnv* env = AndroidRuntime::getJNIEnv();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 85d2a0d..5bf5efd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1300,6 +1300,9 @@
Bundle prevRestrictions) {
resetCrossProfileIntentFiltersIfNeeded(userId, newRestrictions, prevRestrictions);
resetUserVpnIfNeeded(userId, newRestrictions, prevRestrictions);
+ if (Flags.deletePrivateSpaceUnderRestriction()) {
+ removePrivateSpaceIfRestrictionIsSet(userId, newRestrictions, prevRestrictions);
+ }
}
private void resetUserVpnIfNeeded(
@@ -1331,6 +1334,17 @@
UserHandle.of(userId));
}
}
+ private void removePrivateSpaceIfRestrictionIsSet(
+ int userId, Bundle newRestrictions, Bundle prevRestrictions) {
+ final boolean newlyEnforced =
+ !prevRestrictions.getBoolean(UserManager.DISALLOW_ADD_PRIVATE_PROFILE)
+ && newRestrictions.getBoolean(UserManager.DISALLOW_ADD_PRIVATE_PROFILE);
+ if (!newlyEnforced) {
+ return;
+ }
+ mDpms.removePrivateSpaceWithinUserGroupIfExists(userId);
+ }
+
}
private void clearUserConfiguredVpns(int userId) {
@@ -1375,6 +1389,42 @@
}
}
+ /**
+ * Given a parent userId, try removing all private space profiles with its profile group, and
+ * post a notification if at least one private space profile is removed.
+ */
+ private void removePrivateSpaceWithinUserGroupIfExists(int userId) {
+ boolean removed = false;
+ if (mUserManager.isProfile(userId)) return;
+ for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
+ if (profileId == userId) continue;
+ if (mUserManager.getUserInfo(profileId).isPrivateProfile()) {
+ Slogf.i(LOG_TAG, "Removing private space %d due to DISALLOW_ADD_PRIVATE_PROFILE",
+ profileId);
+ removed |= mUserManager.removeUserEvenWhenDisallowed(profileId);
+ }
+ }
+ if (removed) {
+ mHandler.post(() -> sendPrivateSpaceRemovedNotification(userId));
+ }
+ }
+
+ private void sendPrivateSpaceRemovedNotification(int parentUserId) {
+ String notification_details = mContext.getString(
+ R.string.private_space_deleted_by_admin_details);
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(
+ R.string.private_space_deleted_by_admin))
+ .setContentText(notification_details)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(notification_details))
+ .build();
+ mInjector.getNotificationManager().notifyAsUser(/* tag= */ null,
+ SystemMessage.NOTE_PROFILE_WIPED, notification, UserHandle.of(parentUserId));
+ }
+
private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
@Override
@@ -2128,9 +2178,9 @@
mDevicePolicyEngine.load();
mContactSystemRoleHolders = fetchOemSystemHolders(/* roleResIds...= */
- com.android.internal.R.string.config_defaultSms,
- com.android.internal.R.string.config_defaultDialer,
- com.android.internal.R.string.config_systemContacts
+ R.string.config_defaultSms,
+ R.string.config_defaultDialer,
+ R.string.config_systemContacts
);
// The binder caches are not enabled until the first invalidation.
@@ -10459,7 +10509,7 @@
}
final String configComponent = mContext.getResources().getString(
- com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
+ R.string.config_defaultSupervisionProfileOwnerComponent);
if (configComponent != null) {
final ComponentName componentName = ComponentName.unflattenFromString(configComponent);
if (who.equals(componentName)) {
@@ -10469,7 +10519,7 @@
// Check the system supervision role.
final String configPackage = mContext.getResources().getString(
- com.android.internal.R.string.config_systemSupervision);
+ R.string.config_systemSupervision);
return who.getPackageName().equals(configPackage);
}
@@ -22560,7 +22610,7 @@
private String[] getDefaultRoleHolderPackageNameAndSignature() {
String packageNameAndSignature = mContext.getString(
- com.android.internal.R.string.config_devicePolicyManagement);
+ R.string.config_devicePolicyManagement);
if (TextUtils.isEmpty(packageNameAndSignature)) {
return null;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
index 0e448cd..a1bf040 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
@@ -25,7 +25,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Awaits the deletion of all the non-required apps.
@@ -33,38 +32,38 @@
final class NonRequiredPackageDeleteObserver extends IPackageDeleteObserver.Stub {
private static final int PACKAGE_DELETE_TIMEOUT_SEC = 30;
- private final AtomicInteger mPackageCount = new AtomicInteger(/* initialValue= */ 0);
private final CountDownLatch mLatch;
- private boolean mSuccess;
+ private boolean mFailed = false;
NonRequiredPackageDeleteObserver(int packageCount) {
this.mLatch = new CountDownLatch(packageCount);
- this.mPackageCount.set(packageCount);
}
@Override
public void packageDeleted(String packageName, int returnCode) {
if (returnCode != PackageManager.DELETE_SUCCEEDED) {
Slog.e(LOG_TAG, "Failed to delete package: " + packageName);
- mLatch.notifyAll();
- return;
- }
- int currentPackageCount = mPackageCount.decrementAndGet();
- if (currentPackageCount == 0) {
- mSuccess = true;
- Slog.i(LOG_TAG, "All non-required system apps with launcher icon, "
- + "and all disallowed apps have been uninstalled.");
+ mFailed = true;
}
mLatch.countDown();
}
public boolean awaitPackagesDeletion() {
try {
- mLatch.await(PACKAGE_DELETE_TIMEOUT_SEC, TimeUnit.SECONDS);
+ if (mLatch.await(PACKAGE_DELETE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!mFailed) {
+ Slog.i(LOG_TAG, "All non-required system apps with launcher icon, "
+ + "and all disallowed apps have been uninstalled.");
+ }
+ return !mFailed;
+ } else {
+ Slog.i(LOG_TAG, "Waiting time elapsed before all package deletion finished");
+ return false;
+ }
} catch (InterruptedException e) {
Log.w(LOG_TAG, "Interrupted while waiting for package deletion", e);
Thread.currentThread().interrupt();
+ return false;
}
- return mSuccess;
}
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 54d101a..488fe57 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -63,6 +63,9 @@
"com.android.server.profcollect.UPLOAD_PROFILES";
private static final long BG_PROCESS_INTERVAL = TimeUnit.HOURS.toMillis(4); // every 4 hours.
+ private int mUsageSetting;
+ private boolean mUploadEnabled;
+
private IProfCollectd mIProfcollect;
private static ProfcollectForwardingService sSelfService;
private final Handler mHandler = new ProfcollectdHandler(IoThread.getHandler().getLooper());
@@ -78,7 +81,7 @@
public void onReceive(Context context, Intent intent) {
if (INTENT_UPLOAD_PROFILES.equals(intent.getAction())) {
Log.d(LOG_TAG, "Received broadcast to pack and upload reports");
- packAndUploadReport();
+ createAndUploadReport(sSelfService);
}
}
};
@@ -91,6 +94,17 @@
}
sSelfService = this;
+ // Get "Usage & diagnostics" checkbox status. 1 is for enabled, 0 is for disabled.
+ try {
+ mUsageSetting = Settings.Global.getInt(context.getContentResolver(), "multi_cb");
+ } catch (SettingNotFoundException e) {
+ Log.e(LOG_TAG, "Usage setting not found: " + e.getMessage());
+ mUsageSetting = -1;
+ }
+
+ mUploadEnabled =
+ context.getResources().getBoolean(R.bool.config_profcollectReportUploaderEnabled);
+
final IntentFilter filter = new IntentFilter();
filter.addAction(INTENT_UPLOAD_PROFILES);
context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
@@ -221,7 +235,6 @@
*/
public static void schedule(Context context) {
JobScheduler js = context.getSystemService(JobScheduler.class);
-
js.schedule(new JobInfo.Builder(JOB_IDLE_PROCESS, JOB_SERVICE_NAME)
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
@@ -235,19 +248,7 @@
if (DEBUG) {
Log.d(LOG_TAG, "Starting background process job");
}
-
- BackgroundThread.get().getThreadHandler().post(
- () -> {
- try {
- if (sSelfService.mIProfcollect == null) {
- return;
- }
- sSelfService.mIProfcollect.process();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to process profiles in background: "
- + e.getMessage());
- }
- });
+ createAndUploadReport(sSelfService);
jobFinished(params, false);
return true;
}
@@ -357,7 +358,7 @@
}
if (status == UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT) {
- packAndUploadReport();
+ createAndUploadReport(sSelfService);
}
}
@@ -368,41 +369,27 @@
});
}
- private void packAndUploadReport() {
- if (mIProfcollect == null) {
+ private static void createAndUploadReport(ProfcollectForwardingService pfs) {
+ String reportName;
+ try {
+ reportName = pfs.mIProfcollect.report(pfs.mUsageSetting) + ".zip";
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Failed to create report: " + e.getMessage());
return;
}
-
- Context context = getContext();
+ if (!pfs.mUploadEnabled) {
+ Log.i(LOG_TAG, "Upload is not enabled.");
+ return;
+ }
BackgroundThread.get().getThreadHandler().post(() -> {
- try {
- int usageSetting = -1;
- try {
- // Get "Usage & diagnostics" checkbox status. 1 is for enabled, 0 is for
- // disabled.
- usageSetting = Settings.Global.getInt(context.getContentResolver(), "multi_cb");
- } catch (SettingNotFoundException e) {
- Log.i(LOG_TAG, "Usage setting not found: " + e.getMessage());
- }
-
- // Prepare profile report
- String reportName = mIProfcollect.report(usageSetting) + ".zip";
-
- if (!context.getResources().getBoolean(
- R.bool.config_profcollectReportUploaderEnabled)) {
- Log.i(LOG_TAG, "Upload is not enabled.");
- return;
- }
-
- // Upload the report
- Intent intent = new Intent()
- .setPackage("com.android.shell")
- .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
- .putExtra("filename", reportName);
- context.sendBroadcast(intent);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to upload report: " + e.getMessage());
- }
+ Intent intent = new Intent()
+ .setPackage("com.android.shell")
+ .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
+ .putExtra("filename", reportName);
+ pfs.getContext().sendBroadcast(intent);
});
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Sent report for upload.");
+ }
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 54b2d4d..8844e6c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -709,6 +709,64 @@
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
}
+ @Test
+ public void testCreateVirtualDisplayOwnFocus_checkDisplayDeviceInfo() throws RemoteException {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+
+ // This is effectively the DisplayManager service published to ServiceManager.
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+ final String uniqueId = "uniqueId --- Own Focus Test -- checkDisplayDeviceInfo";
+ float refreshRate = 60.0f;
+ int width = 600;
+ int height = 800;
+ int dpi = 320;
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
+
+ when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+ PackageManager.PERMISSION_GRANTED);
+ when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+ VIRTUAL_DISPLAY_NAME, width, height, dpi);
+ builder.setFlags(flags);
+ builder.setUniqueId(uniqueId);
+ builder.setRequestedRefreshRate(refreshRate);
+
+ // Create a virtual display in its own display group.
+ final VirtualDisplayConfig ownerDisplayConfig = builder.build();
+ int displayId = bs.createVirtualDisplay(ownerDisplayConfig, /* callback= */ mMockAppToken,
+ /* projection= */ null, PACKAGE_NAME);
+ verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+ nullable(IMediaProjection.class));
+
+ DisplayInfo displayInfo = bs.getDisplayInfo(displayId);
+ assertNotNull(displayInfo);
+ assertTrue((displayInfo.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
+ final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
+ PACKAGE_NAME, Process.myUid(), ownerDisplayConfig);
+ assertEquals(displayInfo.uniqueId, displayUniqueId);
+ assertEquals(displayInfo.name, VIRTUAL_DISPLAY_NAME);
+ assertEquals(displayInfo.ownerPackageName, PACKAGE_NAME);
+ assertEquals(displayInfo.getRefreshRate(), refreshRate, 0.1f);
+
+ performTraversalInternal(displayManager);
+
+ // Flush the handler.
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+ assertNotNull(ddi);
+ assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
+ assertEquals(ddi.width, width);
+ assertEquals(ddi.height, height);
+ assertEquals(ddi.name, displayInfo.name);
+ assertEquals(ddi.ownerPackageName, displayInfo.ownerPackageName);
+ assertEquals(ddi.uniqueId, displayInfo.uniqueId);
+ assertEquals(ddi.renderFrameRate, displayInfo.getRefreshRate(), 0.1f);
+ }
+
/**
* Tests that the virtual display is created along-side the default display.
*/
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 1a03e78..6d138c5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -50,6 +50,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@@ -80,10 +81,10 @@
import com.android.internal.foldables.FoldGracePeriodProvider;
import com.android.internal.util.test.LocalServiceKeeperRule;
-import com.android.server.LocalServices;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
+import com.android.server.display.mode.SyntheticModeManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.utils.FoldSettingProvider;
@@ -91,6 +92,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -141,6 +143,8 @@
@Mock DisplayManagerFlags mFlagsMock;
@Mock DisplayAdapter mDisplayAdapterMock;
@Mock WindowManagerPolicy mWindowManagerPolicy;
+ @Mock
+ SyntheticModeManager mSyntheticModeManagerMock;
@Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
@Captor ArgumentCaptor<Integer> mDisplayEventCaptor;
@@ -196,6 +200,8 @@
when(mResourcesMock.getIntArray(
com.android.internal.R.array.config_deviceStatesOnWhichToSleep))
.thenReturn(new int[]{0});
+ when(mSyntheticModeManagerMock.createAppSupportedModes(any(), any())).thenAnswer(
+ AdditionalAnswers.returnsSecondArg());
when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false);
mLooper = new TestLooper();
@@ -204,7 +210,7 @@
mFoldGracePeriodProvider,
mDisplayDeviceRepo,
mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
- mDeviceStateToLayoutMapSpy, mFlagsMock);
+ mDeviceStateToLayoutMapSpy, mFlagsMock, mSyntheticModeManagerMock);
mLogicalDisplayMapper.onWindowManagerReady();
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 779445e..8936f06 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -40,9 +41,11 @@
import androidx.test.filters.SmallTest;
import com.android.server.display.layout.Layout;
+import com.android.server.display.mode.SyntheticModeManager;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.AdditionalAnswers;
import java.io.InputStream;
import java.io.OutputStream;
@@ -54,6 +57,7 @@
private static final int DISPLAY_WIDTH = 100;
private static final int DISPLAY_HEIGHT = 200;
private static final int MODE_ID = 1;
+ private static final int OTHER_MODE_ID = 2;
private LogicalDisplay mLogicalDisplay;
private DisplayDevice mDisplayDevice;
@@ -61,6 +65,7 @@
private Context mContext;
private IBinder mDisplayToken;
private DisplayDeviceRepository mDeviceRepo;
+ private SyntheticModeManager mSyntheticModeManager;
private final DisplayDeviceInfo mDisplayDeviceInfo = new DisplayDeviceInfo();
@Before
@@ -71,6 +76,7 @@
mDisplayAdapter = mock(DisplayAdapter.class);
mContext = mock(Context.class);
mDisplayToken = mock(IBinder.class);
+ mSyntheticModeManager = mock(SyntheticModeManager.class);
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo());
@@ -81,6 +87,8 @@
mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 60)};
when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo);
+ when(mSyntheticModeManager.createAppSupportedModes(any(), any())).thenAnswer(
+ AdditionalAnswers.returnsSecondArg());
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
@@ -102,7 +110,7 @@
public void finishWrite(OutputStream os, boolean success) {}
}));
mDeviceRepo.onDisplayDeviceEvent(mDisplayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
}
@Test
@@ -111,7 +119,7 @@
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
var originalDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
assertEquals(DISPLAY_WIDTH, originalDisplayInfo.logicalWidth);
assertEquals(DISPLAY_HEIGHT, originalDisplayInfo.logicalHeight);
@@ -156,7 +164,7 @@
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
var originalDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
// Content width not scaled
assertEquals(DISPLAY_WIDTH, originalDisplayInfo.logicalWidth);
@@ -185,7 +193,7 @@
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
var originalDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
// Content width re-scaled
assertEquals(DISPLAY_WIDTH * 2, originalDisplayInfo.logicalWidth);
@@ -214,7 +222,7 @@
mDisplayDeviceInfo.xDpi = 1.0f;
mDisplayDeviceInfo.yDpi = 0.5f;
mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
@@ -234,7 +242,7 @@
displayInfo.logicalHeight = DISPLAY_HEIGHT;
mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
var updatedDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
assertEquals(Surface.ROTATION_90, updatedDisplayInfo.rotation);
@@ -277,7 +285,7 @@
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
@@ -301,7 +309,7 @@
mDisplayDeviceInfo.xDpi = 1.0f;
mDisplayDeviceInfo.yDpi = 0.5f;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
var originalDisplayInfo = mLogicalDisplay.getDisplayInfoLocked();
// Content width re-scaled
assertEquals(DISPLAY_WIDTH, originalDisplayInfo.logicalWidth);
@@ -341,7 +349,7 @@
expectedPosition.set(40, -20);
mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
displayInfo.logicalWidth = DISPLAY_HEIGHT;
displayInfo.logicalHeight = DISPLAY_WIDTH;
displayInfo.rotation = Surface.ROTATION_90;
@@ -356,7 +364,7 @@
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
/*isAlwaysRotateDisplayDeviceEnabled=*/ true);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
Point expectedPosition = new Point();
SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
@@ -383,7 +391,7 @@
expectedPosition.set(40, -20);
mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
displayInfo.logicalWidth = DISPLAY_HEIGHT;
displayInfo.logicalHeight = DISPLAY_WIDTH;
displayInfo.rotation = Surface.ROTATION_90;
@@ -444,7 +452,7 @@
// Update position and test to see that it's been updated to a rear, presentation display
// that destroys content on removal
mLogicalDisplay.setDevicePositionLocked(Layout.Display.POSITION_REAR);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertEquals(Display.FLAG_REAR | Display.FLAG_PRESENTATION,
mLogicalDisplay.getDisplayInfoLocked().flags);
assertEquals(Display.REMOVE_MODE_DESTROY_CONTENT,
@@ -452,7 +460,7 @@
// And then check the unsetting the position resets both
mLogicalDisplay.setDevicePositionLocked(Layout.Display.POSITION_UNKNOWN);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertEquals(0, mLogicalDisplay.getDisplayInfoLocked().flags);
assertEquals(Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY,
mLogicalDisplay.getDisplayInfoLocked().removeMode);
@@ -468,7 +476,7 @@
// Display info should only be updated when updateLocked is called
assertEquals(info2, info1);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
assertNotEquals(info3, info2);
assertEquals(layoutLimitedRefreshRate, info3.layoutLimitedRefreshRate);
@@ -483,7 +491,7 @@
mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate);
assertTrue(mLogicalDisplay.isDirtyLocked());
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertFalse(mLogicalDisplay.isDirtyLocked());
}
@@ -497,7 +505,7 @@
// Display info should only be updated when updateLocked is called
assertEquals(info2, info1);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
assertNotEquals(info3, info2);
assertTrue(refreshRanges.contentEquals(info3.thermalRefreshRateThrottling));
@@ -512,7 +520,7 @@
mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges);
assertTrue(mLogicalDisplay.isDirtyLocked());
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertFalse(mLogicalDisplay.isDirtyLocked());
}
@@ -525,7 +533,7 @@
// Display info should only be updated when updateLocked is called
assertEquals(info2, info1);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
assertNotEquals(info3, info2);
assertEquals(newId, info3.displayGroupId);
@@ -538,7 +546,7 @@
mLogicalDisplay.updateDisplayGroupIdLocked(99);
assertTrue(mLogicalDisplay.isDirtyLocked());
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertFalse(mLogicalDisplay.isDirtyLocked());
}
@@ -551,7 +559,7 @@
// Display info should only be updated when updateLocked is called
assertEquals(info2, info1);
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
assertNotEquals(info3, info2);
assertEquals(brightnessThrottlingDataId, info3.thermalBrightnessThrottlingDataId);
@@ -564,7 +572,20 @@
mLogicalDisplay.setThermalBrightnessThrottlingDataIdLocked("99");
assertTrue(mLogicalDisplay.isDirtyLocked());
- mLogicalDisplay.updateLocked(mDeviceRepo);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
assertFalse(mLogicalDisplay.isDirtyLocked());
}
+
+ @Test
+ public void testGetsAppSupportedModesFromSyntheticModeManager() {
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
+ Display.Mode[] appSupportedModes = new Display.Mode[] {new Display.Mode(OTHER_MODE_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 45)};
+ when(mSyntheticModeManager.createAppSupportedModes(
+ any(), eq(mDisplayDeviceInfo.supportedModes))).thenReturn(appSupportedModes);
+
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
+ DisplayInfo info = mLogicalDisplay.getDisplayInfoLocked();
+ assertArrayEquals(appSupportedModes, info.appsSupportedModes);
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index c01b15c..81e6cc3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -18,12 +18,14 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.os.IBinder;
+import android.os.Process;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -88,6 +90,25 @@
}
@Test
+ public void testCreatesVirtualDisplay_checkGeneratedDisplayUniqueIdPrefix() {
+ VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
+ /* height= */ 1, /* densityDpi= */ 1).build();
+
+ final String packageName = "testpackage";
+ final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
+ packageName, Process.myUid(), config);
+
+ DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+ mMockCallback, /* projection= */ null, /* ownerUid= */ 10,
+ packageName, displayUniqueId, /* surface= */ null, /* flags= */ 0, config);
+
+ assertNotNull(result);
+
+ final String uniqueId = result.getUniqueId();
+ assertTrue(uniqueId.startsWith(VirtualDisplayAdapter.UNIQUE_ID_PREFIX + packageName));
+ }
+
+ @Test
public void testDoesNotCreateVirtualDisplayForSameCallback() {
VirtualDisplayConfig config1 = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
/* height= */ 1, /* densityDpi= */ 1).build();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 19bff56..d19f479 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -395,7 +395,7 @@
automaticBrightnessController);
assertEquals(automaticScreenBrightness,
mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
- new BrightnessEvent(DISPLAY_ID)), 0.0f);
+ new BrightnessEvent(DISPLAY_ID), false), 0.0f);
assertEquals(automaticScreenBrightness,
mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastUsedLux(
new BrightnessEvent(DISPLAY_ID)), 0.0f);
@@ -461,8 +461,12 @@
}
@Test
- public void isAutoBrightnessValid_returnsTrueWhenBrightnessIsValid() {
+ public void isAutoBrightnessValid_returnsTrueWhenBrightnessIsValid_adjustsAutoBrightness()
+ throws Settings.SettingNotFoundException {
+ float adjustment = 0.1f;
mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment())
+ .thenReturn(0.1f);
mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, true,
BrightnessReason.REASON_UNKNOWN,
DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, 0.1f,
@@ -470,6 +474,11 @@
when(mAutomaticBrightnessController.getAutomaticScreenBrightness(null))
.thenReturn(0.2f);
assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessValid());
+ assertEquals(adjustment, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
+ assertEquals(adjustment, Settings.System.getFloatForUser(
+ mContext.getContentResolver(),
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+ UserHandle.USER_CURRENT), 0.0f);
}
@Test
@@ -486,6 +495,15 @@
when(mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent))
.thenReturn(brightness);
+
+ // We do this to apply the automatic brightness adjustments
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()).thenReturn(
+ 0.25f);
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightness(null))
+ .thenReturn(brightness);
+ assertEquals(brightness, mAutomaticBrightnessStrategy
+ .getAutomaticScreenBrightness(null, false), 0.0f);
+
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
mock(DisplayManagerInternal.DisplayPowerRequest.class);
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
@@ -529,6 +547,12 @@
when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()).thenReturn(
autoBrightnessAdjustment);
+ // We do this to apply the automatic brightness adjustments
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightness(null))
+ .thenReturn(brightness);
+ assertEquals(brightness, mAutomaticBrightnessStrategy
+ .getAutomaticScreenBrightness(null, false), 0.0f);
+
DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
.setBrightness(brightness)
.setSdrBrightness(brightness)
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/AppRequestObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/AppRequestObserverTest.kt
index f0abcd2..cf6146f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/AppRequestObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/AppRequestObserverTest.kt
@@ -58,11 +58,14 @@
val modes = arrayOf(
Display.Mode(1, 1000, 1000, 60f),
Display.Mode(2, 1000, 1000, 90f),
- Display.Mode(3, 1000, 1000, 120f)
+ Display.Mode(3, 1000, 1000, 120f),
+ Display.Mode(99, 1000, 1000, 45f, 45f, true, floatArrayOf(), intArrayOf())
)
- displayModeDirector.injectSupportedModesByDisplay(SparseArray<Array<Display.Mode>>().apply {
- append(Display.DEFAULT_DISPLAY, modes)
- })
+
+ displayModeDirector.injectAppSupportedModesByDisplay(
+ SparseArray<Array<Display.Mode>>().apply {
+ append(Display.DEFAULT_DISPLAY, modes)
+ })
displayModeDirector.injectDefaultModeByDisplay(SparseArray<Display.Mode>().apply {
append(Display.DEFAULT_DISPLAY, modes[0])
})
@@ -116,7 +119,9 @@
BaseModeRefreshRateVote(60f), SizeVote(1000, 1000, 1000, 1000), null),
PREFERRED_REFRESH_RATE_IGNORED(true, 0, 60f, 0f, 0f,
null, null, null),
- PREFERRED_REFRESH_RATE_INVALID(false, 0, 45f, 0f, 0f,
+ PREFERRED_REFRESH_RATE_INVALID(false, 0, 25f, 0f, 0f,
null, null, null),
+ SYNTHETIC_MODE(false, 99, 0f, 0f, 0f,
+ RenderVote(45f, 45f), SizeVote(1000, 1000, 1000, 1000), null),
}
}
\ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt
new file mode 100644
index 0000000..5cd3a33
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SyntheticModeManagerTest.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.server.display.mode
+
+import android.view.Display.Mode
+import com.android.server.display.DisplayDeviceConfig
+import com.android.server.display.feature.DisplayManagerFlags
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+private val DISPLAY_MODES = arrayOf(
+ Mode(1, 100, 100, 60f),
+ Mode(2, 100, 100, 120f)
+)
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class SyntheticModeManagerTest {
+
+ private val mockFlags = mock<DisplayManagerFlags>()
+ private val mockConfig = mock<DisplayDeviceConfig>()
+
+ @Test
+ fun `test app supported modes`(@TestParameter testCase: AppSupportedModesTestCase) {
+ whenever(mockFlags.isSynthetic60HzModesEnabled).thenReturn(testCase.syntheticModesEnabled)
+ whenever(mockConfig.isVrrSupportEnabled).thenReturn(testCase.vrrSupported)
+ val syntheticModeManager = SyntheticModeManager(mockFlags)
+
+ val result = syntheticModeManager.createAppSupportedModes(
+ mockConfig, testCase.supportedModes)
+
+ assertThat(result).isEqualTo(testCase.expectedAppModes)
+ }
+
+ enum class AppSupportedModesTestCase(
+ val syntheticModesEnabled: Boolean,
+ val vrrSupported: Boolean,
+ val supportedModes: Array<Mode>,
+ val expectedAppModes: Array<Mode>
+ ) {
+ SYNTHETIC_MODES_NOT_SUPPORTED(false, true, DISPLAY_MODES, DISPLAY_MODES),
+ VRR_NOT_SUPPORTED(true, false, DISPLAY_MODES, DISPLAY_MODES),
+ VRR_SYNTHETIC_NOT_SUPPORTED(false, false, DISPLAY_MODES, DISPLAY_MODES),
+ SINGLE_RESOLUTION_MODES(true, true, DISPLAY_MODES, arrayOf(
+ Mode(2, 100, 100, 120f),
+ Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf())
+ )),
+ NO_60HZ_MODES(true, true, arrayOf(Mode(2, 100, 100, 120f)),
+ arrayOf(
+ Mode(2, 100, 100, 120f),
+ Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf())
+ )
+ ),
+ MULTI_RESOLUTION_MODES(true, true,
+ arrayOf(
+ Mode(1, 100, 100, 120f),
+ Mode(2, 200, 200, 60f),
+ Mode(3, 300, 300, 60f),
+ Mode(4, 300, 300, 90f),
+ ),
+ arrayOf(
+ Mode(1, 100, 100, 120f),
+ Mode(4, 300, 300, 90f),
+ Mode(5, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf()),
+ Mode(6, 200, 200, 60f, 60f, true, floatArrayOf(), intArrayOf()),
+ Mode(7, 300, 300, 60f, 60f, true, floatArrayOf(), intArrayOf())
+ )
+ ),
+ WITH_HDR_TYPES(true, true,
+ arrayOf(
+ Mode(1, 100, 100, 120f, 120f, false, floatArrayOf(), intArrayOf(1, 2)),
+ Mode(2, 200, 200, 60f, 120f, false, floatArrayOf(), intArrayOf(3, 4)),
+ Mode(3, 200, 200, 120f, 120f, false, floatArrayOf(), intArrayOf(5, 6)),
+ ),
+ arrayOf(
+ Mode(1, 100, 100, 120f, 120f, false, floatArrayOf(), intArrayOf(1, 2)),
+ Mode(3, 200, 200, 120f, 120f, false, floatArrayOf(), intArrayOf(5, 6)),
+ Mode(4, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf(1, 2)),
+ Mode(5, 200, 200, 60f, 60f, true, floatArrayOf(), intArrayOf(5, 6)),
+ )
+ ),
+ UNACHIEVABLE_60HZ(true, true,
+ arrayOf(
+ Mode(1, 100, 100, 90f),
+ ),
+ arrayOf(
+ Mode(1, 100, 100, 90f),
+ )
+ ),
+ MULTI_RESOLUTION_MODES_WITH_UNACHIEVABLE_60HZ(true, true,
+ arrayOf(
+ Mode(1, 100, 100, 120f),
+ Mode(2, 200, 200, 90f),
+ ),
+ arrayOf(
+ Mode(1, 100, 100, 120f),
+ Mode(2, 200, 200, 90f),
+ Mode(3, 100, 100, 60f, 60f, true, floatArrayOf(), intArrayOf()),
+ )
+ ),
+ LOWER_THAN_60HZ_MODES(true, true,
+ arrayOf(
+ Mode(1, 100, 100, 30f),
+ Mode(2, 100, 100, 45f),
+ Mode(3, 100, 100, 90f),
+ ),
+ arrayOf(
+ Mode(3, 100, 100, 90f),
+ )
+ ),
+ }
+}
\ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
index 04b35f1..5da1bb6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
@@ -154,7 +154,7 @@
}
}
private fun createMode(modeId: Int, refreshRate: Float, vsyncRate: Float): Display.Mode {
- return Display.Mode(modeId, 600, 800, refreshRate, vsyncRate,
+ return Display.Mode(modeId, 600, 800, refreshRate, vsyncRate, false,
FloatArray(0), IntArray(0))
}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
index 1322545..b98af6b 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamServiceTest.java
@@ -37,6 +37,7 @@
import android.service.dreams.Flags;
import android.service.dreams.IDreamOverlayCallback;
import android.testing.TestableLooper;
+import android.view.KeyEvent;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -181,4 +182,15 @@
environment.advance(TestDreamEnvironment.DREAM_STATE_WOKEN);
verify(environment.getDreamOverlayClient()).onWakeRequested();
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_DREAM_HANDLES_CONFIRM_KEYS)
+ public void testPartialKeyHandling() throws Exception {
+ TestDreamEnvironment environment = new TestDreamEnvironment.Builder(mTestableLooper)
+ .build();
+ environment.advance(TestDreamEnvironment.DREAM_STATE_STARTED);
+
+ // Ensure service does not crash from only receiving up event.
+ environment.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE));
+ }
}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
index ef85ba5..3d03bf2 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
@@ -46,6 +46,7 @@
import android.service.dreams.IDreamOverlayClient;
import android.service.dreams.IDreamService;
import android.testing.TestableLooper;
+import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowInsetsController;
@@ -390,6 +391,13 @@
}
}
+ /**
+ * Sends a key event to the dream.
+ */
+ public void dispatchKeyEvent(KeyEvent event) {
+ mService.dispatchKeyEvent(event);
+ }
+
private void wakeDream() throws RemoteException {
mService.wakeUp();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index c359412..cb15d6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -3094,13 +3094,14 @@
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
any(), any(Handler.class), isNull(), bundleCaptor.capture());
+ Bundle bundle = bundleCaptor.getValue();
if (idleOptions != null) {
- assertEquals(idleOptions, bundleCaptor.getValue());
+ assertEquals(idleOptions, bundle);
} else {
- assertFalse("BAL flag needs to be false in alarm manager",
- bundleCaptor.getValue().getBoolean(
- ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
- true));
+ ActivityOptions options = ActivityOptions.fromBundle(bundle);
+ assertEquals("BAL should not be allowed in alarm manager",
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED,
+ options.getPendingIntentBackgroundActivityStartMode());
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
index c1f4fee..e88e28b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
@@ -142,6 +142,7 @@
final String app1PackageName = "com.android.test.stub1";
final long appStartTimestampIntentStarted = 1000000;
final long appStartTimestampActivityLaunchFinished = 2000000;
+ final long appStartTimestampFirstFrameDrawn = 2500000;
final long appStartTimestampReportFullyDrawn = 3000000;
final long appStartTimestampService = 4000000;
final long appStartTimestampBroadcast = 5000000;
@@ -272,6 +273,8 @@
mAppStartInfoTracker.onActivityLaunchFinished(appStartTimestampIntentStarted, COMPONENT,
appStartTimestampActivityLaunchFinished, ApplicationStartInfo.LAUNCH_MODE_STANDARD);
+ mAppStartInfoTracker.addTimestampToStart(app1PackageName, app1Uid,
+ appStartTimestampFirstFrameDrawn, ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
list.clear();
mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
verifyInProgressRecordsSize(1);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
index 72c0a9e..2cbc226 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
@@ -1 +1,3 @@
include /services/core/java/com/android/server/am/OWNERS
+
+per-file ApplicationStartInfoTest.java = yforta@google.com, carmenjackson@google.com, jji@google.com
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
index 8e1e339..c77ab0f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
@@ -24,7 +24,6 @@
import android.content.ContentResolver;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.provider.DeviceConfig.Properties;
import android.text.TextUtils;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -43,7 +42,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
/**
* Test SettingsToPropertiesMapper.
@@ -63,7 +61,6 @@
private HashMap<String, String> mSystemSettingsMap;
private HashMap<String, String> mGlobalSettingsMap;
- private HashMap<String, String> mConfigSettingsMap;
@Before
public void setUp() throws Exception {
@@ -74,11 +71,9 @@
.spyStatic(SystemProperties.class)
.spyStatic(Settings.Global.class)
.spyStatic(SettingsToPropertiesMapper.class)
- .spyStatic(Settings.Config.class)
.startMocking();
mSystemSettingsMap = new HashMap<>();
mGlobalSettingsMap = new HashMap<>();
- mConfigSettingsMap = new HashMap<>();
// Mock SystemProperties setter and various getters
doAnswer((Answer<Void>) invocationOnMock -> {
@@ -106,21 +101,6 @@
}
).when(() -> Settings.Global.getString(any(), anyString()));
- // Mock Settings.Config getstrings method
- doAnswer((Answer<Map<String, String>>) invocationOnMock -> {
- String namespace = invocationOnMock.getArgument(0);
- List<String> flags = invocationOnMock.getArgument(1);
- HashMap<String, String> values = new HashMap<>();
- for (String flag : flags) {
- String value = mConfigSettingsMap.get(namespace + "/" + flag);
- if (value != null) {
- values.put(flag, value);
- }
- }
- return values;
- }
- ).when(() -> Settings.Config.getStrings(anyString(), any()));
-
mTestMapper = new SettingsToPropertiesMapper(
mMockContentResolver, TEST_MAPPING, new String[] {}, new String[] {});
}
@@ -259,39 +239,4 @@
Assert.assertTrue(categories.contains("category2"));
Assert.assertTrue(categories.contains("category3"));
}
-
- @Test
- public void testGetStagedFlagsWithValueChange() {
- // mock up what is in the setting already
- mConfigSettingsMap.put("namespace_1/flag_1", "true");
- mConfigSettingsMap.put("namespace_1/flag_2", "true");
-
- // mock up input
- String namespace = "staged";
- Map<String, String> keyValueMap = new HashMap<>();
- // case 1: existing prop, stage the same value
- keyValueMap.put("namespace_1*flag_1", "true");
- // case 2: existing prop, stage a different value
- keyValueMap.put("namespace_1*flag_2", "false");
- // case 3: new prop
- keyValueMap.put("namespace_2*flag_1", "true");
- Properties props = new Properties(namespace, keyValueMap);
-
- HashMap<String, HashMap<String, String>> toStageProps =
- SettingsToPropertiesMapper.getStagedFlagsWithValueChange(props);
-
- HashMap<String, String> namespace_1_to_stage = toStageProps.get("namespace_1");
- HashMap<String, String> namespace_2_to_stage = toStageProps.get("namespace_2");
- Assert.assertTrue(namespace_1_to_stage != null);
- Assert.assertTrue(namespace_2_to_stage != null);
-
- String namespace_1_flag_1 = namespace_1_to_stage.get("flag_1");
- String namespace_1_flag_2 = namespace_1_to_stage.get("flag_2");
- String namespace_2_flag_1 = namespace_2_to_stage.get("flag_1");
- Assert.assertTrue(namespace_1_flag_1 == null);
- Assert.assertTrue(namespace_1_flag_2 != null);
- Assert.assertTrue(namespace_2_flag_1 != null);
- Assert.assertTrue(namespace_1_flag_2.equals("false"));
- Assert.assertTrue(namespace_2_flag_1.equals("true"));
- }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
index 29f3720..1b0a8d2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperCropperTest.java
@@ -210,12 +210,10 @@
new Rect(0, 0, bitmapSize.x, bitmapSize.y),
new Rect(100, 200, bitmapSize.x - 100, bitmapSize.y))) {
for (int mode: ALL_MODES) {
- for (boolean rtl: List.of(true, false)) {
- for (boolean parallax: List.of(true, false)) {
- assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, parallax, rtl, mode))
- .isEqualTo(crop);
- }
+ for (boolean parallax: List.of(true, false)) {
+ assertThat(WallpaperCropper.getAdjustedCrop(
+ crop, bitmapSize, displaySize, parallax, mode))
+ .isEqualTo(crop);
}
}
}
@@ -235,11 +233,9 @@
int expectedWidth = (int) (displaySize.x * (1 + WallpaperCropper.MAX_PARALLAX));
Point expectedCropSize = new Point(expectedWidth, 1000);
for (int mode: ALL_MODES) {
- for (boolean rtl: List.of(false, true)) {
- assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, true, rtl, mode))
- .isEqualTo(centerOf(crop, expectedCropSize));
- }
+ assertThat(WallpaperCropper.getAdjustedCrop(
+ crop, bitmapSize, displaySize, true, mode))
+ .isEqualTo(centerOf(crop, expectedCropSize));
}
}
@@ -258,11 +254,9 @@
Point bitmapSize = new Point(acceptableWidth, 1000);
Rect crop = new Rect(0, 0, bitmapSize.x, bitmapSize.y);
for (int mode : ALL_MODES) {
- for (boolean rtl : List.of(false, true)) {
- assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, true, rtl, mode))
- .isEqualTo(crop);
- }
+ assertThat(WallpaperCropper.getAdjustedCrop(
+ crop, bitmapSize, displaySize, true, mode))
+ .isEqualTo(crop);
}
}
}
@@ -292,11 +286,9 @@
for (int i = 0; i < crops.size(); i++) {
Rect crop = crops.get(i);
Rect expectedCrop = expectedAdjustedCrops.get(i);
- for (boolean rtl: List.of(false, true)) {
- assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, false, rtl, WallpaperCropper.ADD))
- .isEqualTo(expectedCrop);
- }
+ assertThat(WallpaperCropper.getAdjustedCrop(
+ crop, bitmapSize, displaySize, false, WallpaperCropper.ADD))
+ .isEqualTo(expectedCrop);
}
}
@@ -317,11 +309,9 @@
Point expectedCropSize = new Point(1000, 1000);
for (Rect crop: crops) {
- for (boolean rtl : List.of(false, true)) {
- assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, false, rtl, WallpaperCropper.REMOVE))
- .isEqualTo(centerOf(crop, expectedCropSize));
- }
+ assertThat(WallpaperCropper.getAdjustedCrop(
+ crop, bitmapSize, displaySize, false, WallpaperCropper.REMOVE))
+ .isEqualTo(centerOf(crop, expectedCropSize));
}
}
@@ -348,14 +338,14 @@
Rect crop = crops.get(i);
Rect expected = expectedAdjustedCrops.get(i);
assertThat(WallpaperCropper.getAdjustedCrop(
- crop, bitmapSize, displaySize, false, false, WallpaperCropper.BALANCE))
+ crop, bitmapSize, displaySize, false, WallpaperCropper.BALANCE))
.isEqualTo(expected);
Rect transposedCrop = new Rect(crop.top, crop.left, crop.bottom, crop.right);
Rect expectedTransposed = new Rect(
expected.top, expected.left, expected.bottom, expected.right);
assertThat(WallpaperCropper.getAdjustedCrop(transposedCrop, bitmapSize,
- transposedDisplaySize, false, false, WallpaperCropper.BALANCE))
+ transposedDisplaySize, false, WallpaperCropper.BALANCE))
.isEqualTo(expectedTransposed);
}
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index a9ff3a1..4460c6a 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -22,10 +22,12 @@
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 static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -52,6 +54,7 @@
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
+import com.android.server.power.feature.PowerManagerFlags;
import com.android.server.statusbar.StatusBarManagerInternal;
import org.junit.Before;
@@ -77,6 +80,9 @@
@Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
@Mock private Vibrator mVibrator;
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+ @Mock private WakeLockLog mWakeLockLog;
+
+ @Mock private PowerManagerFlags mPowerManagerFlags;
private PowerManagerService mService;
private Context mContextSpy;
@@ -222,6 +228,7 @@
@Test
public void testOnWakeLockListener_RemoteException_NoRethrow() {
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
createNotifier();
IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
@@ -235,6 +242,9 @@
mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
exceptingCallback);
+ verifyZeroInteractions(mWakeLockLog);
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
exceptingCallback);
@@ -244,8 +254,27 @@
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* newWorkSource= */ null, /* newHistoryTag= */ null,
exceptingCallback);
+ verifyNoMoreInteractions(mWakeLockLog);
mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.PARTIAL_WAKE_LOCK, 1);
// If we didn't throw, we're good!
+
+ // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same
+ // thread
+ clearInvocations(mWakeLockLog);
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false);
+
+ mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.PARTIAL_WAKE_LOCK, -1);
+
+ mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@@ -253,7 +282,7 @@
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
- Executor backgroundExecutor) {
+ Executor backgroundExecutor, PowerManagerFlags powerManagerFlags) {
return mNotifierMock;
}
@@ -326,6 +355,18 @@
}
private void createNotifier() {
+ Notifier.Injector injector = new Notifier.Injector() {
+ @Override
+ public long currentTimeMillis() {
+ return 1;
+ }
+
+ @Override
+ public WakeLockLog getWakeLockLog(Context context) {
+ return mWakeLockLog;
+ }
+ };
+
mNotifier = new Notifier(
mTestLooper.getLooper(),
mContextSpy,
@@ -335,7 +376,7 @@
null,
null,
null,
- mTestExecutor);
+ mTestExecutor, mPowerManagerFlags, injector);
}
private static class FakeExecutor implements Executor {
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 7f165e0..b737e0f 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -114,6 +114,7 @@
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
+import com.android.server.power.feature.PowerManagerFlags;
import com.android.server.testutils.OffsettableClock;
import com.google.testing.junit.testparameterinjector.TestParameter;
@@ -275,7 +276,7 @@
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
- Executor executor) {
+ Executor executor, PowerManagerFlags powerManagerFlags) {
return mNotifierMock;
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
index 0fad25d..1c4db6a 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
@@ -57,19 +57,42 @@
}
@Test
+ public void testAddTwoItems_withNoEventTimeSupplied() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, -1);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 102,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, -1);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " 01-01 00:00:01.150 - 102 (some.package2) - ACQ TagFull "
+ + "(full,acq-causes-wake)\n"
+ + " -\n"
+ + " Events: 2, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 6\n",
+ dumpLog(log, false));
+ }
+
+ @Test
public void testAddTwoItems() {
final int tagDatabaseSize = 128;
final int logSize = 20;
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
log.onWakeLockAcquired("TagFull", 102,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -89,11 +112,9 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1350L);
- log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1350L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial (partial)\n"
@@ -111,11 +132,9 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
- log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1150L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - --- - ACQ UNKNOWN (partial)\n"
@@ -134,41 +153,33 @@
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
// Wake lock 1 acquired - log size = 3
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
// Wake lock 2 acquired - log size = 3 + 3 = 6
- when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
- log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1150L);
// Wake lock 3 acquired - log size = 6 + 3 = 9
- when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
- log.onWakeLockAcquired("TagThree", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagThree", 101, PowerManager.PARTIAL_WAKE_LOCK, 1151L);
// We need more space - wake lock 1 acquisition is removed from the log and saved in the
// list. Log size = 9 - 3 + 2 = 8
- when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
- log.onWakeLockReleased("TagThree", 101);
+ log.onWakeLockReleased("TagThree", 101, 1152L);
// We need more space - wake lock 2 acquisition is removed from the log and saved in the
// list. Log size = 8 - 3 + 2 = 7
- when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
- log.onWakeLockReleased("TagPartial", 101);
+ log.onWakeLockReleased("TagPartial", 101, 1153L);
// We need more space - wake lock 3 acquisition is removed from the log and saved in the
// list. Log size = 7 - 3 + 3 = 7
- when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
- log.onWakeLockAcquired("TagFour", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagFour", 101, PowerManager.PARTIAL_WAKE_LOCK, 1154L);
// We need more space - wake lock 3 release is removed from the log and wake lock 3
// acquisition is removed from the list. Log size = 7 - 2 + 3 = 8
- when(injectorSpy.currentTimeMillis()).thenReturn(1155L);
- log.onWakeLockAcquired("TagFive", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("TagFive", 101, PowerManager.PARTIAL_WAKE_LOCK, 1155L);
// We need more space - wake lock 1 release is removed from the log and wake lock 1
// acquisition is removed from the list. Log size = 8 - 2 + 2 = 8
- when(injectorSpy.currentTimeMillis()).thenReturn(1156L);
- log.onWakeLockReleased("TagFull", 102);
+ log.onWakeLockReleased("TagFull", 102, 1156L);
// Wake lock 2 acquisition is still printed because its release have not rolled off the log
// yet.
@@ -191,8 +202,8 @@
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
// Bad tag means it wont get written
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockAcquired(null /* tag */, 0 /* ownerUid */, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired(
+ null /* tag */, 0 /* ownerUid */, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
assertEquals("Wake Lock Log\n"
+ " -\n"
@@ -208,9 +219,8 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("*job*/com.one.two.3hree/.one..Last", 101,
- PowerManager.PARTIAL_WAKE_LOCK);
+ PowerManager.PARTIAL_WAKE_LOCK, 1000L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ "
@@ -228,10 +238,8 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
- when(injectorSpy.currentTimeMillis()).thenReturn(1001L);
- log.onWakeLockReleased("HowdyTag", 101);
+ log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
+ log.onWakeLockReleased("HowdyTag", 101, 1001L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
@@ -250,12 +258,10 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1100L);
- log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1100L);
// New element goes back in time...should not be written to log.
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
- log.onWakeLockReleased("HowdyTag", 101);
+ log.onWakeLockReleased("HowdyTag", 101, 1000L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.100 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
@@ -272,9 +278,8 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.SYSTEM_WAKELOCK);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.SYSTEM_WAKELOCK, 1000L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -293,9 +298,8 @@
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
when(mPackageManager.getPackagesForUid(101)).thenReturn(null);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 - ACQ TagPartial "
@@ -316,9 +320,8 @@
when(mPackageManager.getPackagesForUid(101)).thenReturn(
new String[]{ "some.package1", "some.package2", "some.package3" });
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1,...) - ACQ TagPartial "
@@ -336,17 +339,14 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
log.onWakeLockAcquired("TagFull", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
log.onWakeLockAcquired("TagFull2", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1151L);
assertEquals("Wake Lock Log\n"
+ " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -370,29 +370,23 @@
TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
- when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
log.onWakeLockAcquired("TagPartial", 101,
- PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
log.onWakeLockAcquired("TagFull", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
log.onWakeLockAcquired("TagFull2", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1151L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
log.onWakeLockAcquired("TagFull3", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1152L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
log.onWakeLockAcquired("TagFull4", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1153L);
- when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
log.onWakeLockAcquired("TagFull5", 101,
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1154L);
// The first 3 events have been removed from the log and they exist in the saved
// acquisitions list. They should also use the cache when fetching the package names.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java
new file mode 100644
index 0000000..02c7b74
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java
@@ -0,0 +1,315 @@
+/*
+ * 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.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.UidTraffic;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+import android.os.Handler;
+import android.os.Parcel;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.IndentingPrintWriter;
+import android.util.SparseLongArray;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.IntSupplier;
+
+public class BluetoothPowerStatsCollectorTest {
+ private static final int APP_UID1 = 42;
+ private static final int APP_UID2 = 24;
+ private static final int ISOLATED_UID = 99123;
+
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, 1000);
+
+ private MockBatteryStatsImpl mBatteryStats;
+
+ private final MockClock mClock = mStatsRule.getMockClock();
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
+ private final PowerStatsUidResolver mPowerStatsUidResolver = new PowerStatsUidResolver();
+
+ private BluetoothActivityEnergyInfo mBluetoothActivityEnergyInfo;
+ private final SparseLongArray mUidScanTimes = new SparseLongArray();
+
+ private final BluetoothPowerStatsCollector.BluetoothStatsRetriever mBluetoothStatsRetriever =
+ new BluetoothPowerStatsCollector.BluetoothStatsRetriever() {
+ @Override
+ public void retrieveBluetoothScanTimes(Callback callback) {
+ for (int i = 0; i < mUidScanTimes.size(); i++) {
+ callback.onBluetoothScanTime(mUidScanTimes.keyAt(i),
+ mUidScanTimes.valueAt(i));
+ }
+ }
+
+ @Override
+ public boolean requestControllerActivityEnergyInfo(Executor executor,
+ BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback) {
+ callback.onBluetoothActivityEnergyInfoAvailable(mBluetoothActivityEnergyInfo);
+ return true;
+ }
+ };
+
+ private final List<PowerStats> mRecordedPowerStats = new ArrayList<>();
+
+ private BluetoothPowerStatsCollector.Injector mInjector =
+ new BluetoothPowerStatsCollector.Injector() {
+ @Override
+ public Handler getHandler() {
+ return mStatsRule.getHandler();
+ }
+
+ @Override
+ public Clock getClock() {
+ return mStatsRule.getMockClock();
+ }
+
+ @Override
+ public PowerStatsUidResolver getUidResolver() {
+ return mPowerStatsUidResolver;
+ }
+
+ @Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() {
+ return mConsumedEnergyRetriever;
+ }
+
+ @Override
+ public IntSupplier getVoltageSupplier() {
+ return () -> 3500;
+ }
+
+ @Override
+ public BluetoothPowerStatsCollector.BluetoothStatsRetriever
+ getBluetoothStatsRetriever() {
+ return mBluetoothStatsRetriever;
+ }
+ };
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true);
+ mPowerStatsUidResolver.noteIsolatedUidAdded(ISOLATED_UID, APP_UID2);
+ mBatteryStats = mStatsRule.getBatteryStats();
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void triggering() throws Throwable {
+ PowerStatsCollector collector = mBatteryStats.getPowerStatsCollector(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
+ collector.addConsumer(mRecordedPowerStats::add);
+
+ mBatteryStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ true);
+
+ mBatteryStats.setDummyExternalStatsSync(new MockBatteryStatsImpl.DummyExternalStatsSync(){
+ @Override
+ public void scheduleSyncDueToProcessStateChange(int flags, long delayMillis) {
+ collector.schedule();
+ }
+ });
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 2000, 3000, 600);
+
+ // This should trigger a sample collection to establish a baseline
+ mBatteryStats.onSystemReady(mContext);
+
+ mStatsRule.waitForBackgroundThread();
+ assertThat(mRecordedPowerStats).hasSize(1);
+
+ mRecordedPowerStats.clear();
+ mStatsRule.setTime(70000, 70000);
+ mBatteryStats.noteUidProcessStateLocked(APP_UID1, ActivityManager.PROCESS_STATE_TOP,
+ mClock.realtime, mClock.uptime);
+ mStatsRule.waitForBackgroundThread();
+ assertThat(mRecordedPowerStats).hasSize(1);
+ }
+
+ @Test
+ public void collectStats() {
+ PowerStats powerStats = collectPowerStats();
+ assertThat(powerStats.durationMs).isEqualTo(7200);
+
+ BluetoothPowerStatsLayout layout = new BluetoothPowerStatsLayout(powerStats.descriptor);
+ assertThat(layout.getDeviceRxTime(powerStats.stats)).isEqualTo(6000);
+ assertThat(layout.getDeviceTxTime(powerStats.stats)).isEqualTo(1000);
+ assertThat(layout.getDeviceIdleTime(powerStats.stats)).isEqualTo(200);
+ assertThat(layout.getDeviceScanTime(powerStats.stats)).isEqualTo(800);
+ assertThat(layout.getConsumedEnergy(powerStats.stats, 0))
+ .isEqualTo((64321 - 10000) * 1000 / 3500);
+
+ assertThat(powerStats.uidStats.size()).isEqualTo(2);
+ long[] actual1 = powerStats.uidStats.get(APP_UID1);
+ assertThat(layout.getUidRxBytes(actual1)).isEqualTo(1000);
+ assertThat(layout.getUidTxBytes(actual1)).isEqualTo(2000);
+ assertThat(layout.getUidScanTime(actual1)).isEqualTo(100);
+
+ // Combines APP_UID2 and ISOLATED_UID
+ long[] actual2 = powerStats.uidStats.get(APP_UID2);
+ assertThat(layout.getUidRxBytes(actual2)).isEqualTo(8000);
+ assertThat(layout.getUidTxBytes(actual2)).isEqualTo(10000);
+ assertThat(layout.getUidScanTime(actual2)).isEqualTo(700);
+
+ assertThat(powerStats.uidStats.get(ISOLATED_UID)).isNull();
+ }
+
+ @Test
+ public void dump() throws Throwable {
+ PowerStats powerStats = collectPowerStats();
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(sw);
+ powerStats.dump(pw);
+ pw.flush();
+ String dump = sw.toString();
+ assertThat(dump).contains("duration=7200");
+ assertThat(dump).contains(
+ "rx: 6000 tx: 1000 idle: 200 scan: 800 energy: " + ((64321 - 10000) * 1000 / 3500));
+ assertThat(dump).contains("UID 24: rx-B: 8000 tx-B: 10000 scan: 700");
+ assertThat(dump).contains("UID 42: rx-B: 1000 tx-B: 2000 scan: 100");
+ }
+
+ private PowerStats collectPowerStats() {
+ BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+ collector.setEnabled(true);
+
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH))
+ .thenReturn(new int[]{777});
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 2000,
+ mockUidTraffic(APP_UID1, 100, 200),
+ mockUidTraffic(APP_UID2, 300, 400),
+ mockUidTraffic(ISOLATED_UID, 500, 600));
+
+ mUidScanTimes.put(APP_UID1, 100);
+
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(eq(new int[]{777})))
+ .thenReturn(new long[]{10000});
+
+ // Establish a baseline
+ collector.collectStats();
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1100, 6600, 1100, 2200,
+ mockUidTraffic(APP_UID1, 1100, 2200),
+ mockUidTraffic(APP_UID2, 3300, 4400),
+ mockUidTraffic(ISOLATED_UID, 5500, 6600));
+
+ mUidScanTimes.clear();
+ mUidScanTimes.put(APP_UID1, 200);
+ mUidScanTimes.put(APP_UID2, 300);
+ mUidScanTimes.put(ISOLATED_UID, 400);
+
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(eq(new int[]{777})))
+ .thenReturn(new long[]{64321});
+
+ mStatsRule.setTime(20000, 20000);
+ return collector.collectStats();
+ }
+
+ private BluetoothActivityEnergyInfo mockBluetoothActivityEnergyInfo(long timestamp,
+ long rxTimeMs, long txTimeMs, long idleTimeMs, UidTraffic... uidTraffic) {
+ if (RavenwoodRule.isOnRavenwood()) {
+ BluetoothActivityEnergyInfo info = mock(BluetoothActivityEnergyInfo.class);
+ when(info.getControllerRxTimeMillis()).thenReturn(rxTimeMs);
+ when(info.getControllerTxTimeMillis()).thenReturn(txTimeMs);
+ when(info.getControllerIdleTimeMillis()).thenReturn(idleTimeMs);
+ when(info.getUidTraffic()).thenReturn(List.of(uidTraffic));
+ return info;
+ } else {
+ final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+ btActivityEnergyInfoParcel.writeLong(timestamp);
+ btActivityEnergyInfoParcel.writeInt(
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE);
+ btActivityEnergyInfoParcel.writeLong(txTimeMs);
+ btActivityEnergyInfoParcel.writeLong(rxTimeMs);
+ btActivityEnergyInfoParcel.writeLong(idleTimeMs);
+ btActivityEnergyInfoParcel.writeLong(0L);
+ btActivityEnergyInfoParcel.writeTypedList(List.of(uidTraffic));
+ btActivityEnergyInfoParcel.setDataPosition(0);
+
+ BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+ .createFromParcel(btActivityEnergyInfoParcel);
+ btActivityEnergyInfoParcel.recycle();
+ return info;
+ }
+ }
+
+ private UidTraffic mockUidTraffic(int uid, long rxBytes, long txBytes) {
+ if (RavenwoodRule.isOnRavenwood()) {
+ UidTraffic traffic = mock(UidTraffic.class);
+ when(traffic.getUid()).thenReturn(uid);
+ when(traffic.getRxBytes()).thenReturn(rxBytes);
+ when(traffic.getTxBytes()).thenReturn(txBytes);
+ return traffic;
+ } else {
+ final Parcel uidTrafficParcel = Parcel.obtain();
+ uidTrafficParcel.writeInt(uid);
+ uidTrafficParcel.writeLong(rxBytes);
+ uidTrafficParcel.writeLong(txBytes);
+ uidTrafficParcel.setDataPosition(0);
+
+ UidTraffic traffic = UidTraffic.CREATOR.createFromParcel(uidTrafficParcel);
+ uidTrafficParcel.recycle();
+ return traffic;
+ }
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsProcessorTest.java
new file mode 100644
index 0000000..752bc27
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsProcessorTest.java
@@ -0,0 +1,540 @@
+/*
+ * 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.server.power.stats;
+
+import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.UidTraffic;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Process;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.SparseLongArray;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerProfile;
+import com.android.server.power.stats.BluetoothPowerStatsCollector.BluetoothStatsRetriever;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.IntSupplier;
+
+public class BluetoothPowerStatsProcessorTest {
+
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;
+ private static final int BLUETOOTH_ENERGY_CONSUMER_ID = 1;
+ private static final int VOLTAGE_MV = 3500;
+
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0)
+ .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0)
+ .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0)
+ .initMeasuredEnergyStatsLocked();
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
+ private final PowerStatsUidResolver mPowerStatsUidResolver = new PowerStatsUidResolver();
+
+ private BluetoothActivityEnergyInfo mBluetoothActivityEnergyInfo;
+ private final SparseLongArray mUidScanTimes = new SparseLongArray();
+
+ private final BluetoothPowerStatsCollector.BluetoothStatsRetriever mBluetoothStatsRetriever =
+ new BluetoothPowerStatsCollector.BluetoothStatsRetriever() {
+ @Override
+ public void retrieveBluetoothScanTimes(Callback callback) {
+ for (int i = 0; i < mUidScanTimes.size(); i++) {
+ callback.onBluetoothScanTime(mUidScanTimes.keyAt(i),
+ mUidScanTimes.valueAt(i));
+ }
+ }
+
+ @Override
+ public boolean requestControllerActivityEnergyInfo(Executor executor,
+ BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback) {
+ callback.onBluetoothActivityEnergyInfoAvailable(mBluetoothActivityEnergyInfo);
+ return true;
+ }
+ };
+
+ private final BluetoothPowerStatsCollector.Injector mInjector =
+ new BluetoothPowerStatsCollector.Injector() {
+ @Override
+ public Handler getHandler() {
+ return mStatsRule.getHandler();
+ }
+
+ @Override
+ public Clock getClock() {
+ return mStatsRule.getMockClock();
+ }
+
+ @Override
+ public PowerStatsUidResolver getUidResolver() {
+ return mPowerStatsUidResolver;
+ }
+
+ @Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() {
+ return mConsumedEnergyRetriever;
+ }
+
+ @Override
+ public IntSupplier getVoltageSupplier() {
+ return () -> VOLTAGE_MV;
+ }
+
+ @Override
+ public BluetoothStatsRetriever getBluetoothStatsRetriever() {
+ return mBluetoothStatsRetriever;
+ }
+ };
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true);
+ }
+
+ @Test
+ public void powerProfileModel_mostlyDataTransfer() {
+ // No power monitoring hardware
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH))
+ .thenReturn(new int[0]);
+
+ BluetoothPowerStatsProcessor processor =
+ new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile());
+
+ PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
+
+ BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+ collector.setEnabled(true);
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
+ mockUidTraffic(APP_UID1, 100, 200),
+ mockUidTraffic(APP_UID2, 300, 400));
+
+ mUidScanTimes.put(APP_UID1, 100);
+
+ // Establish a baseline
+ aggregatedStats.addPowerStats(collector.collectStats(), 0);
+
+ // Turn the screen off after 2.5 seconds
+ aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE,
+ 5000);
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1100, 6600, 1100, 2200,
+ mockUidTraffic(APP_UID1, 1100, 2200),
+ mockUidTraffic(APP_UID2, 3300, 4400));
+
+ mUidScanTimes.clear();
+ mUidScanTimes.put(APP_UID1, 200);
+ mUidScanTimes.put(APP_UID2, 300);
+
+ mStatsRule.setTime(10_000, 10_000);
+
+ aggregatedStats.addPowerStats(collector.collectStats(), 10_000);
+
+ processor.finish(aggregatedStats);
+
+ BluetoothPowerStatsLayout statsLayout =
+ new BluetoothPowerStatsLayout(aggregatedStats.getPowerStatsDescriptor());
+
+ // RX power = 'rx-duration * PowerProfile[bluetooth.controller.rx]`
+ // RX power = 6000 * 50 = 300000 mA-ms = 0.083333 mAh
+ // TX power = 'tx-duration * PowerProfile[bluetooth.controller.tx]`
+ // TX power = 1000 * 100 = 100000 mA-ms = 0.02777 mAh
+ // Idle power = 'idle-duration * PowerProfile[bluetooth.controller.idle]`
+ // Idle power = 2000 * 10 = 20000 mA-ms = 0.00555 mAh
+ // Total power = RX + TX + Idle = 0.116666
+ // Screen-on - 25%
+ // Screen-off - 75%
+ double expectedPower = 0.116666;
+ long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength];
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+
+ // UID1 =
+ // (1000 / 4000) * 0.083333 // rx
+ // + (2000 / 6000) * 0.027777 // tx
+ // = 0.030092 mAh
+ double expectedPower1 = 0.030092;
+ long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength];
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.5);
+
+ // UID2 =
+ // (3000 / 4000) * 0.083333 // rx
+ // + (4000 / 6000) * 0.027777 // tx
+ // = 0.08102 mAh
+ double expectedPower2 = 0.08102;
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.75);
+ }
+
+ @Test
+ public void powerProfileModel_mostlyScan() {
+ // No power monitoring hardware
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH))
+ .thenReturn(new int[0]);
+
+ BluetoothPowerStatsProcessor processor =
+ new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile());
+
+ PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
+
+ BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+ collector.setEnabled(true);
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
+ mockUidTraffic(APP_UID1, 100, 200),
+ mockUidTraffic(APP_UID2, 300, 400));
+
+ mUidScanTimes.put(APP_UID1, 100);
+
+ // Establish a baseline
+ aggregatedStats.addPowerStats(collector.collectStats(), 0);
+
+ aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE,
+ 5000);
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1100, 6600, 1100, 2200,
+ mockUidTraffic(APP_UID1, 1100, 2200),
+ mockUidTraffic(APP_UID2, 3300, 4400));
+
+ // Total scan time exceeding data transfer times
+ mUidScanTimes.clear();
+ mUidScanTimes.put(APP_UID1, 3100);
+ mUidScanTimes.put(APP_UID2, 5000);
+
+ mStatsRule.setTime(10_000, 10_000);
+
+ aggregatedStats.addPowerStats(collector.collectStats(), 10_000);
+
+ processor.finish(aggregatedStats);
+
+ BluetoothPowerStatsLayout statsLayout =
+ new BluetoothPowerStatsLayout(aggregatedStats.getPowerStatsDescriptor());
+
+ // RX power = 'rx-duration * PowerProfile[bluetooth.controller.rx]`
+ // RX power = 6000 * 50 = 300000 mA-ms = 0.083333 mAh
+ // TX power = 'tx-duration * PowerProfile[bluetooth.controller.tx]`
+ // TX power = 1000 * 100 = 100000 mA-ms = 0.02777 mAh
+ // Idle power = 'idle-duration * PowerProfile[bluetooth.controller.idle]`
+ // Idle power = 2000 * 10 = 20000 mA-ms = 0.00555 mAh
+ // Total power = RX + TX + Idle = 0.116666
+ double expectedPower = 0.116666;
+ long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength];
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+
+ // UID1 =
+ // (3000 / 8000) * 0.083333 // rx
+ // + (3000 / 8000) * 0.027777 // tx
+ // = 0.041666 mAh
+ double expectedPower1 = 0.041666;
+ long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength];
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.5);
+
+ // UID2 =
+ // (5000 / 8000) * 0.083333 // rx
+ // + (5000 / 8000) * 0.027777 // tx
+ // = 0.069443 mAh
+ double expectedPower2 = 0.069443;
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.75);
+ }
+
+ @Test
+ public void consumedEnergyModel() {
+ // No power monitoring hardware
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH))
+ .thenReturn(new int[]{BLUETOOTH_ENERGY_CONSUMER_ID});
+
+ BluetoothPowerStatsProcessor processor =
+ new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile());
+
+ PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
+
+ BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+ collector.setEnabled(true);
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
+ mockUidTraffic(APP_UID1, 100, 200),
+ mockUidTraffic(APP_UID2, 300, 400));
+
+ mUidScanTimes.put(APP_UID1, 100);
+
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(
+ new int[]{BLUETOOTH_ENERGY_CONSUMER_ID})).thenReturn(new long[]{0});
+
+ // Establish a baseline
+ aggregatedStats.addPowerStats(collector.collectStats(), 0);
+
+ // Turn the screen off after 2.5 seconds
+ aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE,
+ 5000);
+
+ mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1100, 6600, 1100, 2200,
+ mockUidTraffic(APP_UID1, 1100, 2200),
+ mockUidTraffic(APP_UID2, 3300, 4400));
+
+ mUidScanTimes.clear();
+ mUidScanTimes.put(APP_UID1, 200);
+ mUidScanTimes.put(APP_UID2, 300);
+
+ mStatsRule.setTime(10_000, 10_000);
+
+ // 10 mAh represented as microWattSeconds
+ long energyUws = 10 * 3600 * VOLTAGE_MV;
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(
+ new int[]{BLUETOOTH_ENERGY_CONSUMER_ID})).thenReturn(new long[]{energyUws});
+
+ aggregatedStats.addPowerStats(collector.collectStats(), 10_000);
+
+ processor.finish(aggregatedStats);
+
+ BluetoothPowerStatsLayout statsLayout =
+ new BluetoothPowerStatsLayout(aggregatedStats.getPowerStatsDescriptor());
+
+ // All estimates are computed as in the #powerProfileModel_mostlyDataTransfer test,
+ // except they are all scaled by the same ratio to ensure that the total estimated
+ // energy is equal to the measured energy
+ double expectedPower = 10;
+ long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength];
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.25);
+
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(expectedPower * 0.75);
+
+ // UID1
+ // 0.030092 // power profile model estimate
+ // 0.116666 // power profile model estimate for total power
+ // 10 // total consumed energy
+ // = 0.030092 * (10 / 0.116666) = 2.579365
+ double expectedPower1 = 2.579365;
+ long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength];
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 0.5);
+
+ // UID2 =
+ // 0.08102 // power profile model estimate
+ // 0.116666 // power profile model estimate for total power
+ // 10 // total consumed energy
+ // = 0.08102 * (10 / 0.116666) = 6.944444
+ double expectedPower2 = 6.944444;
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.25);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2 * 0.75);
+ }
+
+ private static PowerComponentAggregatedPowerStats createAggregatedPowerStats(
+ BluetoothPowerStatsProcessor processor) {
+ AggregatedPowerStatsConfig.PowerComponent config =
+ new AggregatedPowerStatsConfig.PowerComponent(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH)
+ .trackDeviceStates(STATE_POWER, STATE_SCREEN)
+ .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE)
+ .setProcessor(processor);
+
+ PowerComponentAggregatedPowerStats aggregatedStats =
+ new PowerComponentAggregatedPowerStats(
+ new AggregatedPowerStats(mock(AggregatedPowerStatsConfig.class)), config);
+
+ aggregatedStats.setState(STATE_POWER, POWER_STATE_OTHER, 0);
+ aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_ON, 0);
+ aggregatedStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
+ aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
+
+ return aggregatedStats;
+ }
+
+ private int[] states(int... states) {
+ return states;
+ }
+
+ private BluetoothActivityEnergyInfo mockBluetoothActivityEnergyInfo(long timestamp,
+ long rxTimeMs, long txTimeMs, long idleTimeMs, UidTraffic... uidTraffic) {
+ if (RavenwoodRule.isOnRavenwood()) {
+ BluetoothActivityEnergyInfo info = mock(BluetoothActivityEnergyInfo.class);
+ when(info.getControllerRxTimeMillis()).thenReturn(rxTimeMs);
+ when(info.getControllerTxTimeMillis()).thenReturn(txTimeMs);
+ when(info.getControllerIdleTimeMillis()).thenReturn(idleTimeMs);
+ when(info.getUidTraffic()).thenReturn(List.of(uidTraffic));
+ return info;
+ } else {
+ final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
+ btActivityEnergyInfoParcel.writeLong(timestamp);
+ btActivityEnergyInfoParcel.writeInt(
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE);
+ btActivityEnergyInfoParcel.writeLong(txTimeMs);
+ btActivityEnergyInfoParcel.writeLong(rxTimeMs);
+ btActivityEnergyInfoParcel.writeLong(idleTimeMs);
+ btActivityEnergyInfoParcel.writeLong(0L);
+ btActivityEnergyInfoParcel.writeTypedList(List.of(uidTraffic));
+ btActivityEnergyInfoParcel.setDataPosition(0);
+
+ BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
+ .createFromParcel(btActivityEnergyInfoParcel);
+ btActivityEnergyInfoParcel.recycle();
+ return info;
+ }
+ }
+
+ private UidTraffic mockUidTraffic(int uid, long rxBytes, long txBytes) {
+ if (RavenwoodRule.isOnRavenwood()) {
+ UidTraffic traffic = mock(UidTraffic.class);
+ when(traffic.getUid()).thenReturn(uid);
+ when(traffic.getRxBytes()).thenReturn(rxBytes);
+ when(traffic.getTxBytes()).thenReturn(txBytes);
+ return traffic;
+ } else {
+ final Parcel uidTrafficParcel = Parcel.obtain();
+ uidTrafficParcel.writeInt(uid);
+ uidTrafficParcel.writeLong(rxBytes);
+ uidTrafficParcel.writeLong(txBytes);
+ uidTrafficParcel.setDataPosition(0);
+
+ UidTraffic traffic = UidTraffic.CREATOR.createFromParcel(uidTrafficParcel);
+ uidTrafficParcel.recycle();
+ return traffic;
+ }
+ }
+}
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 ca15aa2..f971f0e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -914,6 +914,38 @@
}
@Test
+ public void onPackageChanged_disableComponent_updateInstalledServices() {
+ // Sets up two accessibility services as installed services
+ setupShortcutTargetServices();
+ assertThat(mA11yms.getCurrentUserState().mInstalledServices).hasSize(2);
+ AccessibilityServiceInfo installedService1 =
+ mA11yms.getCurrentUserState().mInstalledServices.getFirst();
+ ResolveInfo resolveInfo1 = installedService1.getResolveInfo();
+ AccessibilityServiceInfo installedService2 =
+ mA11yms.getCurrentUserState().mInstalledServices.getLast();
+
+ // Disables `installedService2`
+ when(mMockPackageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
+ .thenReturn(List.of(resolveInfo1));
+ when(mMockSecurityPolicy.canRegisterService(any())).thenReturn(true);
+ final Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
+ packageIntent.setData(
+ Uri.parse("package:" + installedService2.getResolveInfo().serviceInfo.packageName));
+ packageIntent.putExtra(Intent.EXTRA_UID, UserHandle.myUserId());
+ packageIntent.putExtra(Intent.EXTRA_USER_HANDLE, mA11yms.getCurrentUserIdLocked());
+ packageIntent.putExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
+ new String[]{
+ installedService2.getComponentName().flattenToString()});
+ mA11yms.getPackageMonitor().doHandlePackageEvent(packageIntent);
+
+ assertThat(mA11yms.getCurrentUserState().mInstalledServices).hasSize(1);
+ ComponentName installedService =
+ mA11yms.getCurrentUserState().mInstalledServices.getFirst().getComponentName();
+ assertThat(installedService)
+ .isEqualTo(installedService1.getComponentName());
+ }
+
+ @Test
public void testSwitchUserScanPackages_scansWithoutHoldingLock() {
setupAccessibilityServiceConnection(0);
final AtomicReference<Set<Boolean>> lockState = collectLockStateWhilePackageScanning();
@@ -1590,12 +1622,10 @@
userState.updateA11yQsTargetLocked(Set.of(daltonizerTile));
mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
- Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .putExtra(Intent.EXTRA_SETTING_NAME, Settings.Secure.ACCESSIBILITY_QS_TARGETS)
- .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, colorInversionTile);
- sendBroadcastToAccessibilityManagerService(intent);
- mTestableLooper.processAllMessages();
+ broadcastSettingRestored(
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+ /*previousValue=*/null,
+ /*newValue=*/colorInversionTile);
assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM).getA11yQsTargets())
.containsExactlyElementsIn(Set.of(daltonizerTile, colorInversionTile));
@@ -1613,12 +1643,10 @@
userState.updateA11yQsTargetLocked(Set.of(daltonizerTile));
mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
- Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .putExtra(Intent.EXTRA_SETTING_NAME, Settings.Secure.ACCESSIBILITY_QS_TARGETS)
- .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, colorInversionTile);
- sendBroadcastToAccessibilityManagerService(intent);
- mTestableLooper.processAllMessages();
+ broadcastSettingRestored(
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+ /*previousValue=*/null,
+ /*newValue=*/colorInversionTile);
assertThat(userState.getA11yQsTargets())
.containsExactlyElementsIn(Set.of(daltonizerTile));
@@ -1679,12 +1707,113 @@
assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
new Intent(),
- new String[]{ "FOO", "BAR"},
+ new String[]{"FOO", "BAR"},
UserHandle.USER_SYSTEM,
false
));
}
+ @Test
+ @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
+ public void restoreA11yShortcutTargetService_targetsMerged() {
+ final String servicePrevious = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+ final String otherPrevious = TARGET_MAGNIFICATION;
+ final String combinedPrevious = String.join(":", servicePrevious, otherPrevious);
+ final String serviceRestored = TARGET_STANDARD_A11Y_SERVICE.flattenToString();
+ final AccessibilityUserState userState = new AccessibilityUserState(
+ UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ setupShortcutTargetServices(userState);
+
+ broadcastSettingRestored(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ /*previousValue=*/combinedPrevious,
+ /*newValue=*/serviceRestored);
+
+ final Set<String> expected = Set.of(servicePrevious, otherPrevious, serviceRestored);
+ assertThat(readStringsFromSetting(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE))
+ .containsExactlyElementsIn(expected);
+ assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM)
+ .getShortcutTargetsLocked(UserShortcutType.HARDWARE))
+ .containsExactlyElementsIn(expected);
+ }
+
+ @Test
+ @EnableFlags({
+ android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
+ Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
+ public void restoreA11yShortcutTargetService_alreadyHadDefaultService_doesNotClear() {
+ final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE.flattenToString();
+ mTestableContext.getOrCreateTestableResources().addOverride(
+ R.string.config_defaultAccessibilityService, serviceDefault);
+ final AccessibilityUserState userState = new AccessibilityUserState(
+ UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ setupShortcutTargetServices(userState);
+
+ broadcastSettingRestored(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ /*previousValue=*/serviceDefault,
+ /*newValue=*/serviceDefault);
+
+ final Set<String> expected = Set.of(serviceDefault);
+ assertThat(readStringsFromSetting(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE))
+ .containsExactlyElementsIn(expected);
+ assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM)
+ .getShortcutTargetsLocked(UserShortcutType.HARDWARE))
+ .containsExactlyElementsIn(expected);
+ }
+
+ @Test
+ @EnableFlags({
+ android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
+ Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
+ public void restoreA11yShortcutTargetService_didNotHaveDefaultService_clearsDefaultService() {
+ final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE.flattenToString();
+ final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+ // Restored value from the broadcast contains both default and non-default service.
+ final String combinedRestored = String.join(":", serviceDefault, serviceRestored);
+ mTestableContext.getOrCreateTestableResources().addOverride(
+ R.string.config_defaultAccessibilityService, serviceDefault);
+ final AccessibilityUserState userState = new AccessibilityUserState(
+ UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ setupShortcutTargetServices(userState);
+
+ broadcastSettingRestored(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ /*previousValue=*/null,
+ /*newValue=*/combinedRestored);
+
+ // The default service is cleared from the final restored value.
+ final Set<String> expected = Set.of(serviceRestored);
+ assertThat(readStringsFromSetting(
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE))
+ .containsExactlyElementsIn(expected);
+ assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM)
+ .getShortcutTargetsLocked(UserShortcutType.HARDWARE))
+ .containsExactlyElementsIn(expected);
+ }
+
+ private Set<String> readStringsFromSetting(String setting) {
+ final Set<String> result = new ArraySet<>();
+ mA11yms.readColonDelimitedSettingToSet(
+ setting, UserHandle.USER_SYSTEM, str -> str, result);
+ return result;
+ }
+
+ private void broadcastSettingRestored(String setting, String previousValue, String newValue) {
+ Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .putExtra(Intent.EXTRA_SETTING_NAME, setting)
+ .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue)
+ .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, newValue);
+ sendBroadcastToAccessibilityManagerService(intent);
+ mTestableLooper.processAllMessages();
+ }
+
private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
ComponentName componentName) {
return mockAccessibilityServiceInfo(
@@ -1738,6 +1867,10 @@
}
private void setupShortcutTargetServices() {
+ setupShortcutTargetServices(mA11yms.getCurrentUserState());
+ }
+
+ private void setupShortcutTargetServices(AccessibilityUserState userState) {
AccessibilityServiceInfo alwaysOnServiceInfo = mockAccessibilityServiceInfo(
TARGET_ALWAYS_ON_A11Y_SERVICE,
/* isSystemApp= */ false,
@@ -1748,9 +1881,9 @@
TARGET_STANDARD_A11Y_SERVICE,
/* isSystemApp= */ false,
/* isAlwaysOnService= */ false);
- mA11yms.getCurrentUserState().mInstalledServices.addAll(
+ userState.mInstalledServices.addAll(
List.of(alwaysOnServiceInfo, standardServiceInfo));
- mA11yms.getCurrentUserState().updateTileServiceMapForAccessibilityServiceLocked();
+ userState.updateTileServiceMapForAccessibilityServiceLocked();
}
private void sendBroadcastToAccessibilityManagerService(Intent intent) {
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 9862663..1db97b9 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -186,7 +186,8 @@
new FileDescriptor(), /* screenshotFd= */ null,
BugreportParams.BUGREPORT_MODE_FULL,
/* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false);
+ /* isScreenshotRequested= */ false,
+ /* skipUserConsentUnused = */ false);
assertThat(mInjector.isBugreportStarted()).isTrue();
}
@@ -202,7 +203,8 @@
new FileDescriptor(), /* screenshotFd= */ null,
BugreportParams.BUGREPORT_MODE_FULL,
/* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false);
+ /* isScreenshotRequested= */ false,
+ /* skipUserConsentUnused = */ false);
assertThat(mInjector.isBugreportStarted()).isTrue();
}
@@ -216,7 +218,8 @@
new FileDescriptor(), /* screenshotFd= */ null,
BugreportParams.BUGREPORT_MODE_FULL,
/* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false));
+ /* isScreenshotRequested= */ false,
+ /* skipUserConsentUnused = */ false));
assertThat(thrown.getMessage()).contains("not an admin user");
}
@@ -232,7 +235,8 @@
new FileDescriptor(), /* screenshotFd= */ null,
BugreportParams.BUGREPORT_MODE_REMOTE,
/* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false));
+ /* isScreenshotRequested= */ false,
+ /* skipUserConsentUnused = */ false));
assertThat(thrown.getMessage()).contains("not affiliated to the device owner");
}
@@ -243,7 +247,7 @@
Listener listener = new Listener(latch);
mService.retrieveBugreport(Binder.getCallingUid(), mContext.getPackageName(),
mContext.getUserId(), new FileDescriptor(), mBugreportFile,
- /* keepOnRetrieval= */ false, listener);
+ /* keepOnRetrieval= */ false, /* skipUserConsent = */ false, listener);
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(listener.getErrorCode()).isEqualTo(
BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
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 d0acacc..32c429e 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
@@ -361,7 +361,8 @@
.createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
SessionTag.OTHER, new SessionConfig());
- // Set session to background and calling updateHintAllowed() would invoke pause();
+ // Set session to background and calling updateHintAllowedByProcState() would invoke
+ // pause();
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
@@ -374,7 +375,8 @@
assertFalse(service.mUidObserver.isUidForeground(a.mUid));
verify(mNativeWrapperMock, times(1)).halPauseHintSession(anyLong());
- // Set session to foreground and calling updateHintAllowed() would invoke resume();
+ // Set session to foreground and calling updateHintAllowedByProcState() would invoke
+ // resume();
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
@@ -561,10 +563,12 @@
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);
+ int threadCount = 2;
+
+ // session 1 has 2 non-isolated tids
long sessionPtr1 = 111;
+ CountDownLatch stopLatch1 = new CountDownLatch(1);
+ int[] tids1 = createThreads(threadCount, stopLatch1);
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(tids1),
eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class)))
.thenReturn(sessionPtr1);
@@ -573,19 +577,19 @@
SessionTag.OTHER, new SessionConfig());
assertNotNull(session1);
- // for test only to avoid conflicting with any real thread that exists on device
+ // session 2 has 2 non-isolated tids and 2 isolated tids
+ long sessionPtr2 = 222;
+ CountDownLatch stopLatch2 = new CountDownLatch(1);
+ // negative value used for test only to avoid conflicting with any real thread that exists
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;
+ int[] expectedTids2 = Arrays.copyOf(tids2, tids2.length + 1);
+ expectedTids2[tids2.length] = isoProc1;
when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
eq(tids2WithIsolated), eq(DEFAULT_TARGET_DURATION), anyInt(),
any(SessionConfig.class))).thenReturn(sessionPtr2);
@@ -594,7 +598,10 @@
DEFAULT_TARGET_DURATION, SessionTag.OTHER, new SessionConfig());
assertNotNull(session2);
- // trigger clean up through UID state change by making the process background
+ // trigger clean up through UID state change by making the process foreground->background
+ // this will remove the one unexpected isolated tid from session 2
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
service.mUidObserver.onUidStateChanged(UID,
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500) + TimeUnit.MILLISECONDS.toNanos(
@@ -614,17 +621,21 @@
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
+ // let all session 1 threads to exit and the cleanup should force pause the session 1
stopLatch1.countDown();
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
service.mUidObserver.onUidStateChanged(UID,
- ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+ 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());
- // all hints will have no effect as the session is force paused while proc in foreground
+ verifyAllHintsEnabled(session1, false);
+ verifyAllHintsEnabled(session2, false);
+ service.mUidObserver.onUidStateChanged(UID,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
+ LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
verifyAllHintsEnabled(session1, false);
verifyAllHintsEnabled(session2, true);
reset(mNativeWrapperMock);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 06726b0..55d93fb 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -144,7 +144,9 @@
assertEquals(aih.getAppStandbyReason(PACKAGE_4, USER_ID, 3000),
REASON_MAIN_FORCED_BY_USER);
- assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ if (!Flags.avoidIdleCheck()) {
+ assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ }
assertFalse(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_FREQUENT));
}
@@ -243,4 +245,4 @@
expectedExpiryTimeMs, actualExpiryTimeMs);
}
}
-}
\ No newline at end of file
+}
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 b0a3374..7031975 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2805,24 +2805,6 @@
}
@Test
- public void testTransferStartingWindowWhileCreating() {
- final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
- organizer.setRunnableWhenAddingSplashScreen(
- () -> {
- // Surprise, ...! Transfer window in the middle of the creation flow.
- activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1,
- true, true, false, true, false, false, false);
- });
- activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
- true, false, false, false);
- waitUntilHandlersIdle();
- assertNoStartingWindow(activity1);
- assertHasStartingWindow(activity2);
- }
-
- @Test
public void testTransferStartingWindowCanAnimate() {
registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1355092..89140a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -104,6 +104,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.provider.DeviceConfig;
import android.service.voice.IVoiceInteractionSession;
import android.util.Pair;
@@ -1034,6 +1035,7 @@
* is the only reason BAL is allowed.
*/
@Test
+ @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS)
public void testBackgroundActivityStartsAllowed_loggingOnlyPendingIntentAllowed() {
doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
MockitoSession mockingSession = mockitoSession()
@@ -1077,6 +1079,7 @@
* is not the primary reason to allow BAL (but the creator).
*/
@Test
+ @RequiresFlagsDisabled(com.android.window.flags.Flags.FLAG_BAL_IMPROVED_METRICS)
public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() {
doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
MockitoSession mockingSession = mockitoSession()
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java
new file mode 100644
index 0000000..23b1c4b
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java
@@ -0,0 +1,206 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_SAW_PERMISSION;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
+import static com.android.server.wm.BackgroundActivityStartControllerTests.setViaReflection;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityOptions;
+import android.app.BackgroundStartPrivileges;
+import android.content.Intent;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.am.PendingIntentRecord;
+import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+/**
+ * Tests for the {@link BackgroundActivityStartController} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:BackgroundActivityStartControllerLogTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class BackgroundActivityStartControllerLogTests {
+
+ private static final int SYSTEM_UID = 1000;
+ private static final int APP1_UID = 10000;
+ private static final int APP2_UID = 10001;
+ private static final int APP1_PID = 10002;
+ private static final int APP2_PID = 10003;
+
+ public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
+
+ @Mock
+ ActivityTaskSupervisor mSupervisor;
+ @Mock
+ ActivityTaskManagerService mService;
+ @Mock
+ PendingIntentRecord mPendingIntentRecord;
+ MirrorActiveUids mActiveUids = new MirrorActiveUids();
+ BackgroundActivityStartController mController;
+ BackgroundActivityStartController.BalState mState;
+
+ @Before
+ public void setup() {
+ setViaReflection(mService, "mActiveUids", mActiveUids);
+ mController = new BackgroundActivityStartController(mService,
+ mSupervisor);
+ }
+
+ @Test
+ public void intent_blocked_log() {
+ useIntent();
+ mState.setResultForCaller(BalVerdict.BLOCK);
+ mState.setResultForRealCaller(BalVerdict.BLOCK);
+ assertThat(mController.shouldLogStats(BalVerdict.BLOCK, mState)).isTrue();
+ }
+
+ @Test
+ public void intent_visible_noLog() {
+ useIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible");
+ mState.setResultForCaller(finalVerdict);
+ mState.setResultForRealCaller(BalVerdict.BLOCK);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void intent_saw_log() {
+ useIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ mState.setResultForCaller(finalVerdict);
+ mState.setResultForRealCaller(BalVerdict.BLOCK);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void pendingIntent_callerOnly_saw_log() {
+ usePendingIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ mState.setResultForCaller(finalVerdict);
+ mState.setResultForRealCaller(BalVerdict.BLOCK);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void pendingIntent_realCallerOnly_saw_log() {
+ usePendingIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW")
+ .setBasedOnRealCaller();
+ mState.setResultForCaller(BalVerdict.BLOCK);
+ mState.setResultForRealCaller(finalVerdict);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void intent_shouldLogIntentActivity() {
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ useIntent(APP1_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ useIntent(SYSTEM_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isTrue();
+ }
+
+ @Test
+ public void pendingIntent_shouldLogIntentActivityForCaller() {
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW");
+ usePendingIntent(APP1_UID, APP2_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ usePendingIntent(SYSTEM_UID, SYSTEM_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isTrue();
+ usePendingIntent(SYSTEM_UID, APP2_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isTrue();
+ usePendingIntent(APP1_UID, SYSTEM_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void pendingIntent_shouldLogIntentActivityForRealCaller() {
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false,
+ "SAW").setBasedOnRealCaller();
+ usePendingIntent(APP1_UID, APP2_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ usePendingIntent(SYSTEM_UID, SYSTEM_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isTrue();
+ usePendingIntent(SYSTEM_UID, APP2_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ usePendingIntent(APP1_UID, SYSTEM_UID);
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isTrue();
+ }
+
+ @Test
+ public void pendingIntent_realCallerOnly_visible_noLog() {
+ usePendingIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false,
+ "visible").setBasedOnRealCaller();
+ mState.setResultForCaller(BalVerdict.BLOCK);
+ mState.setResultForRealCaller(finalVerdict);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isFalse();
+ }
+
+ @Test
+ public void pendingIntent_callerOnly_visible_noLog() {
+ usePendingIntent();
+ BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible");
+ mState.setResultForCaller(finalVerdict);
+ mState.setResultForRealCaller(BalVerdict.BLOCK);
+ assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue();
+ assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse();
+ }
+
+ private void useIntent() {
+ useIntent(APP1_UID);
+ }
+
+ private void useIntent(int uid) {
+ mState = mController.new BalState(uid, APP1_PID,
+ "calling.package", uid, APP1_PID, null,
+ null, BackgroundStartPrivileges.NONE, null, new Intent(),
+ ActivityOptions.makeBasic());
+ }
+
+ private void usePendingIntent() {
+ usePendingIntent(APP1_UID, APP2_UID);
+ }
+
+ private void usePendingIntent(int callerUid, int realCallerUid) {
+ mState = mController.new BalState(callerUid, APP1_PID,
+ "calling.package", realCallerUid, APP2_PID, null,
+ mPendingIntentRecord, BackgroundStartPrivileges.NONE, null, new Intent(),
+ ActivityOptions.makeBasic());
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
index 39a2259..f110c69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java
@@ -213,7 +213,7 @@
BalVerdict.BLOCK);
}
- private void setViaReflection(Object o, String property, Object value) {
+ static final void setViaReflection(Object o, String property, Object value) {
try {
Field field = o.getClass().getDeclaredField(property);
field.setAccessible(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index a0461a6..7faf2aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -324,6 +324,44 @@
});
}
+ @Test
+ public void testPrivateInterceptGlobalDragDropGetsDragFlags() {
+ mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
+ mWindow.setViewVisibility(View.GONE);
+
+ // Necessary for now since DragState.sendDragStartedLocked() will recycle drag events
+ // immediately after dispatching, which is a problem when using mockito arguments captor
+ // because it returns and modifies the same drag event
+ TestIWindow iwindow = (TestIWindow) mWindow.mClient;
+ final ArrayList<DragEvent> dragEvents = new ArrayList<>();
+ iwindow.setDragEventJournal(dragEvents);
+
+ startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+ ClipData.newPlainText("label", "text"), () -> {
+ // Verify the start-drag event has the drag flags
+ final DragEvent dragEvent = dragEvents.get(0);
+ assertTrue(dragEvent.getAction() == ACTION_DRAG_STARTED);
+ assertTrue(dragEvent.getDragFlags() ==
+ (View.DRAG_FLAG_GLOBAL
+ | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG));
+
+ try {
+ mTarget.mDeferDragStateClosed = true;
+ mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0);
+ // // Verify the drop event does not have the drag flags
+ mTarget.handleMotionEvent(false, 0, 0);
+ final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1);
+ assertTrue(dropEvent.getDragFlags() ==
+ (View.DRAG_FLAG_GLOBAL
+ | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG));
+
+ mTarget.reportDropResult(iwindow, true);
+ } finally {
+ mTarget.mDeferDragStateClosed = false;
+ }
+ });
+ }
+
private DragEvent last(ArrayList<DragEvent> list) {
return list.get(list.size() - 1);
}
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 6b17de4..c7f5020 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -908,6 +908,24 @@
}
@Test
+ public void testOverrideOrientationIfNeeded_fullscreenOverride_cameraActivity_unchanged() {
+ doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled();
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabledAtBuildTime();
+
+ // Recreate DisplayContent with DisplayRotationCompatPolicy
+ mActivity = setUpActivityWithComponent();
+ mController = new LetterboxUiController(mWm, mActivity);
+ spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
+
+ doReturn(false).when(mDisplayContent.mDisplayRotationCompatPolicy)
+ .isCameraActive(mActivity, /* mustBeFullscreen= */ true);
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ }
+
+ @Test
public void testOverrideOrientationIfNeeded_respectOrientationRequestOverUserFullScreen() {
spyOn(mController);
doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index c9a83b0..7ebf9ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -109,6 +109,7 @@
defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(),
LOW_REFRESH_RATE),
};
+ mDisplayInfo.appsSupportedModes = mDisplayInfo.supportedModes;
mDisplayInfo.defaultModeId = HI_MODE_ID;
mPolicy = new RefreshRatePolicy(mWm, mDisplayInfo, mDenylist);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index a90a158..d57a7e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -961,6 +962,22 @@
assertEquals(appLeftTop, task.getDisplayContent().mFocusedApp);
}
+ @Test
+ public void testShouldBeVisible_invisibleForEmptyTaskFragment() {
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .build();
+
+ // Empty taskFragment should be invisible
+ assertFalse(taskFragment.shouldBeVisible(null));
+
+ // Should be invisible even if it is ACTIVITY_TYPE_HOME.
+ when(taskFragment.getActivityType()).thenReturn(ACTIVITY_TYPE_HOME);
+ assertFalse(taskFragment.shouldBeVisible(null));
+ }
+
private WindowState createAppWindow(ActivityRecord app, String name) {
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, app, name,
0 /* ownerId */, false /* ownerCanAddInternalSystemWindow */, new TestIWindow());
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 4fc222b..788b624 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -53,7 +53,7 @@
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl.Array activeControls) {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 5b1a18d..9b48cb9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -314,6 +314,18 @@
// Wallpaper is invisible because the lowest show-when-locked activity is opaque.
assertNull(wallpaperController.getWallpaperTarget());
+ // Only transient-launch transition will make notification shade as last resort target.
+ // This verifies that regular transition won't choose invisible keyguard as the target.
+ final WindowState keyguard = createWindow(null /* parent */,
+ WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE, "keyguard");
+ keyguard.mAttrs.flags |= FLAG_SHOW_WALLPAPER;
+ registerTestTransitionPlayer();
+ final Transition transition = wallpaperWindow.mTransitionController.createTransition(
+ WindowManager.TRANSIT_CHANGE);
+ transition.collect(keyguard);
+ wallpaperController.adjustWallpaperWindows();
+ assertNull(wallpaperController.getWallpaperTarget());
+
// A show-when-locked wallpaper is used for lockscreen. So the top wallpaper should
// be the one that is not show-when-locked.
final WindowState wallpaperWindow2 = createWallpaperWindow(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 6bd0874..e1357a9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1785,8 +1785,6 @@
static class TestStartingWindowOrganizer extends WindowOrganizerTests.StubOrganizer {
private final ActivityTaskManagerService mAtm;
private final WindowManagerService mWMService;
-
- private Runnable mRunnableWhenAddingSplashScreen;
private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>();
private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>();
@@ -1796,10 +1794,6 @@
mAtm.mTaskOrganizerController.registerTaskOrganizer(this);
}
- void setRunnableWhenAddingSplashScreen(Runnable r) {
- mRunnableWhenAddingSplashScreen = r;
- }
-
@Override
public void addStartingWindow(StartingWindowInfo info) {
synchronized (mWMService.mGlobalLock) {
@@ -1814,10 +1808,6 @@
mAppWindowMap.put(info.appToken, window);
mTaskAppMap.put(info.taskInfo.taskId, info.appToken);
}
- if (mRunnableWhenAddingSplashScreen != null) {
- mRunnableWhenAddingSplashScreen.run();
- mRunnableWhenAddingSplashScreen = null;
- }
}
@Override
public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 65de7e4..7d845a3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3372,4 +3372,13 @@
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
void unregisterForCommunicationAllowedStateChanged(int subId,
in ISatelliteCommunicationAllowedStateCallback callback);
+
+ /**
+ * This API can be used by only CTS to override the boolean configs used by the
+ * DatagramController module.
+ *
+ * @param enable Whether to enable boolean config.
+ * @return {@code true} if the boolean config is set successfully, {@code false} otherwise.
+ */
+ boolean setDatagramControllerBooleanConfig(boolean reset, int booleanType, boolean enable);
}
diff --git a/tests/BinderLeakTest/Android.bp b/tests/BinderLeakTest/Android.bp
index 78b0ede..3747d04 100644
--- a/tests/BinderLeakTest/Android.bp
+++ b/tests/BinderLeakTest/Android.bp
@@ -24,6 +24,9 @@
"androidx.test.rules",
"androidx.test.runner",
],
+ test_suites: [
+ "general-tests",
+ ],
}
// Built with target_sdk_version: current
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index b024471..3538949c 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -56,6 +56,10 @@
defaults: ["FlickerTestsDefault"],
manifest: "AndroidManifest.xml",
test_config_template: "AndroidTestTemplate.xml",
+ test_suites: [
+ "device-tests",
+ "device-platinum-tests",
+ ],
srcs: [":FlickerTestsIme1-src"],
static_libs: [
"FlickerTestsBase",
diff --git a/tests/FlickerTests/Rotation/Android.bp b/tests/FlickerTests/Rotation/Android.bp
index b3eb934..aceb8ba 100644
--- a/tests/FlickerTests/Rotation/Android.bp
+++ b/tests/FlickerTests/Rotation/Android.bp
@@ -29,6 +29,10 @@
defaults: ["FlickerTestsDefault"],
manifest: "AndroidManifest.xml",
test_config_template: "AndroidTestTemplate.xml",
+ test_suites: [
+ "device-tests",
+ "device-platinum-tests",
+ ],
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
data: ["trace_config/*"],
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
index 5f1bc87..87a0de6 100644
--- a/tests/Input/src/com/android/test/input/InputDeviceTest.java
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -61,6 +61,7 @@
assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size());
assertEquals(device.getHostUsiVersion(), outDevice.getHostUsiVersion());
assertEquals(device.getAssociatedDisplayId(), outDevice.getAssociatedDisplayId());
+ assertEquals(device.isEnabled(), outDevice.isEnabled());
KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap();
KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap();
@@ -100,7 +101,9 @@
.setKeyboardLanguageTag("en-US")
.setKeyboardLayoutType("qwerty")
.setUsiVersion(new HostUsiVersion(2, 0))
- .setShouldSmoothScroll(true);
+ .setShouldSmoothScroll(true)
+ .setAssociatedDisplayId(Display.DEFAULT_DISPLAY)
+ .setEnabled(false);
for (int i = 0; i < 30; i++) {
deviceBuilder.addMotionRange(
diff --git a/tools/hoststubgen/OWNERS b/tools/hoststubgen/OWNERS
index a8c5321..3d8888d 100644
--- a/tools/hoststubgen/OWNERS
+++ b/tools/hoststubgen/OWNERS
@@ -1,3 +1 @@
-omakoto@google.com
-jsharkey@google.com
-jaggies@google.com
+file:platform/frameworks/base:/ravenwood/OWNERS
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index b8d1800..3f2b13a 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -290,6 +290,16 @@
return Visibility.fromAccess(this.access)
}
+/** Return the [access] flags without the visibility */
+fun clearVisibility(access: Int): Int {
+ return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED or Opcodes.ACC_PRIVATE).inv()
+}
+
+/** Return the visibility part of the [access] flags */
+fun getVisibility(access: Int): Int {
+ return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED or Opcodes.ACC_PRIVATE)
+}
+
/*
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
index 6643492..c99ff0e 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
@@ -195,6 +195,8 @@
return null
}
+ var newAccess = access
+
// Maybe rename the method.
val newName: String
val renameTo = filter.getRenameTo(currentClassName, name, descriptor)
@@ -205,8 +207,9 @@
// (the one with the @substitute/replace annotation).
// `name` is the name of the method we're currently visiting, so it's usually a
// "...$ravewnwood" name.
- if (!checkSubstitutionMethodCompatibility(
- classes, currentClassName, newName, name, descriptor, options.errors)) {
+ newAccess = checkSubstitutionMethodCompatibility(
+ classes, currentClassName, newName, name, descriptor, options.errors)
+ if (newAccess == NOT_COMPATIBLE) {
return null
}
@@ -221,7 +224,7 @@
// But note, we only use it when calling the super's method,
// but not for visitMethodInner(), because when subclass wants to change access,
// it can do so inside visitMethodInner().
- val newAccess = updateAccessFlags(access, name, descriptor)
+ newAccess = updateAccessFlags(newAccess, name, descriptor)
val ret = visitMethodInner(access, newName, descriptor, signature, exceptions, policy,
renameTo != null,
@@ -303,4 +306,4 @@
return ret
}
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
index 9d66c32..dc4f26bd 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
@@ -17,12 +17,19 @@
import com.android.hoststubgen.HostStubGenErrors
import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.clearVisibility
import com.android.hoststubgen.asm.getVisibility
import com.android.hoststubgen.asm.isStatic
+const val NOT_COMPATIBLE: Int = -1
+
/**
* Make sure substitution from and to methods have matching definition.
- * (static-ness, visibility.)
+ * (static-ness, etc)
+ *
+ * If the methods are compatible, return the "merged" [access] of the new method.
+ *
+ * If they are not compatible, returns [NOT_COMPATIBLE]
*/
fun checkSubstitutionMethodCompatibility(
classes: ClassNodes,
@@ -31,33 +38,31 @@
toMethodName: String, // the one with either a "_host" or "$ravenwood" prefix. (typically)
descriptor: String,
errors: HostStubGenErrors,
-): Boolean {
+): Int {
val from = classes.findMethod(className, fromMethodName, descriptor)
if (from == null) {
errors.onErrorFound(
- "Substitution-from method not found: $className.$fromMethodName$descriptor")
- return false
+ "Substitution-from method not found: $className.$fromMethodName$descriptor"
+ )
+ return NOT_COMPATIBLE
}
val to = classes.findMethod(className, toMethodName, descriptor)
if (to == null) {
// This shouldn't happen, because the visitor visited this method...
errors.onErrorFound(
- "Substitution-to method not found: $className.$toMethodName$descriptor")
- return false
+ "Substitution-to method not found: $className.$toMethodName$descriptor"
+ )
+ return NOT_COMPATIBLE
}
if (from.isStatic() != to.isStatic()) {
errors.onErrorFound(
"Substitution method must have matching static-ness: " +
- "$className.$fromMethodName$descriptor")
- return false
- }
- if (from.getVisibility().ordinal > to.getVisibility().ordinal) {
- errors.onErrorFound(
- "Substitution method cannot have smaller visibility than original: " +
- "$className.$fromMethodName$descriptor")
- return false
+ "$className.$fromMethodName$descriptor"
+ )
+ return NOT_COMPATIBLE
}
- return true
+ // Return the substitution's access flag but with the original method's visibility.
+ return clearVisibility (to.access) or getVisibility(from.access)
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 931f0c5..dd63892 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -644,9 +644,9 @@
suffix="_host"
)
- public static int nativeAddThree_host(int);
+ private static int nativeAddThree_host(int);
descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
x: iload_0
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
index ab387e0..6d8a48a 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
@@ -73,7 +73,8 @@
@HostSideTestSubstitute(suffix = "_host")
public static native int nativeAddThree(int value);
- public static int nativeAddThree_host(int value) {
+ // This method is private, but at runtime, it'll inherit the visibility of the original method
+ private static int nativeAddThree_host(int value) {
return value + 3;
}
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
index 0ea90ed..75e2536 100644
--- a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
+++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt
@@ -71,7 +71,7 @@
addClass(cn)
}
- fun check(from: MethodNode?, to: MethodNode?, expected: Boolean) {
+ fun check(from: MethodNode?, to: MethodNode?, expected: Int) {
assertThat(checkSubstitutionMethodCompatibility(
classes,
cn.name,
@@ -82,21 +82,21 @@
)).isEqualTo(expected)
}
- check(staticPublic, staticPublic, true)
- check(staticPrivate, staticPrivate, true)
- check(nonStaticPublic, nonStaticPublic, true)
- check(nonStaticPProtected, nonStaticPProtected, true)
+ check(staticPublic, staticPublic, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC)
+ check(staticPrivate, staticPrivate, Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC)
+ check(nonStaticPublic, nonStaticPublic, Opcodes.ACC_PUBLIC)
+ check(nonStaticPProtected, nonStaticPProtected, 0)
- check(staticPublic, null, false)
- check(null, staticPublic, false)
+ check(staticPublic, null, NOT_COMPATIBLE)
+ check(null, staticPublic, NOT_COMPATIBLE)
- check(staticPublic, nonStaticPublic, false)
- check(nonStaticPublic, staticPublic, false)
+ check(staticPublic, nonStaticPublic, NOT_COMPATIBLE)
+ check(nonStaticPublic, staticPublic, NOT_COMPATIBLE)
- check(staticPublic, staticPrivate, false)
- check(staticPrivate, staticPublic, true)
+ check(staticPublic, staticPrivate, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC)
+ check(staticPrivate, staticPublic, Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC)
- check(nonStaticPublic, nonStaticPProtected, false)
- check(nonStaticPProtected, nonStaticPublic, true)
+ check(nonStaticPublic, nonStaticPProtected, Opcodes.ACC_PUBLIC)
+ check(nonStaticPProtected, nonStaticPublic, 0)
}
}
\ No newline at end of file