Merge "Fix injecting custom buffers into QSTileLogger" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 76377e7..3a772e1 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -34,6 +34,7 @@
":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
":com.android.hardware.input-aconfig-java{.generated_srcjars}",
+ ":com.android.input.flags-aconfig-java{.generated_srcjars}",
":com.android.text.flags-aconfig-java{.generated_srcjars}",
":telecom_flags_core_java_lib{.generated_srcjars}",
":telephony_flags_core_java_lib{.generated_srcjars}",
@@ -57,7 +58,10 @@
":android.service.autofill.flags-aconfig-java{.generated_srcjars}",
":com.android.net.flags-aconfig-java{.generated_srcjars}",
":device_policy_aconfig_flags_lib{.generated_srcjars}",
+ ":service-jobscheduler-deviceidle.flags-aconfig-java{.generated_srcjars}",
":surfaceflinger_flags_java_lib{.generated_srcjars}",
+ ":android.view.contentcapture.flags-aconfig-java{.generated_srcjars}",
+ ":android.hardware.usb.flags-aconfig-java{.generated_srcjars}",
]
filegroup {
@@ -129,6 +133,12 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+java_aconfig_library {
+ name: "com.android.input.flags-aconfig-java",
+ aconfig_declarations: "com.android.input.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Text
aconfig_declarations {
name: "com.android.text.flags-aconfig",
@@ -659,3 +669,29 @@
aconfig_declarations: "surfaceflinger_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// Content Capture
+aconfig_declarations {
+ name: "android.view.contentcapture.flags-aconfig",
+ package: "android.view.contentcapture.flags",
+ srcs: ["core/java/android/view/contentcapture/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.view.contentcapture.flags-aconfig-java",
+ aconfig_declarations: "android.view.contentcapture.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// USB
+aconfig_declarations {
+ name: "android.hardware.usb.flags-aconfig",
+ package: "android.hardware.usb.flags",
+ srcs: ["core/java/android/hardware/usb/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.hardware.usb.flags-aconfig-java",
+ aconfig_declarations: "android.hardware.usb.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Ravenwood.bp b/Ravenwood.bp
index da02298..1582266 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -13,7 +13,7 @@
// limitations under the License.
// We need this "trampoline" rule to force soong to give a host-side jar to
-// framework-minus-apex.ravenwood. Otherwise, soong would mix up the arch (?) and we'd get
+// framework-minus-apex.ravenwood-base. Otherwise, soong would mix up the arch (?) and we'd get
// a dex jar.
java_library {
name: "framework-minus-apex-for-hoststubgen",
@@ -26,7 +26,7 @@
}
// Generate the stub/impl from framework-all, with hidden APIs.
-java_genrule_host {
+java_genrule {
name: "framework-minus-apex.ravenwood-base",
tools: ["hoststubgen"],
cmd: "$(location hoststubgen) " +
@@ -57,7 +57,9 @@
}
// Extract the impl jar from "framework-minus-apex.ravenwood-base" for subsequent build rules.
-java_genrule_host {
+// Note this emits a "device side" output, so that ravenwood tests can (implicitly)
+// depend on it.
+java_genrule {
name: "framework-minus-apex.ravenwood",
defaults: ["hoststubgen-for-prototype-only-genrule"],
cmd: "cp $(in) $(out)",
@@ -68,3 +70,17 @@
"framework-minus-apex.ravenwood.jar",
],
}
+
+android_ravenwood_libgroup {
+ name: "ravenwood-runtime",
+ libs: [
+ "framework-minus-apex.ravenwood",
+ "hoststubgen-helper-runtime.ravenwood",
+ "hoststubgen-helper-framework-runtime.ravenwood",
+ ],
+}
+
+android_ravenwood_libgroup {
+ name: "ravenwood-utils",
+ libs: [],
+}
diff --git a/apex/jobscheduler/service/aconfig/Android.bp b/apex/jobscheduler/service/aconfig/Android.bp
index 24ecd3d..7d8a363 100644
--- a/apex/jobscheduler/service/aconfig/Android.bp
+++ b/apex/jobscheduler/service/aconfig/Android.bp
@@ -1,3 +1,19 @@
+// Device Idle
+aconfig_declarations {
+ name: "service-deviceidle.flags-aconfig",
+ package: "com.android.server.deviceidle",
+ srcs: [
+ "device_idle.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "service-jobscheduler-deviceidle.flags-aconfig-java",
+ aconfig_declarations: "service-deviceidle.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ visibility: ["//frameworks/base:__subpackages__"],
+}
+
// JobScheduler
aconfig_declarations {
name: "service-job.flags-aconfig",
@@ -15,6 +31,7 @@
}
service_jobscheduler_aconfig_srcjars = [
+ ":service-jobscheduler-deviceidle.flags-aconfig-java{.generated_srcjars}",
":service-jobscheduler-job.flags-aconfig-java{.generated_srcjars}",
]
diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig
new file mode 100644
index 0000000..fc24b30
--- /dev/null
+++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.deviceidle"
+
+flag {
+ name: "disable_wakelocks_in_light_idle"
+ namespace: "backstage_power"
+ description: "Disable wakelocks for background apps while Light Device Idle is active"
+ bug: "299329948"
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index 7dd3d13..c142482 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
@@ -82,6 +82,10 @@
* be a negative value if the device is not in state to be considered idle.
*/
private long mIdlenessCheckScheduledElapsed = -1;
+ /**
+ * Time (in the elapsed realtime timebase) when the device can be considered idle.
+ */
+ private long mIdleStartElapsed = Long.MAX_VALUE;
private IdlenessListener mIdleListener;
private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener =
@@ -191,11 +195,7 @@
}
mProjectionActive = projectionActive;
if (mProjectionActive) {
- cancelIdlenessCheck();
- if (mIdle) {
- mIdle = false;
- mIdleListener.reportNewIdleState(mIdle);
- }
+ exitIdle();
} else {
maybeScheduleIdlenessCheck("Projection ended");
}
@@ -209,6 +209,7 @@
pw.print(" mDockIdle: "); pw.println(mDockIdle);
pw.print(" mProjectionActive: "); pw.println(mProjectionActive);
pw.print(" mIdlenessCheckScheduledElapsed: "); pw.println(mIdlenessCheckScheduledElapsed);
+ pw.print(" mIdleStartElapsed: "); pw.println(mIdleStartElapsed);
}
@Override
@@ -270,11 +271,7 @@
if (DEBUG) {
Slog.v(TAG, "exiting idle");
}
- cancelIdlenessCheck();
- if (mIdle) {
- mIdle = false;
- mIdleListener.reportNewIdleState(mIdle);
- }
+ exitIdle();
break;
case Intent.ACTION_SCREEN_OFF:
case Intent.ACTION_DREAMING_STARTED:
@@ -302,6 +299,12 @@
}
private void maybeScheduleIdlenessCheck(String reason) {
+ if (mIdle) {
+ if (DEBUG) {
+ Slog.w(TAG, "Already idle. Redundant reason=" + reason);
+ }
+ return;
+ }
if ((!mScreenOn || mDockIdle) && !mProjectionActive) {
final long nowElapsed = sElapsedRealtimeClock.millis();
final long inactivityThresholdMs = mIsStablePower
@@ -319,19 +322,32 @@
mIdlenessCheckScheduledElapsed = nowElapsed;
}
final long when = mIdlenessCheckScheduledElapsed + inactivityThresholdMs;
+ if (when == mIdleStartElapsed) {
+ if (DEBUG) {
+ Slog.i(TAG, "No change to idle start time");
+ }
+ return;
+ }
+ mIdleStartElapsed = when;
if (DEBUG) {
Slog.v(TAG, "Scheduling idle : " + reason + " now:" + nowElapsed
- + " checkElapsed=" + mIdlenessCheckScheduledElapsed + " when=" + when);
+ + " checkElapsed=" + mIdlenessCheckScheduledElapsed
+ + " when=" + mIdleStartElapsed);
}
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- when, mIdleWindowSlop, "JS idleness",
+ mIdleStartElapsed, mIdleWindowSlop, "JS idleness",
AppSchedulingModuleThread.getExecutor(), mIdleAlarmListener);
}
}
- private void cancelIdlenessCheck() {
+ private void exitIdle() {
mAlarm.cancel(mIdleAlarmListener);
mIdlenessCheckScheduledElapsed = -1;
+ mIdleStartElapsed = Long.MAX_VALUE;
+ if (mIdle) {
+ mIdle = false;
+ mIdleListener.reportNewIdleState(false);
+ }
}
private void handleIdleTrigger() {
diff --git a/api/Android.bp b/api/Android.bp
index de4435e..4d56b37 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -334,6 +334,16 @@
visibility: ["//frameworks/base/api"],
}
+// We resolve dependencies on APIs in modules by depending on a prebuilt of the whole
+// platform (sdk_system_current_android). That prebuilt does not include module-lib APIs,
+// so use the prebuilt module-lib stubs for modules that export module-lib stubs that the
+// non-updatable part depends on.
+non_updatable_api_deps_on_modules = [
+ "sdk_module-lib_current_framework-tethering",
+ "sdk_module-lib_current_framework-connectivity-t",
+ "sdk_system_current_android",
+]
+
// Defaults with module APIs in the classpath (mostly from prebuilts).
// Suitable for compiling android-non-updatable.
stubs_defaults {
@@ -345,19 +355,7 @@
"packages/modules/Media/apex/aidl/stable",
],
},
- libs: [
- "art.module.public.api",
- "sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-t",
- "sdk_public_current_framework-bluetooth",
- // There are a few classes from modules used by the core that
- // need to be resolved by metalava. We use a prebuilt stub of the
- // full sdk to ensure we can resolve them. If a new class gets added,
- // the prebuilts/sdk/current needs to be updated.
- "sdk_system_current_android",
- // NOTE: The below can be removed once the prebuilt stub contains IKE.
- "sdk_system_current_android.net.ipsec.ike",
- ],
+ libs: non_updatable_api_deps_on_modules,
}
// Defaults for the java_sdk_libraries of unbundled jars from framework.
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 5688b96..f6f6929 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -351,17 +351,7 @@
"android-non-updatable_from_source_defaults",
],
srcs: [":module-lib-api-stubs-docs-non-updatable"],
- libs: [
- // We cannot depend on all-modules-module-lib-stubs, because the module-lib stubs
- // depend on this stub. We resolve dependencies on APIs in modules by depending
- // on a prebuilt of the whole platform (sdk_system_current_android).
- // That prebuilt does not include module-lib APIs, so use the prebuilt module-lib
- // stubs for modules that export module-lib stubs that the non-updatable part
- // depends on.
- "sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-t",
- "sdk_system_current_android",
- ],
+ libs: non_updatable_api_deps_on_modules,
dist: {
dir: "apistubs/android/module-lib",
},
diff --git a/cmds/gpu_counter_producer/main.cpp b/cmds/gpu_counter_producer/main.cpp
index 1054cba..4616638 100644
--- a/cmds/gpu_counter_producer/main.cpp
+++ b/cmds/gpu_counter_producer/main.cpp
@@ -133,6 +133,12 @@
daemon(0, 0);
}
+ if (getenv("LD_LIBRARY_PATH") == nullptr) {
+ setenv("LD_LIBRARY_PATH", "/vendor/lib64:/vendor/lib", 0 /*override*/);
+ LOG_INFO("execv with: LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
+ execvpe(pname, argv, environ);
+ }
+
if (!writeToPidFile()) {
LOG_ERR("Could not open %s", kPidFileName);
return 1;
diff --git a/core/api/current.txt b/core/api/current.txt
index e8a6ac9..87f5b3c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18634,7 +18634,7 @@
method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") @Nullable public javax.crypto.KeyAgreement getKeyAgreement();
method @Nullable public javax.crypto.Mac getMac();
- method @FlaggedApi("android.hardware.biometrics.get_op_id_crypto_object") public long getOpId();
+ method @FlaggedApi("android.hardware.biometrics.get_op_id_crypto_object") public long getOperationHandle();
method @Nullable public android.security.identity.PresentationSession getPresentationSession();
method @Nullable public java.security.Signature getSignature();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index dfce1b5..739fdc5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -133,6 +133,7 @@
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_METADATA = "android.permission.GET_APP_METADATA";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
+ field @FlaggedApi("android.app.get_binding_uid_importance") public static final String GET_BINDING_UID_IMPORTANCE = "android.permission.GET_BINDING_UID_IMPORTANCE";
field public static final String GET_HISTORICAL_APP_OPS_STATS = "android.permission.GET_HISTORICAL_APP_OPS_STATS";
field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
@@ -367,6 +368,7 @@
field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
+ field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -543,6 +545,7 @@
public class ActivityManager {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
+ method @FlaggedApi("android.app.get_binding_uid_importance") @RequiresPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE) public int getBindingUidImportance(int);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
method @FlaggedApi("android.app.app_start_info") @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
@@ -6186,8 +6189,13 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final int COMPLIANCE_WARNING_BC_1_2 = 3; // 0x3
field public static final int COMPLIANCE_WARNING_DEBUG_ACCESSORY = 2; // 0x2
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_ENUMERATION_FAIL = 7; // 0x7
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_FLAKY_CONNECTION = 8; // 0x8
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_INPUT_POWER_LIMITED = 5; // 0x5
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_MISSING_DATA_LINES = 6; // 0x6
field public static final int COMPLIANCE_WARNING_MISSING_RP = 4; // 0x4
field public static final int COMPLIANCE_WARNING_OTHER = 1; // 0x1
+ field @FlaggedApi("android.hardware.usb.flags.enable_usb_data_compliance_warning") public static final int COMPLIANCE_WARNING_UNRELIABLE_IO = 9; // 0x9
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
field public static final int DATA_ROLE_DEVICE = 2; // 0x2
field public static final int DATA_ROLE_HOST = 1; // 0x1
@@ -10514,6 +10522,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
method @Deprecated public boolean isMediaSharedWithParent();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
+ method @FlaggedApi("android.os.allow_private_profile") public boolean isPrivateProfile();
method public static boolean isRemoveResultSuccessful(int);
method public boolean isRestrictedProfile();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6643663..b2bfda1 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2375,6 +2375,7 @@
method public boolean isVisibleBackgroundUsersOnDefaultDisplaySupported();
method public boolean isVisibleBackgroundUsersSupported();
method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException;
+ field @FlaggedApi("android.os.allow_private_profile") public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
}
public final class VibrationAttributes implements android.os.Parcelable {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f68681b..8b4ebae 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -73,7 +73,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -4269,6 +4268,33 @@
}
/**
+ * Same as {@link #getUidImportance(int)}, but it only works on UIDs that currently
+ * have a service binding, or provider reference, to the calling UID, even if the target UID
+ * belong to another android user or profile.
+ *
+ * <p>This will return {@link RunningAppProcessInfo#IMPORTANCE_GONE} on all other UIDs,
+ * regardless of if they're valid or not.
+ *
+ * <p>Privileged system apps may prefer this API to {@link #getUidImportance(int)} to
+ * avoid requesting the permission {@link Manifest.permission#PACKAGE_USAGE_STATS}, which
+ * would allow access to APIs that return more senstive information.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_GET_BINDING_UID_IMPORTANCE)
+ @SystemApi
+ @RequiresPermission(Manifest.permission.GET_BINDING_UID_IMPORTANCE)
+ public @RunningAppProcessInfo.Importance int getBindingUidImportance(int uid) {
+ try {
+ int procState = getService().getBindingUidProcessState(uid,
+ mContext.getOpPackageName());
+ return RunningAppProcessInfo.procStateToImportanceForClient(procState, mContext);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback to get reports about changes to the importance of a uid. Use with
* {@link #addOnUidImportanceListener}.
* @hide
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dfb416a..3b6ea14 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,7 +56,7 @@
import android.app.backup.BackupAnnotations.OperationType;
import android.app.compat.CompatChanges;
import android.app.sdksandbox.sandboxactivity.ActivityContextInfo;
-import android.app.sdksandbox.sandboxactivity.SdkSandboxActivityAuthority;
+import android.app.sdksandbox.sandboxactivity.ActivityContextInfoProvider;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
import android.app.servertransaction.ActivityRelaunchItem;
@@ -2272,8 +2272,7 @@
case DUMP_HEAP: return "DUMP_HEAP";
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
- case UPDATE_PACKAGE_COMPATIBILITY_INFO:
- return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
@@ -3777,10 +3776,8 @@
r.activityInfo.targetActivity);
}
- boolean isSandboxActivityContext =
- sandboxActivitySdkBasedContext()
- && SdkSandboxActivityAuthority.isSdkSandboxActivity(
- mSystemContext, r.intent);
+ boolean isSandboxActivityContext = sandboxActivitySdkBasedContext()
+ && r.intent.isSandboxActivity(mSystemContext);
boolean isSandboxedSdkContextUsed = false;
ContextImpl activityBaseContext;
if (isSandboxActivityContext) {
@@ -4025,12 +4022,11 @@
*/
@Nullable
private ContextImpl createBaseContextForSandboxActivity(@NonNull ActivityClientRecord r) {
- SdkSandboxActivityAuthority sdkSandboxActivityAuthority =
- SdkSandboxActivityAuthority.getInstance();
+ ActivityContextInfoProvider contextInfoProvider = ActivityContextInfoProvider.getInstance();
ActivityContextInfo contextInfo;
try {
- contextInfo = sdkSandboxActivityAuthority.getActivityContextInfo(r.intent);
+ contextInfo = contextInfoProvider.getActivityContextInfo(r.intent);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Passed intent does not match an expected sandbox activity", e);
return null;
diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java
new file mode 100644
index 0000000..a998ff2
--- /dev/null
+++ b/core/java/android/app/AppCompatTaskInfo.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Stores App Compat information about a particular Task.
+ * @hide
+ */
+public class AppCompatTaskInfo implements Parcelable {
+
+ /**
+ * Camera compat control isn't shown because it's not requested by heuristics.
+ */
+ public static final int CAMERA_COMPAT_CONTROL_HIDDEN = 0;
+
+ /**
+ * Camera compat control is shown with the treatment suggested.
+ */
+ public static final int CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED = 1;
+
+ /**
+ * Camera compat control is shown to allow reverting the applied treatment.
+ */
+ public static final int CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED = 2;
+
+ /**
+ * Camera compat control is dismissed by user.
+ */
+ public static final int CAMERA_COMPAT_CONTROL_DISMISSED = 3;
+
+ /**
+ * Enum for the Camera app compat control states.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CAMERA_COMPAT_CONTROL_" }, value = {
+ CAMERA_COMPAT_CONTROL_HIDDEN,
+ CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED,
+ CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED,
+ CAMERA_COMPAT_CONTROL_DISMISSED,
+ })
+ public @interface CameraCompatControlState {};
+
+ /**
+ * State of the Camera app compat control which is used to correct stretched viewfinder
+ * in apps that don't handle all possible configurations and changes between them correctly.
+ */
+ @CameraCompatControlState
+ public int cameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
+
+ /**
+ * Whether the direct top activity is eligible for letterbox education.
+ */
+ public boolean topActivityEligibleForLetterboxEducation;
+
+ /**
+ * Whether the direct top activity is in size compat mode on foreground.
+ */
+ public boolean topActivityInSizeCompat;
+
+ /**
+ * Whether the double tap is enabled.
+ */
+ public boolean isLetterboxDoubleTapEnabled;
+
+ /**
+ * Whether the user aspect ratio settings button is enabled.
+ */
+ public boolean topActivityEligibleForUserAspectRatioButton;
+
+ /**
+ * Whether the user has forced the activity to be fullscreen through the user aspect ratio
+ * settings.
+ */
+ public boolean isUserFullscreenOverrideEnabled;
+
+ /**
+ * Hint about the letterbox state of the top activity.
+ */
+ public boolean topActivityBoundsLetterboxed;
+
+ /**
+ * Whether the update comes from a letterbox double-tap action from the user or not.
+ */
+ public boolean isFromLetterboxDoubleTap;
+
+ /**
+ * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
+ * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+ */
+ public int topActivityLetterboxVerticalPosition;
+
+ /**
+ * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
+ * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+ */
+ public int topActivityLetterboxHorizontalPosition;
+
+ /**
+ * If {@link isLetterboxDoubleTapEnabled} it contains the current width of the letterboxed
+ * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+ */
+ public int topActivityLetterboxWidth;
+
+ /**
+ * If {@link isLetterboxDoubleTapEnabled} it contains the current height of the letterboxed
+ * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+ */
+ public int topActivityLetterboxHeight;
+
+ private AppCompatTaskInfo() {
+ // Do nothing
+ }
+
+ @NonNull
+ static AppCompatTaskInfo create() {
+ return new AppCompatTaskInfo();
+ }
+
+ private AppCompatTaskInfo(Parcel source) {
+ readFromParcel(source);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<AppCompatTaskInfo> CREATOR =
+ new Creator<>() {
+ @Override
+ public AppCompatTaskInfo createFromParcel(Parcel in) {
+ return new AppCompatTaskInfo(in);
+ }
+
+ @Override
+ public AppCompatTaskInfo[] newArray(int size) {
+ return new AppCompatTaskInfo[size];
+ }
+ };
+
+ /**
+ * @return {@value true} if the task has camera compat controls.
+ */
+ public boolean hasCameraCompatControl() {
+ return cameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN
+ && cameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED;
+ }
+
+ /**
+ * @return {@value true} if the task has some compat ui.
+ */
+ public boolean hasCompatUI() {
+ return hasCameraCompatControl() || topActivityInSizeCompat
+ || topActivityEligibleForLetterboxEducation
+ || isLetterboxDoubleTapEnabled
+ || topActivityEligibleForUserAspectRatioButton;
+ }
+
+ /**
+ * @return {@value true} if top activity is pillarboxed.
+ */
+ public boolean isTopActivityPillarboxed() {
+ return topActivityLetterboxWidth < topActivityLetterboxHeight;
+ }
+
+ /**
+ * @return {@code true} if the app compat parameters that are important for task organizers
+ * are equal.
+ */
+ public boolean equalsForTaskOrganizer(@Nullable AppCompatTaskInfo that) {
+ if (that == null) {
+ return false;
+ }
+ return isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
+ && topActivityEligibleForUserAspectRatioButton
+ == that.topActivityEligibleForUserAspectRatioButton
+ && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
+ && topActivityLetterboxWidth == that.topActivityLetterboxWidth
+ && topActivityLetterboxHeight == that.topActivityLetterboxHeight
+ && topActivityLetterboxHorizontalPosition
+ == that.topActivityLetterboxHorizontalPosition
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
+ }
+
+ /**
+ * @return {@code true} if parameters that are important for size compat have changed.
+ */
+ public boolean equalsForCompatUi(@Nullable AppCompatTaskInfo that) {
+ if (that == null) {
+ return false;
+ }
+ return topActivityInSizeCompat == that.topActivityInSizeCompat
+ && isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
+ && topActivityEligibleForUserAspectRatioButton
+ == that.topActivityEligibleForUserAspectRatioButton
+ && topActivityEligibleForLetterboxEducation
+ == that.topActivityEligibleForLetterboxEducation
+ && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
+ && topActivityLetterboxHorizontalPosition
+ == that.topActivityLetterboxHorizontalPosition
+ && topActivityLetterboxWidth == that.topActivityLetterboxWidth
+ && topActivityLetterboxHeight == that.topActivityLetterboxHeight
+ && cameraCompatControlState == that.cameraCompatControlState
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
+ }
+
+ /**
+ * Reads the TaskInfo from a parcel.
+ */
+ void readFromParcel(Parcel source) {
+ topActivityInSizeCompat = source.readBoolean();
+ topActivityEligibleForLetterboxEducation = source.readBoolean();
+ cameraCompatControlState = source.readInt();
+ isLetterboxDoubleTapEnabled = source.readBoolean();
+ topActivityEligibleForUserAspectRatioButton = source.readBoolean();
+ topActivityBoundsLetterboxed = source.readBoolean();
+ isFromLetterboxDoubleTap = source.readBoolean();
+ topActivityLetterboxVerticalPosition = source.readInt();
+ topActivityLetterboxHorizontalPosition = source.readInt();
+ topActivityLetterboxWidth = source.readInt();
+ topActivityLetterboxHeight = source.readInt();
+ isUserFullscreenOverrideEnabled = source.readBoolean();
+ }
+
+ /**
+ * Writes the TaskInfo to a parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(topActivityInSizeCompat);
+ dest.writeBoolean(topActivityEligibleForLetterboxEducation);
+ dest.writeInt(cameraCompatControlState);
+ dest.writeBoolean(isLetterboxDoubleTapEnabled);
+ dest.writeBoolean(topActivityEligibleForUserAspectRatioButton);
+ dest.writeBoolean(topActivityBoundsLetterboxed);
+ dest.writeBoolean(isFromLetterboxDoubleTap);
+ dest.writeInt(topActivityLetterboxVerticalPosition);
+ dest.writeInt(topActivityLetterboxHorizontalPosition);
+ dest.writeInt(topActivityLetterboxWidth);
+ dest.writeInt(topActivityLetterboxHeight);
+ dest.writeBoolean(isUserFullscreenOverrideEnabled);
+ }
+
+ @Override
+ public String toString() {
+ return "AppCompatTaskInfo { topActivityInSizeCompat=" + topActivityInSizeCompat
+ + " topActivityEligibleForLetterboxEducation= "
+ + topActivityEligibleForLetterboxEducation
+ + " isLetterboxDoubleTapEnabled= " + isLetterboxDoubleTapEnabled
+ + " topActivityEligibleForUserAspectRatioButton= "
+ + topActivityEligibleForUserAspectRatioButton
+ + " topActivityBoundsLetterboxed= " + topActivityBoundsLetterboxed
+ + " isFromLetterboxDoubleTap= " + isFromLetterboxDoubleTap
+ + " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition
+ + " topActivityLetterboxHorizontalPosition= "
+ + topActivityLetterboxHorizontalPosition
+ + " topActivityLetterboxWidth=" + topActivityLetterboxWidth
+ + " topActivityLetterboxHeight=" + topActivityLetterboxHeight
+ + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled
+ + " cameraCompatControlState="
+ + cameraCompatControlStateToString(cameraCompatControlState)
+ + "}";
+ }
+
+ /** Human readable version of the camera control state. */
+ @NonNull
+ public static String cameraCompatControlStateToString(
+ @CameraCompatControlState int cameraCompatControlState) {
+ switch (cameraCompatControlState) {
+ case CAMERA_COMPAT_CONTROL_HIDDEN: return "hidden";
+ case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED: return "treatment-suggested";
+ case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED: return "treatment-applied";
+ case CAMERA_COMPAT_CONTROL_DISMISSED: return "dismissed";
+ default:
+ throw new AssertionError(
+ "Unexpected camera compat control state: " + cameraCompatControlState);
+ }
+ }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 520bf7d..260e985 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -949,4 +949,5 @@
* @param err The binder transaction error
*/
oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
+ int getBindingUidProcessState(int uid, in String callingPackage);
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 5f8b765..efd5a45 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -19,7 +19,6 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -37,8 +36,6 @@
import android.view.DisplayCutout;
import android.window.WindowContainerToken;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
@@ -224,83 +221,6 @@
public ActivityInfo topActivityInfo;
/**
- * Whether the direct top activity is in size compat mode on foreground.
- * @hide
- */
- public boolean topActivityInSizeCompat;
-
- /**
- * Whether the direct top activity is eligible for letterbox education.
- * @hide
- */
- public boolean topActivityEligibleForLetterboxEducation;
-
- /**
- * Whether the double tap is enabled
- * @hide
- */
- public boolean isLetterboxDoubleTapEnabled;
-
- /**
- * Whether the user aspect ratio settings button is enabled
- * @hide
- */
- public boolean topActivityEligibleForUserAspectRatioButton;
-
- /**
- * Whether the user has forced the activity to be fullscreen through the user aspect ratio
- * settings.
- * @hide
- */
- public boolean isUserFullscreenOverrideEnabled;
-
- /**
- * Whether the top activity fillsParent() is false
- * @hide
- */
- public boolean isTopActivityTransparent;
-
- /**
- * Hint about the letterbox state of the top activity.
- * @hide
- */
- public boolean topActivityBoundsLetterboxed;
-
- /**
- * Whether the update comes from a letterbox double-tap action from the user or not.
- * @hide
- */
- public boolean isFromLetterboxDoubleTap;
-
- /**
- * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
- * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
- * @hide
- */
- public int topActivityLetterboxVerticalPosition;
-
- /**
- * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
- * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
- * @hide
- */
- public int topActivityLetterboxHorizontalPosition;
-
- /**
- * If {@link isLetterboxDoubleTapEnabled} it contains the current width of the letterboxed
- * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise
- * @hide
- */
- public int topActivityLetterboxWidth;
-
- /**
- * If {@link isLetterboxDoubleTapEnabled} it contains the current height of the letterboxed
- * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise
- * @hide
- */
- public int topActivityLetterboxHeight;
-
- /**
* Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity
* supports), this is what the system actually uses for resizability based on other policy and
* developer options.
@@ -371,49 +291,16 @@
public boolean isSleeping;
/**
- * Camera compat control isn't shown because it's not requested by heuristics.
+ * Whether the top activity fillsParent() is false
* @hide
*/
- public static final int CAMERA_COMPAT_CONTROL_HIDDEN = 0;
+ public boolean isTopActivityTransparent;
/**
- * Camera compat control is shown with the treatment suggested.
+ * Encapsulate specific App Compat information.
* @hide
*/
- public static final int CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED = 1;
-
- /**
- * Camera compat control is shown to allow reverting the applied treatment.
- * @hide
- */
- public static final int CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED = 2;
-
- /**
- * Camera compat control is dismissed by user.
- * @hide
- */
- public static final int CAMERA_COMPAT_CONTROL_DISMISSED = 3;
-
- /**
- * Enum for the Camera app compat control states.
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "CAMERA_COMPAT_CONTROL_" }, value = {
- CAMERA_COMPAT_CONTROL_HIDDEN,
- CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED,
- CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED,
- CAMERA_COMPAT_CONTROL_DISMISSED,
- })
- public @interface CameraCompatControlState {};
-
- /**
- * State of the Camera app compat control which is used to correct stretched viewfinder
- * in apps that don't handle all possible configurations and changes between them correctly.
- * @hide
- */
- @CameraCompatControlState
- public int cameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
+ public AppCompatTaskInfo appCompatTaskInfo = AppCompatTaskInfo.create();
TaskInfo() {
// Do nothing
@@ -475,20 +362,6 @@
launchCookies.add(cookie);
}
- /** @hide */
- public boolean hasCameraCompatControl() {
- return cameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN
- && cameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED;
- }
-
- /** @hide */
- public boolean hasCompatUI() {
- return hasCameraCompatControl() || topActivityInSizeCompat
- || topActivityEligibleForLetterboxEducation
- || isLetterboxDoubleTapEnabled
- || topActivityEligibleForUserAspectRatioButton;
- }
-
/**
* @return {@code true} if this task contains the launch cookie.
* @hide
@@ -535,14 +408,6 @@
&& isResizeable == that.isResizeable
&& supportsMultiWindow == that.supportsMultiWindow
&& displayAreaFeatureId == that.displayAreaFeatureId
- && isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
- && topActivityEligibleForUserAspectRatioButton
- == that.topActivityEligibleForUserAspectRatioButton
- && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
- && topActivityLetterboxWidth == that.topActivityLetterboxWidth
- && topActivityLetterboxHeight == that.topActivityLetterboxHeight
- && topActivityLetterboxHorizontalPosition
- == that.topActivityLetterboxHorizontalPosition
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
&& Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
@@ -557,8 +422,8 @@
&& Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
&& parentTaskId == that.parentTaskId
&& Objects.equals(topActivity, that.topActivity)
- && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled
- && isTopActivityTransparent == that.isTopActivityTransparent;
+ && isTopActivityTransparent == that.isTopActivityTransparent
+ && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo);
}
/**
@@ -569,30 +434,19 @@
if (that == null) {
return false;
}
+ final boolean hasCompatUI = appCompatTaskInfo.hasCompatUI();
return displayId == that.displayId
&& taskId == that.taskId
- && topActivityInSizeCompat == that.topActivityInSizeCompat
- && isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
- && topActivityEligibleForUserAspectRatioButton
- == that.topActivityEligibleForUserAspectRatioButton
- && topActivityEligibleForLetterboxEducation
- == that.topActivityEligibleForLetterboxEducation
- && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
- && topActivityLetterboxHorizontalPosition
- == that.topActivityLetterboxHorizontalPosition
- && topActivityLetterboxWidth == that.topActivityLetterboxWidth
- && topActivityLetterboxHeight == that.topActivityLetterboxHeight
- && cameraCompatControlState == that.cameraCompatControlState
- // Bounds are important if top activity has compat controls.
- && (!hasCompatUI() || configuration.windowConfiguration.getBounds()
- .equals(that.configuration.windowConfiguration.getBounds()))
- && (!hasCompatUI() || configuration.getLayoutDirection()
- == that.configuration.getLayoutDirection())
- && (!hasCompatUI() || configuration.uiMode == that.configuration.uiMode)
- && (!hasCompatUI() || isVisible == that.isVisible)
&& isFocused == that.isFocused
- && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled
- && isTopActivityTransparent == that.isTopActivityTransparent;
+ && isTopActivityTransparent == that.isTopActivityTransparent
+ && appCompatTaskInfo.equalsForCompatUi(that.appCompatTaskInfo)
+ // Bounds are important if top activity has compat controls.
+ && (!hasCompatUI || configuration.windowConfiguration.getBounds()
+ .equals(that.configuration.windowConfiguration.getBounds()))
+ && (!hasCompatUI || configuration.getLayoutDirection()
+ == that.configuration.getLayoutDirection())
+ && (!hasCompatUI || configuration.uiMode == that.configuration.uiMode)
+ && (!hasCompatUI || isVisible == that.isVisible);
}
/**
@@ -635,21 +489,10 @@
isVisible = source.readBoolean();
isVisibleRequested = source.readBoolean();
isSleeping = source.readBoolean();
- topActivityInSizeCompat = source.readBoolean();
- topActivityEligibleForLetterboxEducation = source.readBoolean();
mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
displayAreaFeatureId = source.readInt();
- cameraCompatControlState = source.readInt();
- isLetterboxDoubleTapEnabled = source.readBoolean();
- topActivityEligibleForUserAspectRatioButton = source.readBoolean();
- topActivityBoundsLetterboxed = source.readBoolean();
- isFromLetterboxDoubleTap = source.readBoolean();
- topActivityLetterboxVerticalPosition = source.readInt();
- topActivityLetterboxHorizontalPosition = source.readInt();
- topActivityLetterboxWidth = source.readInt();
- topActivityLetterboxHeight = source.readInt();
- isUserFullscreenOverrideEnabled = source.readBoolean();
isTopActivityTransparent = source.readBoolean();
+ appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
}
/**
@@ -693,21 +536,10 @@
dest.writeBoolean(isVisible);
dest.writeBoolean(isVisibleRequested);
dest.writeBoolean(isSleeping);
- dest.writeBoolean(topActivityInSizeCompat);
- dest.writeBoolean(topActivityEligibleForLetterboxEducation);
dest.writeTypedObject(mTopActivityLocusId, flags);
dest.writeInt(displayAreaFeatureId);
- dest.writeInt(cameraCompatControlState);
- dest.writeBoolean(isLetterboxDoubleTapEnabled);
- dest.writeBoolean(topActivityEligibleForUserAspectRatioButton);
- dest.writeBoolean(topActivityBoundsLetterboxed);
- dest.writeBoolean(isFromLetterboxDoubleTap);
- dest.writeInt(topActivityLetterboxVerticalPosition);
- dest.writeInt(topActivityLetterboxHorizontalPosition);
- dest.writeInt(topActivityLetterboxWidth);
- dest.writeInt(topActivityLetterboxHeight);
- dest.writeBoolean(isUserFullscreenOverrideEnabled);
dest.writeBoolean(isTopActivityTransparent);
+ dest.writeTypedObject(appCompatTaskInfo, flags);
}
@Override
@@ -741,39 +573,10 @@
+ " isVisible=" + isVisible
+ " isVisibleRequested=" + isVisibleRequested
+ " isSleeping=" + isSleeping
- + " topActivityInSizeCompat=" + topActivityInSizeCompat
- + " topActivityEligibleForLetterboxEducation= "
- + topActivityEligibleForLetterboxEducation
- + " isLetterboxDoubleTapEnabled= " + isLetterboxDoubleTapEnabled
- + " topActivityEligibleForUserAspectRatioButton= "
- + topActivityEligibleForUserAspectRatioButton
- + " topActivityBoundsLetterboxed= " + topActivityBoundsLetterboxed
- + " isFromLetterboxDoubleTap= " + isFromLetterboxDoubleTap
- + " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition
- + " topActivityLetterboxHorizontalPosition= "
- + topActivityLetterboxHorizontalPosition
- + " topActivityLetterboxWidth=" + topActivityLetterboxWidth
- + " topActivityLetterboxHeight=" + topActivityLetterboxHeight
- + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled
- + " isTopActivityTransparent=" + isTopActivityTransparent
+ " locusId=" + mTopActivityLocusId
+ " displayAreaFeatureId=" + displayAreaFeatureId
- + " cameraCompatControlState="
- + cameraCompatControlStateToString(cameraCompatControlState)
+ + " isTopActivityTransparent=" + isTopActivityTransparent
+ + " appCompatTaskInfo=" + appCompatTaskInfo
+ "}";
}
-
- /** @hide */
- public static String cameraCompatControlStateToString(
- @CameraCompatControlState int cameraCompatControlState) {
- switch (cameraCompatControlState) {
- case CAMERA_COMPAT_CONTROL_HIDDEN: return "hidden";
- case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED: return "treatment-suggested";
- case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED: return "treatment-applied";
- case CAMERA_COMPAT_CONTROL_DISMISSED: return "dismissed";
- default:
- throw new AssertionError(
- "Unexpected camera compat control state: " + cameraCompatControlState);
- }
- }
}
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 2076e85..b303ea6 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -5,4 +5,11 @@
name: "app_start_info"
description: "Control collecting of ApplicationStartInfo records and APIs."
bug: "247814855"
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "backstage_power"
+ name: "get_binding_uid_importance"
+ description: "API to get importance of UID that's binding to the caller"
+ bug: "292533010"
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 70811bb..9ea3dfc 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -248,7 +248,7 @@
* The length limit of Association tag.
* @hide
*/
- private static final int ASSOCIATION_TAG_LENGTH_LIMIT = 100;
+ private static final int ASSOCIATION_TAG_LENGTH_LIMIT = 1024;
/**
* Callback for applications to receive updates about and the outcome of
@@ -1427,7 +1427,7 @@
/**
* Sets the {@link AssociationInfo#getTag() tag} for this association.
*
- * <p>The length of the tag must be at most 100 characters to save disk space.
+ * <p>The length of the tag must be at most 1024 characters to save disk space.
*
* <p>This allows to store useful information about the associated devices.
*
@@ -1441,7 +1441,8 @@
Objects.requireNonNull(tag, "tag cannot be null");
if (tag.length() > ASSOCIATION_TAG_LENGTH_LIMIT) {
- throw new IllegalArgumentException("Length of the tag must be at most 100 characters");
+ throw new IllegalArgumentException("Length of the tag must be at most"
+ + ASSOCIATION_TAG_LENGTH_LIMIT + " characters");
}
try {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 02e0cf6..ea54c91 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12587,12 +12587,8 @@
return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT;
}
- /**
- * @deprecated Use {@link SdkSandboxActivityAuthority#isSdkSandboxActivity} instead.
- * Once the other API is finalized this method will be removed.
- * @hide
- */
- @Deprecated
+ // TODO(b/299109198): Refactor into the {@link SdkSandboxManagerLocal}
+ /** @hide */
public boolean isSandboxActivity(@NonNull Context context) {
if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) {
return true;
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 9b819a7..ec96215 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -13,3 +13,10 @@
description: "Enables Credential Manager to work with Instant Apps"
bug: "302190269"
}
+
+flag {
+ namespace: "credential_manager"
+ name: "clear_session_enabled"
+ description: "Enables clearing of Credential Manager sessions when client process dies"
+ bug: "308470501"
+}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 7b874cc..2081ced 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -47,6 +47,8 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Static utility methods for dealing with databases and {@link Cursor}s.
@@ -1585,6 +1587,38 @@
}
/**
+ * A regular expression that matches the first three characters in a SQL statement, after
+ * skipping past comments and whitespace. PREFIX_GROUP_NUM is the regex group that contains
+ * the matching prefix string. If PREFIX_REGEX is changed, PREFIX_GROUP_NUM may require an
+ * update too.
+ */
+ private static final String PREFIX_REGEX =
+ "(" // Zero-or more...
+ + "\\s+" // Leading space
+ + "|"
+ + "--.*?\n" // Line comment
+ + "|"
+ + "/\\*[\\w\\W]*?\\*/" // Block comment
+ + ")*"
+ + "(\\w\\w\\w)"; // Three word-characters
+ private static final int PREFIX_GROUP_NUM = 2;
+ private static final Pattern sPrefixPattern = Pattern.compile(PREFIX_REGEX);
+
+ /**
+ * Return the three-letter prefix of a SQL statement, skipping past whitespace and comments.
+ * Comments either start with "--" and run to the end of the line or are C-style block
+ * comments. The function returns null if a prefix could not be found.
+ */
+ private static String getSqlStatementPrefixExtended(String sql) {
+ Matcher m = sPrefixPattern.matcher(sql);
+ if (m.lookingAt()) {
+ return m.group(PREFIX_GROUP_NUM).toUpperCase(Locale.ROOT);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Return the extended statement type for the SQL statement. This is not a public API and it
* can return values that are not publicly visible.
* @hide
@@ -1630,6 +1664,9 @@
*/
public static int getSqlStatementTypeExtended(@NonNull String sql) {
int type = categorizeStatement(getSqlStatementPrefixSimple(sql), sql);
+ if (type == STATEMENT_COMMENT) {
+ type = categorizeStatement(getSqlStatementPrefixExtended(sql), sql);
+ }
return type;
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 97bbfbb..8c1ea5f 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -857,7 +857,7 @@
* Get the operation handle associated with this object or 0 if none.
*/
@FlaggedApi(FLAG_GET_OP_ID_CRYPTO_OBJECT)
- public long getOpId() {
+ public long getOperationHandle() {
return super.getOpId();
}
}
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index 56ec763..375fdb5 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -16,7 +16,7 @@
flag {
name: "get_op_id_crypto_object"
- namespace: "biometrics"
+ namespace: "biometrics_framework"
description: "Feature flag for adding a get operation id api to CryptoObject."
bug: "307601768"
}
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 490b128..8f0149b 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -52,6 +52,11 @@
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
@@ -789,6 +794,21 @@
case UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP:
complianceWarningString.append("missing rp, ");
break;
+ case UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED:
+ complianceWarningString.append("input power limited, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES:
+ complianceWarningString.append("missing data lines, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL:
+ complianceWarningString.append("enumeration fail, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION:
+ complianceWarningString.append("flaky connection, ");
+ break;
+ case UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO:
+ complianceWarningString.append("unreliable io, ");
+ break;
default:
complianceWarningString.append(String.format("Unknown(%d), ", warning));
break;
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index b4fe3a2..d959240 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -18,11 +18,13 @@
import android.Manifest;
import android.annotation.CheckResult;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.hardware.usb.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -310,6 +312,54 @@
public static final int COMPLIANCE_WARNING_MISSING_RP = 4;
/**
+ * Used to indicate the charging setups on the USB ports are unable to
+ * deliver negotiated power. Introduced in Android V (API level 35)
+ * and client applicantions that target API levels lower than 35 will
+ * receive {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_INPUT_POWER_LIMITED = 5;
+
+ /**
+ * Used to indicate the cable/connector on the USB ports are missing
+ * the required wires on the data pins to make data transfer.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_MISSING_DATA_LINES = 6;
+
+ /**
+ * Used to indicate enumeration failures on the USB ports, potentially due to
+ * signal integrity issues or other causes. Introduced in Android V
+ * (API level 35) and client applicantions that target API levels lower
+ * than 35 will receive {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_ENUMERATION_FAIL = 7;
+
+ /**
+ * Used to indicate unexpected data disconnection on the USB ports,
+ * potentially due to signal integrity issues or other causes.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_FLAKY_CONNECTION = 8;
+
+ /**
+ * Used to indicate unreliable or slow data transfer on the USB ports,
+ * potentially due to signal integrity issues or other causes.
+ * Introduced in Android V (API level 35) and client applicantions that
+ * target API levels lower than 35 will receive
+ * {@link #COMPLIANCE_WARNING_OTHER} instead.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING)
+ public static final int COMPLIANCE_WARNING_UNRELIABLE_IO = 9;
+
+ /**
* Indicates that the Type-C plug orientation cannot be
* determined because the connected state of the device is unknown.
*/
@@ -372,6 +422,11 @@
COMPLIANCE_WARNING_DEBUG_ACCESSORY,
COMPLIANCE_WARNING_BC_1_2,
COMPLIANCE_WARNING_MISSING_RP,
+ COMPLIANCE_WARNING_INPUT_POWER_LIMITED,
+ COMPLIANCE_WARNING_MISSING_DATA_LINES,
+ COMPLIANCE_WARNING_ENUMERATION_FAIL,
+ COMPLIANCE_WARNING_FLAKY_CONNECTION,
+ COMPLIANCE_WARNING_UNRELIABLE_IO,
})
@Retention(RetentionPolicy.SOURCE)
@interface ComplianceWarning{}
@@ -591,7 +646,12 @@
* @return array including {@link #COMPLIANCE_WARNING_OTHER},
* {@link #COMPLIANCE_WARNING_DEBUG_ACCESSORY},
* {@link #COMPLIANCE_WARNING_BC_1_2},
- * or {@link #COMPLIANCE_WARNING_MISSING_RP}
+ * {@link #COMPLIANCE_WARNING_MISSING_RP},
+ * {@link #COMPLIANCE_WARNING_INPUT_POWER_LIMITED},
+ * {@link #COMPLIANCE_WARNING_MISSING_DATA_LINES},
+ * {@link #COMPLIANCE_WARNING_ENUMERATION_FAIL},
+ * {@link #COMPLIANCE_WARNING_FLAKY_CONNECTION},
+ * {@link #COMPLIANCE_WARNING_UNRELIABLE_IO}.
*/
@CheckResult
@NonNull
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
new file mode 100644
index 0000000..6b78d05
--- /dev/null
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.hardware.usb.flags"
+
+flag {
+ name: "enable_usb_data_compliance_warning"
+ namespace: "system_sw_usb"
+ description: "Enable USB data compliance warnings when set"
+ bug: "296119135"
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index cc79ae3..57962f6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -153,8 +153,8 @@
/**
* User type representing a clone profile. Clone profile is a user profile type used to run
- * second instance of an otherwise single user App (eg, messengers). Only the primary user
- * is allowed to have a clone profile.
+ * second instance of an otherwise single user App (eg, messengers). Currently only the
+ * {@link android.content.pm.UserInfo#isMain()} user can have a clone profile.
*
* @hide
*/
@@ -166,6 +166,8 @@
* User type representing a private profile.
* @hide
*/
+ @FlaggedApi(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ @TestApi
public static final String USER_TYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
/**
@@ -3261,11 +3263,15 @@
/**
* Checks if the context user is a private profile.
*
+ * <p>A Private profile is a separate {@link #isProfile() profile} that can be used to store
+ * sensitive apps and data, which can be hidden or revealed at the user's discretion.
+ *
* @return whether the context user is a private profile.
*
- * @see android.os.UserManager#USER_TYPE_PROFILE_PRIVATE
* @hide
*/
+ @SystemApi
+ @FlaggedApi(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE)
@UserHandleAware(
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
android.Manifest.permission.MANAGE_USERS,
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index bcda25a..27ad45d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3206,15 +3206,6 @@
public static final String INFRASTRUCTURE_BITMASK = "infrastructure_bitmask";
/**
- * Indicating if the APN is used for eSIM bootsrap provisioning. The default value is 0 (Not
- * used for eSIM bootstrap provisioning).
- *
- * <P>Type: INTEGER</P>
- * @hide
- */
- public static final String ESIM_BOOTSTRAP_PROVISIONING = "esim_bootstrap_provisioning";
-
- /**
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index a1885ae..43c38f3 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -75,10 +75,3 @@
description: "A feature flag that implements line break word style auto."
bug: "280005585"
}
-
-flag {
- name: "inter_character_justification"
- namespace: "text"
- description: "A feature flag that implement inter character justification."
- bug: "283193133"
-}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 155f508..2945c8f 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -21,8 +21,6 @@
import com.android.internal.util.ArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 73114e2..adebe2c 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -20,8 +20,6 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import libcore.util.EmptyArray;
-
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
diff --git a/core/java/android/util/Base64.java b/core/java/android/util/Base64.java
index 33cc5e3..92abd7c 100644
--- a/core/java/android/util/Base64.java
+++ b/core/java/android/util/Base64.java
@@ -26,7 +26,6 @@
* href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
* href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
*/
-@android.ravenwood.annotations.RavenwoodWholeClassKeep
public class Base64 {
/**
* Default values for encoder/decoder flags.
diff --git a/core/java/android/util/EmptyArray.java b/core/java/android/util/EmptyArray.java
new file mode 100644
index 0000000..1216024
--- /dev/null
+++ b/core/java/android/util/EmptyArray.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+
+/**
+ * Empty array is immutable. Use a shared empty array to avoid allocation.
+ *
+ * @hide
+ */
+public final class EmptyArray {
+ private EmptyArray() {}
+
+ public static final @NonNull boolean[] BOOLEAN = new boolean[0];
+ public static final @NonNull byte[] BYTE = new byte[0];
+ public static final @NonNull char[] CHAR = new char[0];
+ public static final @NonNull double[] DOUBLE = new double[0];
+ public static final @NonNull float[] FLOAT = new float[0];
+ public static final @NonNull int[] INT = new int[0];
+ public static final @NonNull long[] LONG = new long[0];
+ public static final @NonNull Object[] OBJECT = new Object[0];
+ public static final @NonNull String[] STRING = new String[0];
+}
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index ac76fc2..c04a71c 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 9f269ed..3101c0d 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -23,8 +23,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/LongArrayQueue.java b/core/java/android/util/LongArrayQueue.java
index 5c701db..354f8df 100644
--- a/core/java/android/util/LongArrayQueue.java
+++ b/core/java/android/util/LongArrayQueue.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.NoSuchElementException;
/**
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 2f14b25..8402ab2 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -24,8 +24,6 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.LongObjPredicate;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
import java.util.Objects;
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index f23ec91..d4a0126 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -23,8 +23,6 @@
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
-import libcore.util.EmptyArray;
-
/**
* Map of {@code long} to {@code long}. Unlike a normal array of longs, there
* can be gaps in the indices. It is intended to be more memory efficient than using a
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 41c171a..750696b 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -19,7 +19,8 @@
import static com.android.internal.util.Preconditions.*;
import android.annotation.Nullable;
-import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Objects;
/**
* Immutable class for describing the range of two numeric values.
@@ -351,7 +352,7 @@
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCodeGeneric(mLower, mUpper);
+ return Objects.hash(mLower, mUpper);
}
private final T mLower;
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index cd03d83..c18cac3 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -22,8 +22,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.Objects;
/**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 12a9900..795f4c9 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -22,8 +22,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
/**
* SparseBooleanArrays map integers to booleans.
* Unlike a normal array of booleans
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 0e98c28..24d04be 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -21,8 +21,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
import java.util.Arrays;
/**
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index e86b647..4b257e6 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -19,8 +19,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
-import libcore.util.EmptyArray;
-
/**
* SparseLongArrays map integers to longs. Unlike a normal array of longs,
* there can be gaps in the indices. It is intended to be more memory efficient
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 42ac74c..ad326e4 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -11,6 +11,7 @@
roosa@google.com
jreck@google.com
siyamed@google.com
+mount@google.com
# Autofill
per-file ViewStructure.java = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index e4e8b7b5b..163dfa2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -424,11 +424,13 @@
TextureLayer layer = getTextureLayer();
if (layer != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextureView#draw()");
applyUpdate();
applyTransformMatrix();
mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
recordingCanvas.drawTextureLayer(layer);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e9d0e4c..a478b3c4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19,6 +19,8 @@
import static android.content.res.Resources.ID_NULL;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
+import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
@@ -27,6 +29,7 @@
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH;
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
+import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.flags.Flags.viewVelocityApi;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
@@ -114,6 +117,7 @@
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.FloatProperty;
import android.util.LayoutDirection;
import android.util.Log;
@@ -2300,6 +2304,8 @@
*/
protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+ private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
+
static {
EMPTY_STATE_SET = StateSet.get(0);
@@ -2381,6 +2387,8 @@
StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
| StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED
| StateSet.VIEW_STATE_PRESSED);
+
+ sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
}
/**
@@ -5509,6 +5517,11 @@
private ViewTranslationResponse mViewTranslationResponse;
/**
+ * A threshold value to determine the frame rate category of the View based on the size.
+ */
+ private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f;
+
+ /**
* Simple constructor to use when creating a view from code.
*
* @param context The Context the view is running in, through which it can
@@ -20183,6 +20196,9 @@
return;
}
+ // For VRR to vote the preferred frame rate
+ votePreferredFrameRate();
+
// Reset content capture caches
mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
mContentCaptureSessionCached = false;
@@ -20285,6 +20301,8 @@
*/
protected void damageInParent() {
if (mParent != null && mAttachInfo != null) {
+ // For VRR to vote the preferred frame rate
+ votePreferredFrameRate();
mParent.onDescendantInvalidated(this, this);
}
}
@@ -32981,6 +32999,41 @@
return null;
}
+ private float getSizePercentage() {
+ if (mResources == null || getAlpha() == 0 || getVisibility() != VISIBLE) {
+ return 0;
+ }
+
+ DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
+ int screenSize = displayMetrics.widthPixels
+ * displayMetrics.heightPixels;
+ int viewSize = getWidth() * getHeight();
+
+ if (screenSize == 0 || viewSize == 0) {
+ return 0f;
+ }
+ return (float) viewSize / screenSize;
+ }
+
+ private int calculateFrameRateCategory() {
+ float sizePercentage = getSizePercentage();
+
+ if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) {
+ return FRAME_RATE_CATEGORY_LOW;
+ } else {
+ return FRAME_RATE_CATEGORY_NORMAL;
+ }
+ }
+
+ private void votePreferredFrameRate() {
+ // use toolkitSetFrameRate flag to gate the change
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (sToolkitSetFrameRateReadOnlyFlagValue && viewRootImpl != null
+ && getSizePercentage() > 0) {
+ viewRootImpl.votePreferredFrameRateCategory(calculateFrameRateCategory());
+ }
+ }
+
/**
* Set the current velocity of the View, we only track positive value.
* We will use the velocity information to adjust the frame rate when applicable.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1ee303c..c9c1f20 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -24,6 +24,8 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsSource.ID_IME;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -74,7 +76,10 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -87,6 +92,7 @@
import static android.view.accessibility.Flags.forceInvertColor;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
+import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -738,6 +744,7 @@
private SurfaceControl mBoundsLayer;
private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final Transaction mTransaction = new Transaction();
+ private final Transaction mFrameRateTransaction = new Transaction();
@UnsupportedAppUsage
boolean mAdded;
@@ -961,6 +968,34 @@
private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
+ /*
+ * for Variable Refresh Rate project
+ */
+
+ // The preferred frame rate category of the view that
+ // could be updated on a frame-by-frame basis.
+ private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
+ // The preferred frame rate category of the last frame that
+ // could be used to lower frame rate after touch boost
+ private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
+ // The preferred frame rate of the view that is mainly used for
+ // touch boosting, view velocity handling, and TextureView.
+ private float mPreferredFrameRate = 0;
+ // Used to check if there were any view invalidations in
+ // the previous time frame (FRAME_RATE_IDLENESS_REEVALUATE_TIME).
+ private boolean mHasInvalidation = false;
+ // Used to check if it is in the touch boosting period.
+ private boolean mIsFrameRateBoosting = false;
+ // Used to check if there is a message in the message queue
+ // for idleness handling.
+ private boolean mHasIdledMessage = false;
+ // time for touch boost period.
+ private static final int FRAME_RATE_TOUCH_BOOST_TIME = 1500;
+ // time for checking idle status periodically.
+ private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
+ // time for revaluating the idle status before lowering the frame rate.
+ private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500;
+
/**
* A temporary object used so relayoutWindow can return the latest SyncSeqId
* system. The SyncSeqId system was designed to work without synchronous relayout
@@ -1010,6 +1045,12 @@
private String mTag = TAG;
+ private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
+
+ static {
+ sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
+ }
+
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
}
@@ -3947,6 +3988,12 @@
mWmsRequestSyncGroupState = WMS_SYNC_NONE;
}
}
+
+ // For the variable refresh rate project.
+ setPreferredFrameRate(mPreferredFrameRate);
+ setPreferredFrameRateCategory(mPreferredFrameRateCategory);
+ mLastPreferredFrameRateCategory = mPreferredFrameRateCategory;
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
}
private void createSyncIfNeeded() {
@@ -6022,6 +6069,8 @@
private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38;
+ private static final int MSG_TOUCH_BOOST_TIMEOUT = 39;
+ private static final int MSG_CHECK_INVALIDATION_IDLE = 40;
final class ViewRootHandler extends Handler {
@Override
@@ -6317,6 +6366,32 @@
mNumPausedForSync = 0;
scheduleTraversals();
break;
+ case MSG_TOUCH_BOOST_TIMEOUT:
+ /**
+ * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME).
+ */
+ mIsFrameRateBoosting = false;
+ setPreferredFrameRateCategory(Math.max(mPreferredFrameRateCategory,
+ mLastPreferredFrameRateCategory));
+ break;
+ case MSG_CHECK_INVALIDATION_IDLE:
+ if (!mHasInvalidation && !mIsFrameRateBoosting) {
+ mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
+ setPreferredFrameRateCategory(mPreferredFrameRateCategory);
+ mHasIdledMessage = false;
+ } else {
+ /**
+ * If there is no invalidation within a certain period,
+ * we consider the display is idled.
+ * We then set the frame rate catetogry to NO_PREFERENCE.
+ * Note that SurfaceFlinger also has a mechanism to lower the refresh rate
+ * if there is no updates of the buffer.
+ */
+ mHasInvalidation = false;
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
+ FRAME_RATE_IDLENESS_REEVALUATE_TIME);
+ }
+ break;
}
}
}
@@ -7259,6 +7334,7 @@
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
+ final int action = event.getAction();
boolean handled = mHandwritingInitiator.onTouchEvent(event);
if (handled) {
// If handwriting is started, toolkit doesn't receive ACTION_UP.
@@ -7279,6 +7355,22 @@
scheduleConsumeBatchedInputImmediately();
}
}
+
+ // For the variable refresh rate project
+ if (handled && shouldTouchBoost(action, mWindowAttributes.type)) {
+ // set the frame rate to the maximum value.
+ mIsFrameRateBoosting = true;
+ setPreferredFrameRateCategory(mPreferredFrameRateCategory);
+ }
+ /**
+ * We want to lower the refresh rate when MotionEvent.ACTION_UP,
+ * MotionEvent.ACTION_CANCEL is detected.
+ * Not using ACTION_MOVE to avoid checking and sending messages too frequently.
+ */
+ if (mIsFrameRateBoosting && (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_CANCEL)) {
+ sendDelayedEmptyMessage(MSG_TOUCH_BOOST_TIMEOUT, FRAME_RATE_TOUCH_BOOST_TIME);
+ }
return handled ? FINISH_HANDLED : FORWARD;
}
@@ -11894,6 +11986,96 @@
Log.d(mTag, msg);
}
+ private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
+ if (!shouldSetFrameRateCategory()) {
+ return;
+ }
+
+ int frameRateCategory = mIsFrameRateBoosting
+ ? FRAME_RATE_CATEGORY_HIGH : preferredFrameRateCategory;
+
+ try {
+ mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
+ frameRateCategory, false).apply();
+ } catch (Exception e) {
+ Log.e(mTag, "Unable to set frame rate category", e);
+ }
+
+ if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
+ // Check where the display is idled periodically.
+ // If so, set the frame rate category to NO_PREFERENCE
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
+ FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
+ mHasIdledMessage = true;
+ }
+ }
+
+ private void setPreferredFrameRate(float preferredFrameRate) {
+ if (!shouldSetFrameRate()) {
+ return;
+ }
+
+ try {
+ mFrameRateTransaction.setFrameRate(mSurfaceControl,
+ preferredFrameRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT).apply();
+ } catch (Exception e) {
+ Log.e(mTag, "Unable to set frame rate", e);
+ }
+ }
+
+ private void sendDelayedEmptyMessage(int message, int delayedTime) {
+ mHandler.removeMessages(message);
+
+ mHandler.sendEmptyMessageDelayed(message, delayedTime);
+ }
+
+ private boolean shouldSetFrameRateCategory() {
+ // use toolkitSetFrameRate flag to gate the change
+ return mSurface.isValid() && sToolkitSetFrameRateReadOnlyFlagValue;
+ }
+
+ private boolean shouldSetFrameRate() {
+ // use toolkitSetFrameRate flag to gate the change
+ return mPreferredFrameRate > 0 && sToolkitSetFrameRateReadOnlyFlagValue;
+ }
+
+ private boolean shouldTouchBoost(int motionEventAction, int windowType) {
+ boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
+ || motionEventAction == MotionEvent.ACTION_MOVE
+ || motionEventAction == MotionEvent.ACTION_UP;
+ boolean desiredType = windowType == TYPE_BASE_APPLICATION || windowType == TYPE_APPLICATION
+ || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION;
+ // use toolkitSetFrameRate flag to gate the change
+ return desiredAction && desiredType && sToolkitSetFrameRateReadOnlyFlagValue;
+ }
+
+ /**
+ * Allow Views to vote for the preferred frame rate category
+ *
+ * @param frameRateCategory the preferred frame rate category of a View
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public void votePreferredFrameRateCategory(int frameRateCategory) {
+ mPreferredFrameRateCategory = Math.max(mPreferredFrameRateCategory, frameRateCategory);
+ mHasInvalidation = true;
+ }
+
+ /**
+ * Get the value of mPreferredFrameRateCategory
+ */
+ @VisibleForTesting
+ public int getPreferredFrameRateCategory() {
+ return mPreferredFrameRateCategory;
+ }
+
+ /**
+ * Get the value of mPreferredFrameRate
+ */
+ @VisibleForTesting
+ public float getPreferredFrameRate() {
+ return mPreferredFrameRate;
+ }
+
@Override
public boolean transferHostTouchGestureToEmbedded(
@NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
new file mode 100644
index 0000000..3c15518
--- /dev/null
+++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.view.contentcapture.flags"
+
+flag {
+ name: "run_on_background_thread_enabled"
+ namespace: "machine_learning"
+ description: "Feature flag for running content capture tasks on background thread"
+ bug: "309411951"
+}
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 2b08eeb..cc951cf 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -15,6 +15,14 @@
}
flag {
+ name: "toolkit_set_frame_rate_read_only"
+ namespace: "toolkit"
+ description: "Feature flag for toolkit to set frame rate"
+ bug: "293512962"
+ is_fixed_read_only: true
+}
+
+flag {
name: "expected_presentation_time_api"
namespace: "toolkit"
description: "Feature flag for using expected presentation time of the Choreographer"
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 2913faf..cd1275c 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -24,7 +24,7 @@
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityManager;
-import android.app.TaskInfo.CameraCompatControlState;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 1a2d202..5bfa3d7 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -55,6 +55,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Used to communicate information about what is changing during a transition to a TransitionPlayer.
@@ -610,7 +611,7 @@
private final WindowContainerToken mContainer;
private WindowContainerToken mParent;
private WindowContainerToken mLastParent;
- private final SurfaceControl mLeash;
+ private SurfaceControl mLeash;
private @TransitionMode int mMode = TRANSIT_NONE;
private @ChangeFlags int mFlags = FLAG_NONE;
private final Rect mStartAbsBounds = new Rect();
@@ -697,6 +698,11 @@
mLastParent = lastParent;
}
+ /** Sets the animation leash for controlling this change's container */
+ public void setLeash(@NonNull SurfaceControl leash) {
+ mLeash = Objects.requireNonNull(leash);
+ }
+
/** Sets the transition mode for this change */
public void setMode(@TransitionMode int mode) {
mMode = mode;
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index 4bfb177..94e6009 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -19,4 +19,11 @@
namespace: "responsible_apis"
description: "Enable toasts to indicate (potential) BAL blocking."
bug: "308059069"
+}
+
+flag {
+ name: "bal_show_toasts_blocked"
+ namespace: "responsible_apis"
+ description: "Enable toasts to indicate actual BAL blocking."
+ bug: "308059069"
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 08de4dfb..be3f10a 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -287,7 +287,6 @@
updatedView = mInflater.inflate(
R.layout.app_language_picker_current_locale_item,
parent, false);
- addStateDescriptionIntoCurrentLocaleItem(updatedView);
}
} else {
shouldReuseView = convertView instanceof TextView
@@ -304,7 +303,6 @@
if (!shouldReuseView) {
updatedView = mInflater.inflate(
R.layout.app_language_picker_current_locale_item, parent, false);
- addStateDescriptionIntoCurrentLocaleItem(updatedView);
}
break;
default:
@@ -441,9 +439,4 @@
: View.TEXT_DIRECTION_LTR);
}
}
-
- private void addStateDescriptionIntoCurrentLocaleItem(View root) {
- String description = root.getContext().getResources().getString(R.string.checked);
- root.setStateDescription(description);
- }
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index e014ab0..6c17e9e 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -65,6 +65,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
import android.transition.Scene;
@@ -183,6 +184,12 @@
private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
/**
+ * Since which target SDK version this window should be edge-to-edge by default.
+ */
+ private static final int DEFAULT_EDGE_TO_EDGE_SDK_VERSION =
+ SystemProperties.getInt("persist.wm.debug.default_e2e_since_sdk", Integer.MAX_VALUE);
+
+ /**
* Simple callback used by the context menu and its submenus. The options
* menu submenus do not use this (their behavior is more complex).
*/
@@ -359,6 +366,8 @@
boolean mDecorFitsSystemWindows = true;
+ private final boolean mDefaultEdgeToEdge;
+
private final ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher;
static class WindowManagerHolder {
@@ -377,6 +386,11 @@
mProxyOnBackInvokedDispatcher = new ProxyOnBackInvokedDispatcher(context);
mAllowFloatingWindowsFillScreen = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowFloatingWindowsFillScreen);
+ mDefaultEdgeToEdge =
+ context.getApplicationInfo().targetSdkVersion >= DEFAULT_EDGE_TO_EDGE_SDK_VERSION;
+ if (mDefaultEdgeToEdge) {
+ mDecorFitsSystemWindows = false;
+ }
}
/**
@@ -2527,7 +2541,14 @@
final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
if (!mForcedStatusBarColor) {
- mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, Color.BLACK);
+ final int statusBarCompatibleColor = context.getColor(R.color.status_bar_compatible);
+ final int statusBarDefaultColor = context.getColor(R.color.status_bar_default);
+ final int statusBarColor = a.getColor(R.styleable.Window_statusBarColor,
+ statusBarDefaultColor);
+
+ mStatusBarColor = statusBarColor == statusBarDefaultColor && !mDefaultEdgeToEdge
+ ? statusBarCompatibleColor
+ : statusBarColor;
}
if (!mForcedNavigationBarColor) {
final int navBarCompatibleColor = context.getColor(R.color.navigation_bar_compatible);
@@ -2541,6 +2562,7 @@
&& Flags.navBarTransparentByDefault())
&& !context.getResources().getBoolean(
R.bool.config_navBarDefaultTransparent)
+ && !mDefaultEdgeToEdge
? navBarCompatibleColor
: navBarColor;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index b64771b..686e1fc 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -21,11 +21,10 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.util.ArraySet;
+import android.util.EmptyArray;
import dalvik.system.VMRuntime;
-import libcore.util.EmptyArray;
-
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
@@ -84,6 +83,38 @@
return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
}
+ public static byte[] newUnpaddedByteArray$ravenwood(int minLen) {
+ return new byte[minLen];
+ }
+
+ public static char[] newUnpaddedCharArray$ravenwood(int minLen) {
+ return new char[minLen];
+ }
+
+ public static int[] newUnpaddedIntArray$ravenwood(int minLen) {
+ return new int[minLen];
+ }
+
+ public static boolean[] newUnpaddedBooleanArray$ravenwood(int minLen) {
+ return new boolean[minLen];
+ }
+
+ public static long[] newUnpaddedLongArray$ravenwood(int minLen) {
+ return new long[minLen];
+ }
+
+ public static float[] newUnpaddedFloatArray$ravenwood(int minLen) {
+ return new float[minLen];
+ }
+
+ public static Object[] newUnpaddedObjectArray$ravenwood(int minLen) {
+ return new Object[minLen];
+ }
+
+ public static <T> T[] newUnpaddedArray$ravenwood(Class<T> clazz, int minLen) {
+ return (T[]) Array.newInstance(clazz, minLen);
+ }
+
/**
* Checks if the beginnings of two byte arrays are equal.
*
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index b462c21..58ee2b2 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -19,12 +19,14 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED;
@@ -222,6 +224,16 @@
*/
public static final int ACTION_NOTIFICATION_BIG_PICTURE_LOADED = 23;
+ /**
+ * Time it takes to unlock the device via udfps, until the whole launcher appears.
+ */
+ public static final int ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME = 24;
+
+ /**
+ * Time it takes to start back preview surface animation after a back gesture starts.
+ */
+ public static final int ACTION_BACK_SYSTEM_ANIMATION = 25;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -247,6 +259,8 @@
ACTION_REQUEST_IME_HIDDEN,
ACTION_SMARTSPACE_DOORBELL,
ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ ACTION_BACK_SYSTEM_ANIMATION,
};
/** @hide */
@@ -275,6 +289,8 @@
ACTION_REQUEST_IME_HIDDEN,
ACTION_SMARTSPACE_DOORBELL,
ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ ACTION_BACK_SYSTEM_ANIMATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -306,6 +322,8 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION,
};
private final Object mLock = new Object();
@@ -492,6 +510,10 @@
return "ACTION_SMARTSPACE_DOORBELL";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATION_BIG_PICTURE_LOADED:
return "ACTION_NOTIFICATION_BIG_PICTURE_LOADED";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME:
+ return "ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION:
+ return "ACTION_BACK_SYSTEM_ANIMATION";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ab0ef7d..6859f1f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2247,6 +2247,13 @@
<permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
+ credentials such as Network Key and PSKc.
+ <p>Not for use by third-party applications.
+ @FlaggedApi("com.android.net.thread.flags.thread_enabled") -->
+ <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
<!-- #SystemApi @hide Allows an app to bypass Private DNS.
<p>Not for use by third-party applications.
TODO: publish as system API in next API release. -->
@@ -7782,6 +7789,15 @@
<permission android:name="android.permission.WRITE_FLAGS"
android:protectionLevel="signature" />
+ <!-- @hide @SystemApi
+ @FlaggedApi("android.app.get_binding_uid_importance")
+ Allows to get the importance of an UID that has a service
+ binding to the app.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @hide Allows internal applications to manage displays.
<p>This means intercept internal signals about displays being (dis-)connected
and being able to enable or disable the external displays.
diff --git a/core/res/res/layout/app_language_picker_current_locale_item.xml b/core/res/res/layout/app_language_picker_current_locale_item.xml
index 990e26c..01b9cc5 100644
--- a/core/res/res/layout/app_language_picker_current_locale_item.xml
+++ b/core/res/res/layout/app_language_picker_current_locale_item.xml
@@ -39,6 +39,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_check_24dp"
- app:tint="?attr/colorAccentPrimaryVariant"/>
+ app:tint="?attr/colorAccentPrimaryVariant"
+ android:contentDescription="@*android:string/checked"/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values-af-watch/strings.xml b/core/res/res/values-af-watch/strings.xml
index 21ba346..15bc1f3 100644
--- a/core/res/res/values-af-watch/strings.xml
+++ b/core/res/res/values-af-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Nood-SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-stelselopdatering"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am-watch/strings.xml b/core/res/res/values-am-watch/strings.xml
index ad9b696..243ba55 100644
--- a/core/res/res/values-am-watch/strings.xml
+++ b/core/res/res/values-am-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"አነፍናፊዎች"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"የነፍስ አድን ድንገተኛ ጥሪ"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"የWear OS ስርዓት ዝማኔ"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar-watch/strings.xml b/core/res/res/values-ar-watch/strings.xml
index a8ca4cc..2a8248b 100644
--- a/core/res/res/values-ar-watch/strings.xml
+++ b/core/res/res/values-ar-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"أجهزة الاستشعار"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"اتصالات الطوارئ"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"تحديث نظام التشغيل Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as-watch/strings.xml b/core/res/res/values-as-watch/strings.xml
index 5dc8863..d65b58d 100644
--- a/core/res/res/values-as-watch/strings.xml
+++ b/core/res/res/values-as-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ছেন্সৰসমূহ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"জৰুৰীকালীন SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OSৰ ছিষ্টেম আপডে’ট"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index df4f28a..517ae9a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1941,8 +1941,8 @@
<string name="importance_from_user" msgid="2782756722448800447">"এই জাননীবোৰৰ গুৰুত্ব আপুনি ছেট কৰব লাগিব।"</string>
<string name="importance_from_person" msgid="4235804979664465383">"এই কার্যৰ সৈতে জড়িত থকা লোকসকলক ভিত্তি কৰি এইয়া গুৰুত্বপূর্ণ বুলি বিবেচনা কৰা হৈছ।"</string>
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"কাষ্টম এপৰ জাননী"</string>
- <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এজন ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string>
- <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এগৰাকী ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এগৰাকী নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string>
+ <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এগৰাকী নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
<string name="supervised_user_creation_label" msgid="6884904353827427515">"নিৰীক্ষণত থকা ব্যৱহাৰকাৰী যোগ দিয়ক"</string>
<string name="language_selection_title" msgid="52674936078683285">"ভাষা যোগ কৰক"</string>
<string name="country_selection_title" msgid="5221495687299014379">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
diff --git a/core/res/res/values-az-watch/strings.xml b/core/res/res/values-az-watch/strings.xml
index cf1b7a5..15b640b 100644
--- a/core/res/res/values-az-watch/strings.xml
+++ b/core/res/res/values-az-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorlar"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Fövqəladə halda SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS sistem güncəlləməsi"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn-watch/strings.xml b/core/res/res/values-b+sr+Latn-watch/strings.xml
index da58726..fc0b05d 100644
--- a/core/res/res/values-b+sr+Latn-watch/strings.xml
+++ b/core/res/res/values-b+sr+Latn-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Hitna pomoć"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Ažuriranje sistema za Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be-watch/strings.xml b/core/res/res/values-be-watch/strings.xml
index 75e6307..bd3f77a 100644
--- a/core/res/res/values-be-watch/strings.xml
+++ b/core/res/res/values-be-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Датчыкі"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Экстранны выклік"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Абнаўленне сістэмы Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg-watch/strings.xml b/core/res/res/values-bg-watch/strings.xml
index 7977f66..e72ec96 100644
--- a/core/res/res/values-bg-watch/strings.xml
+++ b/core/res/res/values-bg-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Сензори"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Спешно повикване SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Системна актуализация за Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn-watch/strings.xml b/core/res/res/values-bn-watch/strings.xml
index c98d372..9b6ad6b 100644
--- a/core/res/res/values-bn-watch/strings.xml
+++ b/core/res/res/values-bn-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"সেন্সরগুলি"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ইমারজেন্সি SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS সিস্টেম আপডেট"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs-watch/strings.xml b/core/res/res/values-bs-watch/strings.xml
index da58726..e4a774a 100644
--- a/core/res/res/values-bs-watch/strings.xml
+++ b/core/res/res/values-bs-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Hitni pozivi"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Ažuriranje Wear OS sistema"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 8104b59..20f1d68 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1690,8 +1690,8 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Nastaviti slušati pri visokoj jačini zvuka?\n\nJačina zvuka slušalica je bila visoka duže od preporučenog, što može oštetiti sluh"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Otkriven je glasan zvuk\n\nJačina zvuka slušalica je bila viša od preporučenog, što može oštetiti sluh"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Nastaviti slušati pri visokoj jačini zvuka?\n\nJačina zvuka slušalica je bila visoka duže nego što se preporučuje, što može oštetiti sluh"</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Otkriven je glasan zvuk\n\nJačina zvuka slušalica je bila viša od preporučene, što može oštetiti sluh"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Uključiti prečicu za funkcije pristupačnosti?"</string>
diff --git a/core/res/res/values-ca-watch/strings.xml b/core/res/res/values-ca-watch/strings.xml
index 21ba346..98f1daa 100644
--- a/core/res/res/values-ca-watch/strings.xml
+++ b/core/res/res/values-ca-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergència SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Actualització del sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs-watch/strings.xml b/core/res/res/values-cs-watch/strings.xml
index 6c9d718..2ddd534 100644
--- a/core/res/res/values-cs-watch/strings.xml
+++ b/core/res/res/values-cs-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzory"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Tísňové volání"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Aktualizace systému Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da-watch/strings.xml b/core/res/res/values-da-watch/strings.xml
index fa296b6..26e7b72 100644
--- a/core/res/res/values-da-watch/strings.xml
+++ b/core/res/res/values-da-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorer"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Alarm-SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-systemopdatering"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de-watch/strings.xml b/core/res/res/values-de-watch/strings.xml
index 3f693a9..370ea92 100644
--- a/core/res/res/values-de-watch/strings.xml
+++ b/core/res/res/values-de-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensoren"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Notfall-SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-Systemupdate"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3faf328..2c1adb8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1689,8 +1689,8 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Entfernen"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Weiter mit hoher Lautstärke hören?\n\nDu hast deine Kopfhörer länger als empfohlen mit einer hohen Lautstärke betrieben. Das kann deinem Hörvermögen schaden"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Lautes Geräusch erkannt\n\nDu hast deine Kopfhörer lauter als empfohlen eingestellt. Das kann deinem Hörvermögen schaden"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Weiter mit hoher Lautstärke hören?\n\nDeine Kopfhörer sind schon länger als empfohlen auf hohe Lautstärke eingestellt – das kann deinem Hörvermögen schaden"</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Hohe Lautstärke erkannt\n\nDu hast deine Kopfhörer lauter als empfohlen eingestellt – das kann deinem Hörvermögen schaden"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Verknüpfung für Bedienungshilfen aktivieren?"</string>
diff --git a/core/res/res/values-el-watch/strings.xml b/core/res/res/values-el-watch/strings.xml
index 4d5b10d..55de5f2 100644
--- a/core/res/res/values-el-watch/strings.xml
+++ b/core/res/res/values-el-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Αισθητήρες"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Έκτακτη ανάγκη SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Ενημέρωση συστήματος Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU-watch/strings.xml b/core/res/res/values-en-rAU-watch/strings.xml
index 21ba346..e550f9e 100644
--- a/core/res/res/values-en-rAU-watch/strings.xml
+++ b/core/res/res/values-en-rAU-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS system update"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rCA-watch/strings.xml b/core/res/res/values-en-rCA-watch/strings.xml
index 21ba346..5008fac 100644
--- a/core/res/res/values-en-rCA-watch/strings.xml
+++ b/core/res/res/values-en-rCA-watch/strings.xml
@@ -21,4 +21,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <string name="reboot_to_update_prepare" msgid="4129802024411268230">"Preparing to update"</string>
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS system update"</string>
+ <string name="select_input_method" msgid="1285150113084396451">"Choose input"</string>
</resources>
diff --git a/core/res/res/values-en-rGB-watch/strings.xml b/core/res/res/values-en-rGB-watch/strings.xml
index 21ba346..e550f9e 100644
--- a/core/res/res/values-en-rGB-watch/strings.xml
+++ b/core/res/res/values-en-rGB-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS system update"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN-watch/strings.xml b/core/res/res/values-en-rIN-watch/strings.xml
index 21ba346..e550f9e 100644
--- a/core/res/res/values-en-rIN-watch/strings.xml
+++ b/core/res/res/values-en-rIN-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS system update"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rXC-watch/strings.xml b/core/res/res/values-en-rXC-watch/strings.xml
index 4ed361d..8910f31 100644
--- a/core/res/res/values-en-rXC-watch/strings.xml
+++ b/core/res/res/values-en-rXC-watch/strings.xml
@@ -21,4 +21,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensors"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <string name="reboot_to_update_prepare" msgid="4129802024411268230">"Preparing to update"</string>
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS system update"</string>
+ <string name="select_input_method" msgid="1285150113084396451">"Choose input"</string>
</resources>
diff --git a/core/res/res/values-es-rUS-watch/strings.xml b/core/res/res/values-es-rUS-watch/strings.xml
index dea270b..5c5b660 100644
--- a/core/res/res/values-es-rUS-watch/strings.xml
+++ b/core/res/res/values-es-rUS-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergencia SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Actualización del sistema de Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es-watch/strings.xml b/core/res/res/values-es-watch/strings.xml
index dea270b..1877b42 100644
--- a/core/res/res/values-es-watch/strings.xml
+++ b/core/res/res/values-es-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergencia SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Actualización del sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f310c93..b76229a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1690,8 +1690,8 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Quitar"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"¿Seguir escuchando a un volumen alto?\n\nEl volumen de los auriculares ha estado alto durante más tiempo del recomendado, lo que puede dañar tu audición"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Sonido alto detectado\n\nEl volumen de los auriculares está más alto de lo recomendado, lo que puede dañar tu audición"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"¿Seguir escuchando a un volumen alto?\n\nEl volumen de los auriculares ha estado alto durante más tiempo del recomendado, lo que puede dañar tu audición."</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Sonido alto detectado\n\nEl volumen de los auriculares está más alto de lo recomendado, lo que puede dañar tu audición."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar el acceso directo a las funciones de accesibilidad?"</string>
diff --git a/core/res/res/values-et-watch/strings.xml b/core/res/res/values-et-watch/strings.xml
index 4888bc1..09ff2e5 100644
--- a/core/res/res/values-et-watch/strings.xml
+++ b/core/res/res/values-et-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Andurid"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Hädaabikõne"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-i süsteemivärskendus"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu-watch/strings.xml b/core/res/res/values-eu-watch/strings.xml
index 7bb5e9d..3d739a0 100644
--- a/core/res/res/values-eu-watch/strings.xml
+++ b/core/res/res/values-eu-watch/strings.xml
@@ -21,4 +21,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sentsoreak"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS larrialdia"</string>
+ <string name="reboot_to_update_prepare" msgid="4129802024411268230">"Eguneratzeko prestatzen"</string>
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS sistemaren eguneratzea"</string>
+ <string name="select_input_method" msgid="1285150113084396451">"Aukeratu idazketa-metodo bat"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index a163ed8..86eaf0a 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1689,8 +1689,8 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Kendu"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Bolumen altuan entzuten jarraitu nahi duzu?\n\nEntzungailuen bolumena gomendatutako denboran baino gehiagoan eduki da ozen, eta baliteke horrek entzumena kaltetzea"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Soinu ozen bat hauteman da\n\nEntzungailuen bolumena gomendatutakoa baino ozenago eduki da, eta baliteke horrek entzumena kaltetzea"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Bolumen altuan entzuten jarraitu nahi duzu?\n\nEntzungailuen bolumena gomendatutako denbora baino luzaroago egon da ozen, eta baliteke horrek entzumena kaltetzea"</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Soinua ozenegia dela hauteman da\n\nEntzungailuen bolumena gomendatutakoa baino ozenago eduki da, eta baliteke horrek entzumena kaltetzea"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erabilerraztasun-eginbideetarako lasterbidea aktibatu nahi duzu?"</string>
diff --git a/core/res/res/values-fa-watch/strings.xml b/core/res/res/values-fa-watch/strings.xml
index 4bd0216..0607c37 100644
--- a/core/res/res/values-fa-watch/strings.xml
+++ b/core/res/res/values-fa-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"حسگرها"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"کمک اضطراری"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"بهروزرسانی سیستم Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi-watch/strings.xml b/core/res/res/values-fi-watch/strings.xml
index d565979c3..a8e873d 100644
--- a/core/res/res/values-fi-watch/strings.xml
+++ b/core/res/res/values-fi-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Anturit"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Hätäpuhelut"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS ‑järjestelmäpäivitys"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA-watch/strings.xml b/core/res/res/values-fr-rCA-watch/strings.xml
index dc71b35..babd6ca 100644
--- a/core/res/res/values-fr-rCA-watch/strings.xml
+++ b/core/res/res/values-fr-rCA-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Capteurs"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Appel d\'urgence"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Mise à jour du système Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-watch/strings.xml b/core/res/res/values-fr-watch/strings.xml
index dc71b35..130c466 100644
--- a/core/res/res/values-fr-watch/strings.xml
+++ b/core/res/res/values-fr-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Capteurs"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS Urgence"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Mise à jour du système Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl-watch/strings.xml b/core/res/res/values-gl-watch/strings.xml
index dea270b..f11990a 100644
--- a/core/res/res/values-gl-watch/strings.xml
+++ b/core/res/res/values-gl-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emerxencia SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Actualización do sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu-watch/strings.xml b/core/res/res/values-gu-watch/strings.xml
index 8d38a68..331ffa7 100644
--- a/core/res/res/values-gu-watch/strings.xml
+++ b/core/res/res/values-gu-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"સેન્સર્સ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ઇમર્જન્સી સહાય"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OSની સિસ્ટમ અપડેટ"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi-watch/strings.xml b/core/res/res/values-hi-watch/strings.xml
index e73ce77..75ff50d 100644
--- a/core/res/res/values-hi-watch/strings.xml
+++ b/core/res/res/values-hi-watch/strings.xml
@@ -20,5 +20,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="permgrouplab_sensors" msgid="2439544173324807471">"संवेदक"</string>
+ <string name="permgrouplab_sensors" msgid="2439544173324807471">"सेंसर"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"इमरजेंसी एसओएस"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS का सिस्टम अपडेट"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr-watch/strings.xml b/core/res/res/values-hr-watch/strings.xml
index da58726..237b4c0 100644
--- a/core/res/res/values-hr-watch/strings.xml
+++ b/core/res/res/values-hr-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS poziv"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Ažuriranje sustava Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu-watch/strings.xml b/core/res/res/values-hu-watch/strings.xml
index b8053c1..00c7b04 100644
--- a/core/res/res/values-hu-watch/strings.xml
+++ b/core/res/res/values-hu-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Érzékelők"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Segélyhívás"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-rendszerfrissítés"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy-watch/strings.xml b/core/res/res/values-hy-watch/strings.xml
index 4966e04..3de85ed 100644
--- a/core/res/res/values-hy-watch/strings.xml
+++ b/core/res/res/values-hy-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Սենսորներ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Շտապ կանչեր"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS համակարգի թարմացում"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ccea0cc..9c2c2c5 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1689,7 +1689,7 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Հեռացնել"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Պահե՞լ ձայնը բարձրացրած\n\nԱկանջակալների ձայնի ուժգնությունը տևական ժամանակ ավելի բարձր է եղել առաջարկվող մակարդակից, ինչը կարող է վնասել ձեր լսողությունը"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Բարձր պահե՞լ ձայնը\n\nԱկանջակալների ձայնի ուժգնությունը տևական ժամանակ ավելի բարձր է եղել առաջարկվող մակարդակից, ինչը կարող է վնասել ձեր լսողությունը"</string>
<string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Հայտնաբերվել է ձայնի բարձր ուժգնություն\n\nԱկանջակալների ձայնի ուժգնությունը բարձր է առաջարկվող մակարդակից, ինչը կարող է վնասել ձեր լսողությունը"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string>
diff --git a/core/res/res/values-in-watch/strings.xml b/core/res/res/values-in-watch/strings.xml
index 4d64473..34eaa91 100644
--- a/core/res/res/values-in-watch/strings.xml
+++ b/core/res/res/values-in-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensor"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Darurat SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Update sistem Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is-watch/strings.xml b/core/res/res/values-is-watch/strings.xml
index 041a534..50781a8 100644
--- a/core/res/res/values-is-watch/strings.xml
+++ b/core/res/res/values-is-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Skynjarar"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Neyðartilkynning"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Kerfisuppfærsla Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it-watch/strings.xml b/core/res/res/values-it-watch/strings.xml
index e22f614..e01c55f 100644
--- a/core/res/res/values-it-watch/strings.xml
+++ b/core/res/res/values-it-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS emergenze"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Aggiornamento di sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index e6bc552..9ffadbe 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1691,7 +1691,7 @@
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Rimuovi"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string>
<string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Vuoi continuare ad ascoltare a un volume alto?\n\nIl volume delle cuffie è rimasto alto per un periodo superiore a quello raccomandato, con il rischio di danneggiare l\'udito"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Rilevato un suono forte\n\nIl volume delle cuffie è più alto di quello raccomandato, con il rischio di danneggiare l\'udito"</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Rilevato suono forte\n\nIl volume delle cuffie è più alto di quello raccomandato e potrebbe danneggiare il tuo udito"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vuoi attivare la scorciatoia per le funzioni di accessibilità?"</string>
diff --git a/core/res/res/values-iw-watch/strings.xml b/core/res/res/values-iw-watch/strings.xml
index d03a499..3dc8a86 100644
--- a/core/res/res/values-iw-watch/strings.xml
+++ b/core/res/res/values-iw-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"חיישנים"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"מצב חירום"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"עדכון מערכת של Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja-watch/strings.xml b/core/res/res/values-ja-watch/strings.xml
index 05ee203..7e19843 100644
--- a/core/res/res/values-ja-watch/strings.xml
+++ b/core/res/res/values-ja-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"センサー"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"緊急 SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS システム アップデート"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka-watch/strings.xml b/core/res/res/values-ka-watch/strings.xml
index e91e2d3..993d6d2 100644
--- a/core/res/res/values-ka-watch/strings.xml
+++ b/core/res/res/values-ka-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"სენსორები"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"გადაუდებელი დახმარება"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS სისტემის განახლება"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk-watch/strings.xml b/core/res/res/values-kk-watch/strings.xml
index 6eb05ba..622350c 100644
--- a/core/res/res/values-kk-watch/strings.xml
+++ b/core/res/res/values-kk-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Сенсорлар"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Құтқару қызметін шақыру"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS жүйесін жаңарту"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km-watch/strings.xml b/core/res/res/values-km-watch/strings.xml
index dd72ee4..ae7ba7d 100644
--- a/core/res/res/values-km-watch/strings.xml
+++ b/core/res/res/values-km-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ឧបករណ៍ចាប់សញ្ញា"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS ពេលមានអាសន្ន"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"បច្ចុប្បន្នភាពប្រព័ន្ធ Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn-watch/strings.xml b/core/res/res/values-kn-watch/strings.xml
index b5cf763..6b7af18 100644
--- a/core/res/res/values-kn-watch/strings.xml
+++ b/core/res/res/values-kn-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ಸೆನ್ಸರ್ಗಳು"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ತುರ್ತು SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS ಸಿಸ್ಟಂ ಅಪ್ಡೇಟ್"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko-watch/strings.xml b/core/res/res/values-ko-watch/strings.xml
index a9cbb63..c5bf069 100644
--- a/core/res/res/values-ko-watch/strings.xml
+++ b/core/res/res/values-ko-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"센서"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"긴급 SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS 시스템 업데이트"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0608283..b867fe6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1690,7 +1690,7 @@
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"삭제"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
<string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"계속해서 높은 볼륨으로 들으시겠습니까?\n\n헤드폰 볼륨이 권장 시간보다 오랫동안 높은 상태였으며 이로 인해 청력 손상이 발생할 수 있습니다."</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"큰 소리가 감지됨\n\n헤드폰 볼륨이 권장 시간보다 오랫동안 높은 상태였으며 이로 인해 청력 손상이 발생할 수 있습니다."</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"큰 소리가 감지됨\n\n헤드폰 볼륨이 권장 수준보다 높으며 이로 인해 청력 손상이 발생할 수 있습니다."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"접근성 기능 바로가기를 사용 설정하시겠습니까?"</string>
diff --git a/core/res/res/values-ky-watch/strings.xml b/core/res/res/values-ky-watch/strings.xml
index 4095282..df2b762 100644
--- a/core/res/res/values-ky-watch/strings.xml
+++ b/core/res/res/values-ky-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Сенсорлор"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Кырсыктаганда чалуу"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS системасын жаңыртуу"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo-watch/strings.xml b/core/res/res/values-lo-watch/strings.xml
index e83751a..d4804d3 100644
--- a/core/res/res/values-lo-watch/strings.xml
+++ b/core/res/res/values-lo-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ເຊັນເຊີ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS ສຸກເສີນ"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"ອັບເດດລະບົບ Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt-watch/strings.xml b/core/res/res/values-lt-watch/strings.xml
index bf6e92a..ba40587 100644
--- a/core/res/res/values-lt-watch/strings.xml
+++ b/core/res/res/values-lt-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Jutikliai"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Pagalbos iškv. kr. atv."</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"„Wear OS“ sistemos naujinys"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv-watch/strings.xml b/core/res/res/values-lv-watch/strings.xml
index e22f614..77817e9 100644
--- a/core/res/res/values-lv-watch/strings.xml
+++ b/core/res/res/values-lv-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Ārkārtas zvans"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS sistēmas atjauninājums"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk-watch/strings.xml b/core/res/res/values-mk-watch/strings.xml
index 7977f66..b2e4218 100644
--- a/core/res/res/values-mk-watch/strings.xml
+++ b/core/res/res/values-mk-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Сензори"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Итна помош"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Системско ажурирање на Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml-watch/strings.xml b/core/res/res/values-ml-watch/strings.xml
index 807f1a9..e543254 100644
--- a/core/res/res/values-ml-watch/strings.xml
+++ b/core/res/res/values-ml-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"സെൻസറുകൾ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"എമർജൻസി SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS സിസ്റ്റം അപ്ഡേറ്റ്"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn-watch/strings.xml b/core/res/res/values-mn-watch/strings.xml
index b00580f..d01f174 100644
--- a/core/res/res/values-mn-watch/strings.xml
+++ b/core/res/res/values-mn-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Мэдрэгч"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Яаралтай тусламж"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-н систем шинэчлэлт"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr-watch/strings.xml b/core/res/res/values-mr-watch/strings.xml
index 0bc7ad6..6092559 100644
--- a/core/res/res/values-mr-watch/strings.xml
+++ b/core/res/res/values-mr-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"सेन्सर"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"आणीबाणी SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS संबंधित सिस्टीम अपडेट"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms-watch/strings.xml b/core/res/res/values-ms-watch/strings.xml
index cadbbbd..b223c03 100644
--- a/core/res/res/values-ms-watch/strings.xml
+++ b/core/res/res/values-ms-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Penderia"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS Kecemasan"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Kemaskinian sistem Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my-watch/strings.xml b/core/res/res/values-my-watch/strings.xml
index c471b3831..b0f1809 100644
--- a/core/res/res/values-my-watch/strings.xml
+++ b/core/res/res/values-my-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"အာရုံခံကိရိယာများ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"အရေးပေါ် SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS စနစ် အပ်ဒိတ်လုပ်ခြင်း"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb-watch/strings.xml b/core/res/res/values-nb-watch/strings.xml
index fa296b6..6038976 100644
--- a/core/res/res/values-nb-watch/strings.xml
+++ b/core/res/res/values-nb-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorer"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS-alarm"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-systemoppdatering"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne-watch/strings.xml b/core/res/res/values-ne-watch/strings.xml
index 8c0df82..7f20abd 100644
--- a/core/res/res/values-ne-watch/strings.xml
+++ b/core/res/res/values-ne-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"सेन्सरहरू"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"आपत्कालीन सेवामा फोन गर्ने सुविधा"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS को सिस्टम अपडेट"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl-watch/strings.xml b/core/res/res/values-nl-watch/strings.xml
index 3f693a9..bdcaf42 100644
--- a/core/res/res/values-nl-watch/strings.xml
+++ b/core/res/res/values-nl-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensoren"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS-systeemupdate"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ae7d366..a4bedd3 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1689,8 +1689,8 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Verwijderen"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
- <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Wil je blijven luisteren op hoog volume?\n\nHet hoofdtelefoonvolume is langer dan de aanbevolen tijd hoog geweest, wat je gehoor kan beschadigen"</string>
- <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Hard geluid gedetecteerd\n\nHet hoofdtelefoonvolume is hoger dan aanbevolen, wat je gehoor kan beschadigen"</string>
+ <string name="csd_dose_reached_warning" product="default" msgid="491875107583931974">"Wil je blijven luisteren op hoog volume?\n\nHet hoofdtelefoonvolume is langer dan de aanbevolen tijd hoog geweest. Dit kan je gehoor beschadigen."</string>
+ <string name="csd_momentary_exposure_warning" product="default" msgid="7730840903435405501">"Hard geluid gedetecteerd\n\nHet hoofdtelefoonvolume is hoger dan aanbevolen. Dit kan je gehoor beschadigen."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling aanstaat, houd je beide volumeknoppen 3 seconden ingedrukt om een toegankelijkheidsfunctie te starten."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Snelkoppeling voor toegankelijkheidsfuncties aanzetten?"</string>
diff --git a/core/res/res/values-or-watch/strings.xml b/core/res/res/values-or-watch/strings.xml
index 8b11631..7fd7c19 100644
--- a/core/res/res/values-or-watch/strings.xml
+++ b/core/res/res/values-or-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ସେନ୍ସର୍"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ଜରୁରୀକାଳୀନ SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS ସିଷ୍ଟମ୍ ଅପଡେଟ୍"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa-watch/strings.xml b/core/res/res/values-pa-watch/strings.xml
index b1eb3a7..fd31f9b 100644
--- a/core/res/res/values-pa-watch/strings.xml
+++ b/core/res/res/values-pa-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"ਸੰੰਵੇਦਕ"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ਐਮਰਜੈਂਸੀ ਸਹਾਇਤਾ"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS ਸਿਸਟਮ ਅੱਪਡੇਟ"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl-watch/strings.xml b/core/res/res/values-pl-watch/strings.xml
index 2d81625..4f4b661 100644
--- a/core/res/res/values-pl-watch/strings.xml
+++ b/core/res/res/values-pl-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Czujniki"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Połączenie alarmowe"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Aktualizacja systemu Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR-watch/strings.xml b/core/res/res/values-pt-rBR-watch/strings.xml
index dea270b..e06a547 100644
--- a/core/res/res/values-pt-rBR-watch/strings.xml
+++ b/core/res/res/values-pt-rBR-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS de emergência"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Atualização do sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT-watch/strings.xml b/core/res/res/values-pt-rPT-watch/strings.xml
index dea270b..d828e37 100644
--- a/core/res/res/values-pt-rPT-watch/strings.xml
+++ b/core/res/res/values-pt-rPT-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Urgência SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Atualização do sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-watch/strings.xml b/core/res/res/values-pt-watch/strings.xml
index dea270b..e06a547 100644
--- a/core/res/res/values-pt-watch/strings.xml
+++ b/core/res/res/values-pt-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensores"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS de emergência"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Atualização do sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro-watch/strings.xml b/core/res/res/values-ro-watch/strings.xml
index da58726..27f926e 100644
--- a/core/res/res/values-ro-watch/strings.xml
+++ b/core/res/res/values-ro-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzori"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Apel de urgență"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Actualizare de sistem pentru Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru-watch/strings.xml b/core/res/res/values-ru-watch/strings.xml
index b8416c3..fc0d3b7 100644
--- a/core/res/res/values-ru-watch/strings.xml
+++ b/core/res/res/values-ru-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Датчики"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Экстренные вызовы"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Обновление Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si-watch/strings.xml b/core/res/res/values-si-watch/strings.xml
index bab95aa..0017070 100644
--- a/core/res/res/values-si-watch/strings.xml
+++ b/core/res/res/values-si-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"සංවේදක"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"හදිසි SOS උදවු"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS පද්ධති යාවත්කාලීනය"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk-watch/strings.xml b/core/res/res/values-sk-watch/strings.xml
index 6c9d718..790e424 100644
--- a/core/res/res/values-sk-watch/strings.xml
+++ b/core/res/res/values-sk-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Senzory"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Pomoc v tiesni"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Aktualizácia systému Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl-watch/strings.xml b/core/res/res/values-sl-watch/strings.xml
index 0afcaa3..1954f29 100644
--- a/core/res/res/values-sl-watch/strings.xml
+++ b/core/res/res/values-sl-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Tipala"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Nujni primer"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Posodobitev sistema Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq-watch/strings.xml b/core/res/res/values-sq-watch/strings.xml
index 093d3b1..a35d397 100644
--- a/core/res/res/values-sq-watch/strings.xml
+++ b/core/res/res/values-sq-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorët"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Thirrja e urgjencës"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Përditësimi i sistemit Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr-watch/strings.xml b/core/res/res/values-sr-watch/strings.xml
index 7977f66..edc4a8b 100644
--- a/core/res/res/values-sr-watch/strings.xml
+++ b/core/res/res/values-sr-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Сензори"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Хитна помоћ"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Ажурирање система за Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv-watch/strings.xml b/core/res/res/values-sv-watch/strings.xml
index fa296b6..d3afbf6 100644
--- a/core/res/res/values-sv-watch/strings.xml
+++ b/core/res/res/values-sv-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorer"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS-larm"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Systemuppdatering av Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw-watch/strings.xml b/core/res/res/values-sw-watch/strings.xml
index bf6b2c5..7c4d6970 100644
--- a/core/res/res/values-sw-watch/strings.xml
+++ b/core/res/res/values-sw-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Vihisi"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Vipengele vya Dharura"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Sasisho la mfumo wa Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta-watch/strings.xml b/core/res/res/values-ta-watch/strings.xml
index baaa696..342e46e 100644
--- a/core/res/res/values-ta-watch/strings.xml
+++ b/core/res/res/values-ta-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"உணர்விகள்"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"அவசர உதவி"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS சிஸ்டம் புதுப்பிப்பு"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te-watch/strings.xml b/core/res/res/values-te-watch/strings.xml
index 3a487bd..056733f 100644
--- a/core/res/res/values-te-watch/strings.xml
+++ b/core/res/res/values-te-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"సెన్సార్లు"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ఎమర్జెన్సీ సహాయం"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS సిస్టమ్ అప్డేట్"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th-watch/strings.xml b/core/res/res/values-th-watch/strings.xml
index bc4be24..37fbd63 100644
--- a/core/res/res/values-th-watch/strings.xml
+++ b/core/res/res/values-th-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"เซ็นเซอร์"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS ฉุกเฉิน"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"อัปเดตระบบ Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl-watch/strings.xml b/core/res/res/values-tl-watch/strings.xml
index 961cccf..2213858 100644
--- a/core/res/res/values-tl-watch/strings.xml
+++ b/core/res/res/values-tl-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Mga Sensor"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Emergency SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Pag-update ng system ng Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr-watch/strings.xml b/core/res/res/values-tr-watch/strings.xml
index 19add08..42c543d 100644
--- a/core/res/res/values-tr-watch/strings.xml
+++ b/core/res/res/values-tr-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensörler"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Acil Yardım"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS sistem güncellemesi"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk-watch/strings.xml b/core/res/res/values-uk-watch/strings.xml
index b8416c3..5bcd773 100644
--- a/core/res/res/values-uk-watch/strings.xml
+++ b/core/res/res/values-uk-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Датчики"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Екстрені виклики"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Оновлення системи Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur-watch/strings.xml b/core/res/res/values-ur-watch/strings.xml
index ec1089c..6d6c735 100644
--- a/core/res/res/values-ur-watch/strings.xml
+++ b/core/res/res/values-ur-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"سینسرز"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"ایمرجنسی SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS سسٹم اپ ڈیٹ"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz-watch/strings.xml b/core/res/res/values-uz-watch/strings.xml
index cf1b7a5..93bce9b 100644
--- a/core/res/res/values-uz-watch/strings.xml
+++ b/core/res/res/values-uz-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Sensorlar"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Favqulodda yordam"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS uchun tizim yangilanishi"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi-watch/strings.xml b/core/res/res/values-vi-watch/strings.xml
index 162a223..f4e17f3 100644
--- a/core/res/res/values-vi-watch/strings.xml
+++ b/core/res/res/values-vi-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Cảm biến"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"SOS khẩn cấp"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Bản cập nhật hệ thống Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN-watch/strings.xml b/core/res/res/values-zh-rCN-watch/strings.xml
index d047d8e..470544d 100644
--- a/core/res/res/values-zh-rCN-watch/strings.xml
+++ b/core/res/res/values-zh-rCN-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"传感器"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"紧急求救"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS 系统更新"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK-watch/strings.xml b/core/res/res/values-zh-rHK-watch/strings.xml
index 668061e..456f3cf 100644
--- a/core/res/res/values-zh-rHK-watch/strings.xml
+++ b/core/res/res/values-zh-rHK-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"感應器"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"緊急求救"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS 系統更新"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW-watch/strings.xml b/core/res/res/values-zh-rTW-watch/strings.xml
index 668061e..456f3cf 100644
--- a/core/res/res/values-zh-rTW-watch/strings.xml
+++ b/core/res/res/values-zh-rTW-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"感應器"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"緊急求救"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Wear OS 系統更新"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu-watch/strings.xml b/core/res/res/values-zu-watch/strings.xml
index a19d77f..edb0a6d 100644
--- a/core/res/res/values-zu-watch/strings.xml
+++ b/core/res/res/values-zu-watch/strings.xml
@@ -21,4 +21,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permgrouplab_sensors" msgid="2439544173324807471">"Izinzwa"</string>
+ <string name="global_action_emergency" msgid="2097576936362874627">"Isimo esiphuthumayo se-SOS"</string>
+ <!-- no translation found for reboot_to_update_prepare (4129802024411268230) -->
+ <skip />
+ <string name="reboot_to_update_title" msgid="8043761242418682803">"Isibuyekezo sesistimu ye-Wear OS"</string>
+ <!-- no translation found for select_input_method (1285150113084396451) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c0c6e05..30beee0 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -568,6 +568,10 @@
<color name="side_fps_button_color">#00677E</color>
<!-- Color for system bars -->
+ <color name="status_bar_compatible">@android:color/black</color>
+ <!-- This uses non-regular transparent intentionally. It is used to tell if the transparent
+ color is set by the framework or not. -->
+ <color name="status_bar_default">#00808080</color>
<color name="navigation_bar_compatible">@android:color/black</color>
<!-- This uses non-regular transparent intentionally. It is used to tell if the transparent
color is set by the framework or not. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e646548..8748ca1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3074,6 +3074,8 @@
<java-symbol type="bool" name="config_navBarDefaultTransparent" />
<java-symbol type="color" name="navigation_bar_default"/>
<java-symbol type="color" name="navigation_bar_compatible"/>
+ <java-symbol type="color" name="status_bar_default"/>
+ <java-symbol type="color" name="status_bar_compatible"/>
<!-- EditText suggestion popup. -->
<java-symbol type="id" name="suggestionWindowContainer" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bdbf96b..d5d67ab 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -190,7 +190,7 @@
<item name="windowTranslucentStatus">false</item>
<item name="windowTranslucentNavigation">false</item>
<item name="windowDrawsSystemBarBackgrounds">false</item>
- <item name="statusBarColor">@color/black</item>
+ <item name="statusBarColor">@color/status_bar_default</item>
<item name="navigationBarColor">@color/navigation_bar_default</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_action_bar</item>
<item name="windowContentTransitions">false</item>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 3a2e50a..709646b 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
<!-- Arab Emirates -->
- <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" />
+ <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214|6253" />
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -155,7 +155,7 @@
<shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
<!-- Israel: 4 digits, known premium codes listed -->
- <shortcode country="il" pattern="\\d{4}" premium="4422|4545" />
+ <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477" />
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
@@ -198,6 +198,9 @@
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
+ <!-- Namibia: 5 digits -->
+ <shortcode country="na" pattern="\\d{1,5}" free="40005" />
+
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 2993a0e..445ddf5 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -65,6 +65,7 @@
"device-time-shell-utils",
"testables",
"com.android.text.flags-aconfig-java",
+ "flag-junit",
],
libs: [
@@ -75,6 +76,7 @@
"framework",
"ext",
"framework-res",
+ "android.view.flags-aconfig-java",
],
jni_libs: [
"libpowermanagertest_jni",
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index 13ce253..2323527 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -96,13 +96,28 @@
assertEquals(othr, getSqlStatementType("-- cmt\n SE"));
assertEquals(othr, getSqlStatementType("WITH"));
- // Test the extended statement types.
+ // Verify that leading line-comments are skipped.
+ assertEquals(sel, getSqlStatementType("-- cmt\n SELECT"));
+ assertEquals(sel, getSqlStatementType("-- line 1\n-- line 2\n SELECT"));
+ assertEquals(sel, getSqlStatementType("-- line 1\nSELECT"));
+ // Verify that embedded comments do not confuse the scanner.
+ assertEquals(sel, getSqlStatementType("-- line 1\nSELECT\n-- line 3\n"));
- final int wit = STATEMENT_WITH;
- assertEquals(wit, getSqlStatementTypeExtended("WITH"));
+ // Verify that leading block-comments are skipped.
+ assertEquals(sel, getSqlStatementType("/* foo */SELECT"));
+ assertEquals(sel, getSqlStatementType("/* line 1\n line 2\n*/\nSELECT"));
+ assertEquals(sel, getSqlStatementType("/* UPDATE\nline 2*/\nSELECT"));
+ // Verify that embedded comment characters do not confuse the scanner.
+ assertEquals(sel, getSqlStatementType("/* Foo /* /* // ** */SELECT"));
- final int cmt = STATEMENT_COMMENT;
- assertEquals(cmt, getSqlStatementTypeExtended("-- cmt\n SELECT"));
+ // Mix it up with comment types
+ assertEquals(sel, getSqlStatementType("/* foo */ -- bar\n SELECT"));
+
+ // Test the extended statement types. Note that the STATEMENT_COMMENT type is not possible,
+ // since leading comments are skipped.
+
+ final int with = STATEMENT_WITH;
+ assertEquals(with, getSqlStatementTypeExtended("WITH"));
final int cre = STATEMENT_CREATE;
assertEquals(cre, getSqlStatementTypeExtended("CREATE TABLE t1 (i int)"));
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index 4ee987b..3fc08ee 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -39,9 +39,13 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Phaser;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -231,4 +235,116 @@
// This exception is expected.
}
}
+
+ /**
+ * Count the number of rows in the database <count> times. The answer must match <expected>
+ * every time. Any errors are reported back to the main thread through the <errors>
+ * array. The ticker forces the database reads to be interleaved with database operations from
+ * the sibling threads.
+ */
+ private void concurrentReadOnlyReader(SQLiteDatabase database, int count, long expected,
+ List<Throwable> errors, Phaser ticker) {
+
+ final String query = "--comment\nSELECT count(*) from t1";
+
+ try {
+ for (int i = count; i > 0; i--) {
+ ticker.arriveAndAwaitAdvance();
+ long r = DatabaseUtils.longForQuery(database, query, null);
+ if (r != expected) {
+ // The type of the exception is not important. Only the message matters.
+ throw new RuntimeException(
+ String.format("concurrentRead expected %d, got %d", expected, r));
+ }
+ }
+ } catch (Throwable t) {
+ errors.add(t);
+ } finally {
+ ticker.arriveAndDeregister();
+ }
+ }
+
+ /**
+ * Insert a new row <count> times. Any errors are reported back to the main thread through
+ * the <errors> array. The ticker forces the database reads to be interleaved with database
+ * operations from the sibling threads.
+ */
+ private void concurrentImmediateWriter(SQLiteDatabase database, int count,
+ List<Throwable> errors, Phaser ticker) {
+ database.beginTransaction();
+ try {
+ int n = 100;
+ for (int i = count; i > 0; i--) {
+ ticker.arriveAndAwaitAdvance();
+ database.execSQL(String.format("INSERT INTO t1 (i) VALUES (%d)", n++));
+ }
+ database.setTransactionSuccessful();
+ } catch (Throwable t) {
+ errors.add(t);
+ } finally {
+ database.endTransaction();
+ ticker.arriveAndDeregister();
+ }
+ }
+
+ /**
+ * This test verifies that a read-only transaction can be started, and it is deferred. A
+ * deferred transaction does not take a database locks until the database is accessed. This
+ * test verifies that the implicit connection selection process correctly identifies
+ * read-only transactions even when they are preceded by a comment.
+ */
+ @Test
+ public void testReadOnlyTransaction() throws Exception {
+ // Enable WAL for concurrent read and write transactions.
+ mDatabase.enableWriteAheadLogging();
+
+ // Create the t1 table and put some data in it.
+ mDatabase.beginTransaction();
+ try {
+ mDatabase.execSQL("CREATE TABLE t1 (i int);");
+ mDatabase.execSQL("INSERT INTO t1 (i) VALUES (2)");
+ mDatabase.execSQL("INSERT INTO t1 (i) VALUES (3)");
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+
+ // Threads install errors in this array.
+ final List<Throwable> errors = Collections.synchronizedList(new ArrayList<Throwable>());
+
+ // This forces the read and write threads to execute in a lock-step, round-robin fashion.
+ Phaser ticker = new Phaser(3);
+
+ // Create three threads that will perform transactions. One thread is a writer and two
+ // are readers. The intent is that the readers begin before the writer commits, so the
+ // readers always see a database with two rows.
+ Thread readerA = new Thread(() -> {
+ concurrentReadOnlyReader(mDatabase, 4, 2, errors, ticker);
+ });
+ Thread readerB = new Thread(() -> {
+ concurrentReadOnlyReader(mDatabase, 4, 2, errors, ticker);
+ });
+ Thread writerC = new Thread(() -> {
+ concurrentImmediateWriter(mDatabase, 4, errors, ticker);
+ });
+
+ readerA.start();
+ readerB.start();
+ writerC.start();
+
+ // All three threads should have completed. Give the total set 1s. The 10ms delay for
+ // the second and third threads is just a small, positive number.
+ readerA.join(1000);
+ assertFalse(readerA.isAlive());
+ readerB.join(10);
+ assertFalse(readerB.isAlive());
+ writerC.join(10);
+ assertFalse(writerC.isAlive());
+
+ // The writer added 4 rows to the database.
+ long r = DatabaseUtils.longForQuery(mDatabase, "SELECT count(*) from t1", null);
+ assertEquals(6, r);
+
+ assertTrue("ReadThread failed with errors: " + errors, errors.isEmpty());
+ }
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 40fd34e..e7117a7 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -17,6 +17,11 @@
package android.view;
import static android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR;
+import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
+import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
+import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
+import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -53,6 +58,7 @@
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -447,6 +453,129 @@
assertThat(result).isFalse();
}
+ /**
+ * Test the default values are properly set
+ */
+ @UiThreadTest
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_getDefaultValues() {
+ ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
+ sContext.getDisplayNoVerify());
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1);
+ }
+
+ /**
+ * Test the value of the frame rate cateogry based on the visibility of a view
+ * Invsible: FRAME_RATE_CATEGORY_NO_PREFERENCE
+ * Visible: FRAME_RATE_CATEGORY_NORMAL
+ */
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_voteFrameRateCategory_visibility() {
+ View view = new View(sContext);
+ attachViewToWindow(view);
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ sInstrumentation.runOnMainSync(() -> {
+ view.setVisibility(View.INVISIBLE);
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ });
+
+ sInstrumentation.runOnMainSync(() -> {
+ view.setVisibility(View.VISIBLE);
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NORMAL);
+ });
+ }
+
+ /**
+ * Test the value of the frame rate cateogry based on the size of a view.
+ * The current threshold value is 7% of the screen size
+ * <7%: FRAME_RATE_CATEGORY_LOW
+ */
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_voteFrameRateCategory_smallSize() {
+ View view = new View(sContext);
+ WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+ wmlp.width = 1;
+ wmlp.height = 1;
+
+ sInstrumentation.runOnMainSync(() -> {
+ WindowManager wm = sContext.getSystemService(WindowManager.class);
+ wm.addView(view, wmlp);
+ });
+ sInstrumentation.waitForIdleSync();
+
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ sInstrumentation.runOnMainSync(() -> {
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
+ });
+ }
+
+ /**
+ * Test the value of the frame rate cateogry based on the size of a view.
+ * The current threshold value is 7% of the screen size
+ * >=7% : FRAME_RATE_CATEGORY_NORMAL
+ */
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_voteFrameRateCategory_normalSize() {
+ View view = new View(sContext);
+ WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+ sInstrumentation.runOnMainSync(() -> {
+ WindowManager wm = sContext.getSystemService(WindowManager.class);
+ Display display = wm.getDefaultDisplay();
+ DisplayMetrics metrics = new DisplayMetrics();
+ display.getMetrics(metrics);
+ wmlp.width = (int) (metrics.widthPixels * 0.9);
+ wmlp.height = (int) (metrics.heightPixels * 0.9);
+ wm.addView(view, wmlp);
+ });
+ sInstrumentation.waitForIdleSync();
+
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ sInstrumentation.runOnMainSync(() -> {
+ view.invalidate();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
+ });
+ }
+
+ /**
+ * Test how values of the frame rate cateogry are aggregated.
+ * It should take the max value among all of the voted categories per frame.
+ */
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
+ View view = new View(sContext);
+ attachViewToWindow(view);
+ sInstrumentation.runOnMainSync(() -> {
+ ViewRootImpl viewRootImpl = view.getViewRootImpl();
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+ FRAME_RATE_CATEGORY_NO_PREFERENCE);
+ viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
+ viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
+ viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_HIGH);
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
+ viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
+ viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
+ assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
+ });
+ }
+
@Test
public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 69aa401..32186667 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -439,6 +439,8 @@
<permission name="android.permission.MANAGE_WIFI_NETWORK_SELECTION" />
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pSetWfdInfo -->
<permission name="android.permission.CONFIGURE_WIFI_DISPLAY" />
+ <!-- Permission required for CTS test - CtsThreadNetworkTestCases -->
+ <permission name="android.permission.THREAD_NETWORK_PRIVILEGED"/>
<!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
<!-- Permission required for CTS test - MusicRecognitionManagerTest -->
@@ -529,6 +531,7 @@
<permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
<!-- Permission required for CTS test IntentRedirectionTest -->
<permission name="android.permission.QUERY_CLONED_APPS"/>
+ <permission name="android.permission.GET_BINDING_UID_IMPORTANCE"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/framework-minus-apex-ravenwood-policies.txt b/framework-minus-apex-ravenwood-policies.txt
index 6bac58b..8e76fd2 100644
--- a/framework-minus-apex-ravenwood-policies.txt
+++ b/framework-minus-apex-ravenwood-policies.txt
@@ -1 +1,91 @@
# Ravenwood "policy" file for framework-minus-apex.
+
+# Collections
+class android.util.ArrayMap stubclass
+class android.util.ArraySet stubclass
+class android.util.LongSparseArray stubclass
+class android.util.SparseArrayMap stubclass
+class android.util.SparseArray stubclass
+class android.util.SparseBooleanArray stubclass
+class android.util.SparseIntArray stubclass
+class android.util.SparseLongArray stubclass
+class android.util.ContainerHelpers stubclass
+class android.util.EmptyArray stubclass
+class android.util.MapCollections stubclass
+
+# Logging
+class android.util.Log stubclass
+class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host
+class android.util.LogPrinter stubclass
+
+# String Manipulation
+class android.util.Printer stubclass
+class android.util.PrintStreamPrinter stubclass
+class android.util.PrintWriterPrinter stubclass
+class android.util.StringBuilderPrinter stubclass
+
+# Properties
+class android.util.Property stubclass
+class android.util.FloatProperty stubclass
+class android.util.IntProperty stubclass
+class android.util.NoSuchPropertyException stubclass
+class android.util.ReflectiveProperty stubclass
+
+# Exceptions
+class android.util.AndroidException stubclass
+class android.util.AndroidRuntimeException stubclass
+
+# JSON
+class android.util.JsonReader stubclass
+class android.util.JsonWriter stubclass
+class android.util.MalformedJsonException stubclass
+
+# Base64
+class android.util.Base64 stubclass
+class android.util.Base64DataException stubclass
+class android.util.Base64InputStream stubclass
+class android.util.Base64OutputStream stubclass
+
+# Data Holders
+class android.util.MutableFloat stubclass
+class android.util.MutableShort stubclass
+class android.util.MutableBoolean stubclass
+class android.util.MutableByte stubclass
+class android.util.MutableChar stubclass
+class android.util.MutableDouble stubclass
+class android.util.Pair stubclass
+class android.util.Range stubclass
+class android.util.Rational stubclass
+class android.util.Size stubclass
+class android.util.SizeF stubclass
+
+# Proto
+class android.util.proto.EncodedBuffer stubclass
+class android.util.proto.ProtoInputStream stubclass
+class android.util.proto.ProtoOutputStream stubclass
+class android.util.proto.ProtoParseException stubclass
+class android.util.proto.ProtoStream stubclass
+class android.util.proto.ProtoUtils stubclass
+class android.util.proto.WireTypeMismatchException stubclass
+
+# Misc
+class android.util.Dumpable stubclass
+class android.util.DebugUtils stubclass
+class android.util.UtilConfig stubclass
+class android.util.Patterns stubclass
+
+# Internals
+class com.android.internal.util.ArrayUtils stubclass
+ method newUnpaddedByteArray (I)[B @newUnpaddedByteArray$ravenwood
+ method newUnpaddedCharArray (I)[C @newUnpaddedCharArray$ravenwood
+ method newUnpaddedIntArray (I)[I @newUnpaddedIntArray$ravenwood
+ method newUnpaddedBooleanArray (I)[Z @newUnpaddedBooleanArray$ravenwood
+ method newUnpaddedLongArray (I)[J @newUnpaddedLongArray$ravenwood
+ method newUnpaddedFloatArray (I)[F @newUnpaddedFloatArray$ravenwood
+ method newUnpaddedObjectArray (I)[Ljava/lang/Object; @newUnpaddedObjectArray$ravenwood
+ method newUnpaddedArray (Ljava/lang/Class;I)[Ljava/lang/Object; @newUnpaddedArray$ravenwood
+
+class com.android.internal.util.GrowingArrayUtils stubclass
+class com.android.internal.util.LineBreakBufferedWriter stubclass
+class com.android.internal.util.Preconditions stubclass
+class com.android.internal.util.StringPool stubclass
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
index d2360e9..657720e 100644
--- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
@@ -21,7 +21,7 @@
<solid
android:color="?androidprv:attr/materialColorSurfaceContainerHigh"
/>
- <corners android:radius="20dp" />
+ <corners android:radius="18sp" />
<padding
android:left="20dp"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 55a9132..de9d2a2 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -185,10 +185,11 @@
<dimen name="bubble_pointer_overlap">1dp</dimen>
<!-- Extra padding around the dismiss target for bubbles -->
<dimen name="bubble_dismiss_slop">16dp</dimen>
- <!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">36dp</dimen>
- <!-- Height of manage button including margins. -->
- <dimen name="bubble_manage_button_total_height">68dp</dimen>
+ <!-- Height of button allowing users to adjust settings for bubbles. We use sp so that the
+ button can scale with the font size. -->
+ <dimen name="bubble_manage_button_height">36sp</dimen>
+ <!-- Touch area height of the manage button. -->
+ <dimen name="bubble_manage_button_touch_area_height">48dp</dimen>
<!-- The margin around the outside of the manage button. -->
<dimen name="bubble_manage_button_margin">16dp</dimen>
<!-- Height of an item in the bubble manage menu. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 0479576..b1b196d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -29,6 +29,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.LocusId;
@@ -700,7 +701,7 @@
@Override
public void onCameraControlStateUpdated(
- int taskId, @TaskInfo.CameraCompatControlState int state) {
+ int taskId, @AppCompatTaskInfo.CameraCompatControlState int state) {
final TaskAppearedInfo info;
synchronized (mLock) {
info = mTasks.get(taskId);
@@ -754,7 +755,7 @@
// The task is vanished or doesn't support compat UI, notify to remove compat UI
// on this Task if there is any.
if (taskListener == null || !taskListener.supportCompatUI()
- || !taskInfo.hasCompatUI() || !taskInfo.isVisible) {
+ || !taskInfo.appCompatTaskInfo.hasCompatUI() || !taskInfo.isVisible) {
mCompatUI.onCompatInfoChanged(taskInfo, null /* taskListener */);
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 5cf9175..8241e1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -136,6 +136,7 @@
/** Called on frame update. */
final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
+ mTransformation.clear();
// Extract the transformation to the current time.
mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
mTransformation);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 880579d..2ec9e8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -88,8 +88,6 @@
public static final PathInterpolator DIM_INTERPOLATOR =
new PathInterpolator(.23f, .87f, .52f, -0.11f);
- public static final Interpolator DECELERATE = new PathInterpolator(0f, 0f, 0.5f, 1f);
-
// Create the default emphasized interpolator
private static PathInterpolator createEmphasizedInterpolator() {
Path path = new Path();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 03c546d..5843635 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -61,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.ExternalInterfaceBinder;
@@ -99,6 +100,7 @@
* Max duration to wait for an animation to finish before triggering the real back.
*/
private static final long MAX_ANIMATION_DURATION = 2000;
+ private final LatencyTracker mLatencyTracker;
/** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false;
@@ -167,6 +169,7 @@
private final BackAnimationBackground mAnimationBackground;
private StatusBarCustomizer mCustomizer;
+ private boolean mTrackingLatency;
public BackAnimationController(
@NonNull ShellInit shellInit,
@@ -213,6 +216,7 @@
.setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
.build();
mShellBackAnimationRegistry = shellBackAnimationRegistry;
+ mLatencyTracker = LatencyTracker.getInstance(mContext);
}
private void onInit() {
@@ -438,6 +442,7 @@
private void startBackNavigation(@NonNull TouchTracker touchTracker) {
try {
+ startLatencyTracking();
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
mNavigationObserver, mEnableAnimations.get() ? mBackAnimationAdapter : null);
onBackNavigationInfoReceived(mBackNavigationInfo, touchTracker);
@@ -452,6 +457,7 @@
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
if (backNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
+ cancelLatencyTracking();
return;
}
final int backType = backNavigationInfo.getType();
@@ -462,6 +468,8 @@
}
} else {
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
+ // App is handling back animation. Cancel system animation latency tracking.
+ cancelLatencyTracking();
dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
}
}
@@ -808,12 +816,36 @@
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
mActiveCallback = null;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
+ cancelLatencyTracking();
if (mBackNavigationInfo != null) {
mBackNavigationInfo.onBackNavigationFinished(triggerBack);
mBackNavigationInfo = null;
}
}
+ private void startLatencyTracking() {
+ if (mTrackingLatency) {
+ cancelLatencyTracking();
+ }
+ mLatencyTracker.onActionStart(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = true;
+ }
+
+ private void cancelLatencyTracking() {
+ if (!mTrackingLatency) {
+ return;
+ }
+ mLatencyTracker.onActionCancel(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = false;
+ }
+
+ private void endLatencyTracking() {
+ if (!mTrackingLatency) {
+ return;
+ }
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_BACK_SYSTEM_ANIMATION);
+ mTrackingLatency = false;
+ }
private void createAdapter() {
IBackAnimationRunner runner =
@@ -826,6 +858,7 @@
IBackAnimationFinishedCallback finishedCallback) {
mShellExecutor.execute(
() -> {
+ endLatencyTracking();
if (mBackNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW,
"Lack of navigation info to start animation.");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 8ec297e..5a15674 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -89,7 +89,6 @@
private final PointF mInitialTouchPos = new PointF();
private final Interpolator mPostAnimationInterpolator = Interpolators.EMPHASIZED;
- private final Interpolator mYMovementInterpolator = Interpolators.DECELERATE;
private final Interpolator mProgressInterpolator = new DecelerateInterpolator();
private final Matrix mTransformMatrix = new Matrix();
@@ -164,7 +163,7 @@
float yDirection = rawYDelta < 0 ? -1 : 1;
// limit yDelta interpretation to 1/2 of screen height in either direction
float deltaYRatio = Math.min(height / 2f, Math.abs(rawYDelta)) / (height / 2f);
- float interpolatedYRatio = mYMovementInterpolator.getInterpolation(deltaYRatio);
+ float interpolatedYRatio = mProgressInterpolator.getInterpolation(deltaYRatio);
// limit y-shift so surface never passes 8dp screen margin
float deltaY = yDirection * interpolatedYRatio * Math.max(0f,
(height - scaledHeight) / 2f - mVerticalMargin);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
index 312e88d..dc65919 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
@@ -34,6 +34,9 @@
@Qualifier
public @interface ReturnToHome {}
+ @Qualifier
+ public @interface DialogClose {}
+
/** Retrieve the {@link BackAnimationRunner} associated with this animation. */
public abstract BackAnimationRunner getRunner();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
index 62b18f3..26d2097 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
@@ -33,17 +33,22 @@
public ShellBackAnimationRegistry(
@ShellBackAnimation.CrossActivity @Nullable ShellBackAnimation crossActivityAnimation,
@ShellBackAnimation.CrossTask @Nullable ShellBackAnimation crossTaskAnimation,
+ @ShellBackAnimation.DialogClose @Nullable ShellBackAnimation dialogCloseAnimation,
@ShellBackAnimation.CustomizeActivity @Nullable
ShellBackAnimation customizeActivityAnimation,
@ShellBackAnimation.ReturnToHome @Nullable
ShellBackAnimation defaultBackToHomeAnimation) {
if (crossActivityAnimation != null) {
mAnimationDefinition.set(
+ BackNavigationInfo.TYPE_CROSS_ACTIVITY, crossActivityAnimation.getRunner());
+ }
+ if (crossTaskAnimation != null) {
+ mAnimationDefinition.set(
BackNavigationInfo.TYPE_CROSS_TASK, crossTaskAnimation.getRunner());
}
- if (crossActivityAnimation != null) {
+ if (dialogCloseAnimation != null) {
mAnimationDefinition.set(
- BackNavigationInfo.TYPE_CROSS_ACTIVITY, crossActivityAnimation.getRunner());
+ BackNavigationInfo.TYPE_DIALOG_CLOSE, dialogCloseAnimation.getRunner());
}
if (defaultBackToHomeAnimation != null) {
mAnimationDefinition.set(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 0568eda..c7ab6aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -57,6 +57,7 @@
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
@@ -470,6 +471,17 @@
R.layout.bubble_manage_button, this /* parent */, false /* attach */);
addView(mManageButton);
mManageButton.setVisibility(visibility);
+ post(() -> {
+ int touchAreaHeight =
+ getResources().getDimensionPixelSize(
+ R.dimen.bubble_manage_button_touch_area_height);
+ Rect r = new Rect();
+ mManageButton.getHitRect(r);
+ int extraTouchArea = (touchAreaHeight - r.height()) / 2;
+ r.top -= extraTouchArea;
+ r.bottom += extraTouchArea;
+ setTouchDelegate(new TouchDelegate(r, mManageButton));
+ });
}
}
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 17e06e9..144c456 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
@@ -198,9 +198,10 @@
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
- mManageButtonHeightIncludingMargins =
- res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+ mManageButtonHeightIncludingMargins =
+ mManageButtonHeight
+ + 2 * res.getDimensionPixelSize(R.dimen.bubble_manage_button_margin);
mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 9402d02..87461dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1829,9 +1829,12 @@
}
bubble.cleanupViews(); // cleans up the icon view
updateExpandedView(); // resets state for no expanded bubble
+ mExpandedBubble = null;
});
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
+ } else if (getBubbleCount() == 1) {
+ mExpandedBubble = null;
}
// Remove it from the views
for (int i = 0; i < getBubbleCount(); i++) {
@@ -2420,14 +2423,13 @@
mExpandedAnimationController.notifyPreparingToCollapse();
updateOverflowDotVisibility(false /* expanding */);
- final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(
- mStackAnimationController
- .getStackPositionAlongNearestHorizontalEdge()
- /* collapseTo */,
- () -> {
- mBubbleContainer.setActiveController(mStackAnimationController);
- updateOverflowVisibility();
- });
+ final Runnable collapseBackToStack = () ->
+ mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
+ () -> {
+ mBubbleContainer.setActiveController(mStackAnimationController);
+ updateOverflowVisibility();
+ });
final Runnable after = () -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 953efa7..86571cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -20,8 +20,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -239,7 +239,7 @@
*/
public void onCompatInfoChanged(@NonNull TaskInfo taskInfo,
@Nullable ShellTaskOrganizer.TaskListener taskListener) {
- if (taskInfo != null && !taskInfo.topActivityInSizeCompat) {
+ if (taskInfo != null && !taskInfo.appCompatTaskInfo.topActivityInSizeCompat) {
mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
}
@@ -267,7 +267,7 @@
}
return;
}
- if (!taskInfo.isFromLetterboxDoubleTap) {
+ if (!taskInfo.appCompatTaskInfo.isFromLetterboxDoubleTap) {
createOrUpdateUserAspectRatioSettingsLayout(taskInfo, taskListener);
}
}
@@ -348,7 +348,8 @@
// as they are still relevant. Else, if the activity is visible and focused (the one the
// user can see and is using), the user aspect ratio button can potentially be displayed so
// start tracking the buttons visibility for this task.
- if (mTopActivityTaskId != taskInfo.taskId && !taskInfo.isTopActivityTransparent
+ if (mTopActivityTaskId != taskInfo.taskId
+ && !taskInfo.isTopActivityTransparent
&& taskInfo.isVisible && taskInfo.isFocused) {
mTopActivityTaskId = taskInfo.taskId;
setHasShownUserAspectRatioSettingsButton(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
index d44b4d8..a0986fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
@@ -16,9 +16,10 @@
package com.android.wm.shell.compatui;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+
import android.annotation.IdRes;
-import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
@@ -57,10 +58,10 @@
}
void updateCameraTreatmentButton(@CameraCompatControlState int newState) {
- int buttonBkgId = newState == TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED
+ int buttonBkgId = newState == CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED
? R.drawable.camera_compat_treatment_suggested_ripple
: R.drawable.camera_compat_treatment_applied_ripple;
- int hintStringId = newState == TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED
+ int hintStringId = newState == CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED
? R.string.camera_compat_treatment_suggested_button_description
: R.string.camera_compat_treatment_applied_button_description;
final ImageButton button = findViewById(R.id.camera_compat_treatment_button);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index ce3c509..00e0cdb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -16,15 +16,15 @@
package com.android.wm.shell.compatui;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
import android.annotation.Nullable;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
@@ -75,8 +75,8 @@
Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
mCallback = callback;
- mHasSizeCompat = taskInfo.topActivityInSizeCompat;
- mCameraCompatControlState = taskInfo.cameraCompatControlState;
+ mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
+ mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;
mCompatUIHintsState = compatUIHintsState;
mCompatUIConfiguration = compatUIConfiguration;
mOnRestartButtonClicked = onRestartButtonClicked;
@@ -127,8 +127,8 @@
boolean canShow) {
final boolean prevHasSizeCompat = mHasSizeCompat;
final int prevCameraCompatControlState = mCameraCompatControlState;
- mHasSizeCompat = taskInfo.topActivityInSizeCompat;
- mCameraCompatControlState = taskInfo.cameraCompatControlState;
+ mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
+ mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;
if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
index fce1a39..623fead 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
@@ -103,7 +103,8 @@
R.dimen.letterbox_education_dialog_margin);
mDockStateReader = dockStateReader;
mCompatUIConfiguration = compatUIConfiguration;
- mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
+ mEligibleForLetterboxEducation =
+ taskInfo.appCompatTaskInfo.topActivityEligibleForLetterboxEducation;
}
@Override
@@ -204,7 +205,8 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
- mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
+ mEligibleForLetterboxEducation =
+ taskInfo.appCompatTaskInfo.topActivityEligibleForLetterboxEducation;
return super.updateCompatInfo(taskInfo, taskListener, canShow);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
index 5612bc8..835f1af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
@@ -21,6 +21,7 @@
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;
import android.annotation.Nullable;
+import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Rect;
@@ -89,11 +90,12 @@
BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> onDismissCallback,
Function<Integer, Integer> disappearTimeSupplier) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
- mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
- mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
- mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition;
- mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth;
- mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight;
+ final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
+ mIsActivityLetterboxed = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
+ mLetterboxVerticalPosition = appCompatTaskInfo.topActivityLetterboxVerticalPosition;
+ mLetterboxHorizontalPosition = appCompatTaskInfo.topActivityLetterboxHorizontalPosition;
+ mTopActivityLetterboxWidth = appCompatTaskInfo.topActivityLetterboxWidth;
+ mTopActivityLetterboxHeight = appCompatTaskInfo.topActivityLetterboxHeight;
mCompatUIConfiguration = compatUIConfiguration;
mMainExecutor = mainExecutor;
mOnDismissCallback = onDismissCallback;
@@ -145,12 +147,13 @@
final int prevLetterboxHorizontalPosition = mLetterboxHorizontalPosition;
final int prevTopActivityLetterboxWidth = mTopActivityLetterboxWidth;
final int prevTopActivityLetterboxHeight = mTopActivityLetterboxHeight;
- mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
- mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
- mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition;
- mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth;
- mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight;
- mHasUserDoubleTapped = taskInfo.isFromLetterboxDoubleTap;
+ final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
+ mIsActivityLetterboxed = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
+ mLetterboxVerticalPosition = appCompatTaskInfo.topActivityLetterboxVerticalPosition;
+ mLetterboxHorizontalPosition = appCompatTaskInfo.topActivityLetterboxHorizontalPosition;
+ mTopActivityLetterboxWidth = appCompatTaskInfo.topActivityLetterboxWidth;
+ mTopActivityLetterboxHeight = appCompatTaskInfo.topActivityLetterboxHeight;
+ mHasUserDoubleTapped = appCompatTaskInfo.isFromLetterboxDoubleTap;
if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index c2dec62..ef763ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -227,9 +227,9 @@
}
private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
- return taskInfo.topActivityEligibleForUserAspectRatioButton
- && (taskInfo.topActivityBoundsLetterboxed
- || taskInfo.isUserFullscreenOverrideEnabled)
+ return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton
+ && (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
+ || taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled)
&& (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 64294c9..54cf84c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -646,11 +646,12 @@
@Provides
static KeyguardTransitionHandler provideKeyguardTransitionHandler(
ShellInit shellInit,
+ ShellController shellController,
Transitions transitions,
@ShellMainThread Handler mainHandler,
@ShellMainThread ShellExecutor mainExecutor) {
return new KeyguardTransitionHandler(
- shellInit, transitions, mainHandler, mainExecutor);
+ shellInit, shellController, transitions, mainHandler, mainExecutor);
}
@WMSingleton
@@ -837,10 +838,12 @@
// Use optional-of-lazy for the dependency that this provider relies on.
// Lazy ensures that this provider will not be the cause the dependency is created
// when it will not be returned due to the condition below.
- if (DesktopModeStatus.isEnabled()) {
- return desktopTasksController.map(Lazy::get);
- }
- return Optional.empty();
+ return desktopTasksController.flatMap((lazy)-> {
+ if (DesktopModeStatus.isEnabled()) {
+ return Optional.of(lazy.get());
+ }
+ return Optional.empty();
+ });
}
@BindsOptionalOf
@@ -854,10 +857,12 @@
// Use optional-of-lazy for the dependency that this provider relies on.
// Lazy ensures that this provider will not be the cause the dependency is created
// when it will not be returned due to the condition below.
- if (DesktopModeStatus.isEnabled()) {
- return desktopModeTaskRepository.map(Lazy::get);
- }
- return Optional.empty();
+ return desktopModeTaskRepository.flatMap((lazy)-> {
+ if (DesktopModeStatus.isEnabled()) {
+ return Optional.of(lazy.get());
+ }
+ return Optional.empty();
+ });
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
index b34c6b2..3be7d97 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
@@ -38,6 +38,7 @@
return new ShellBackAnimationRegistry(
crossActivity,
crossTask,
+ /* dialogCloseAnimation */ null,
customizeActivity,
/* defaultBackToHomeAnimation= */ null);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 53b5bd7..0890861 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -22,6 +22,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.view.WindowManager.TRANSIT_SLEEP;
@@ -49,6 +50,8 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
@@ -58,10 +61,12 @@
*
* <p>This takes the highest priority.
*/
-public class KeyguardTransitionHandler implements Transitions.TransitionHandler {
+public class KeyguardTransitionHandler
+ implements Transitions.TransitionHandler, KeyguardChangeListener {
private static final String TAG = "KeyguardTransition";
private final Transitions mTransitions;
+ private final ShellController mShellController;
private final Handler mMainHandler;
private final ShellExecutor mMainExecutor;
@@ -80,6 +85,9 @@
// transition.
private boolean mIsLaunchingActivityOverLockscreen;
+ // Last value reported by {@link KeyguardChangeListener}.
+ private boolean mKeyguardShowing = true;
+
private final class StartedTransition {
final TransitionInfo mInfo;
final SurfaceControl.Transaction mFinishT;
@@ -92,12 +100,15 @@
mPlayer = player;
}
}
+
public KeyguardTransitionHandler(
@NonNull ShellInit shellInit,
+ @NonNull ShellController shellController,
@NonNull Transitions transitions,
@NonNull Handler mainHandler,
@NonNull ShellExecutor mainExecutor) {
mTransitions = transitions;
+ mShellController = shellController;
mMainHandler = mainHandler;
mMainExecutor = mainExecutor;
shellInit.addInitCallback(this::onInit, this);
@@ -105,6 +116,7 @@
private void onInit() {
mTransitions.addHandler(this);
+ mShellController.addKeyguardChangeListener(this);
}
/**
@@ -120,6 +132,16 @@
}
@Override
+ public void onKeyguardVisibilityChanged(
+ boolean visible, boolean occluded, boolean animatingDismiss) {
+ mKeyguardShowing = visible;
+ }
+
+ public boolean isKeyguardShowing() {
+ return mKeyguardShowing;
+ }
+
+ @Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -134,24 +156,28 @@
"going-away",
transition, info, startTransaction, finishTransaction, finishCallback);
}
- if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_OCCLUDING) != 0) {
- if (hasOpeningDream(info)) {
- return startAnimation(mOccludeByDreamTransition,
- "occlude-by-dream",
- transition, info, startTransaction, finishTransaction, finishCallback);
- } else {
- return startAnimation(mOccludeTransition,
- "occlude",
+
+ // Occlude/unocclude animations are only played if the keyguard is locked.
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_OCCLUDING) != 0) {
+ if (hasOpeningDream(info)) {
+ return startAnimation(mOccludeByDreamTransition,
+ "occlude-by-dream",
+ transition, info, startTransaction, finishTransaction, finishCallback);
+ } else {
+ return startAnimation(mOccludeTransition,
+ "occlude",
+ transition, info, startTransaction, finishTransaction, finishCallback);
+ }
+ } else if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
+ return startAnimation(mUnoccludeTransition,
+ "unocclude",
transition, info, startTransaction, finishTransaction, finishCallback);
}
- } else if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
- return startAnimation(mUnoccludeTransition,
- "unocclude",
- transition, info, startTransaction, finishTransaction, finishCallback);
- } else {
- Log.i(TAG, "Refused to play keyguard transition: " + info);
- return false;
}
+
+ Log.i(TAG, "Refused to play keyguard transition: " + info);
+ return false;
}
private boolean startAnimation(IRemoteTransition remoteHandler, String description,
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 c20d23e..271a3b2 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
@@ -64,6 +64,7 @@
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Handles the Recents (overview) animation. Only one of these can run at a time. A recents
@@ -130,21 +131,21 @@
wct.sendPendingIntent(intent, fillIn, options);
final RecentsController controller = new RecentsController(listener);
RecentsMixedHandler mixer = null;
- Transitions.TransitionHandler mixedHandler = null;
+ Consumer<IBinder> setTransitionForMixer = null;
for (int i = 0; i < mMixers.size(); ++i) {
- mixedHandler = mMixers.get(i).handleRecentsRequest(wct);
- if (mixedHandler != null) {
+ setTransitionForMixer = mMixers.get(i).handleRecentsRequest(wct);
+ if (setTransitionForMixer != null) {
mixer = mMixers.get(i);
break;
}
}
final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct,
- mixedHandler == null ? this : mixedHandler);
+ mixer == null ? this : mixer);
for (int i = 0; i < mStateListeners.size(); i++) {
mStateListeners.get(i).onTransitionStarted(transition);
}
if (mixer != null) {
- mixer.setRecentsTransition(transition);
+ setTransitionForMixer.accept(transition);
}
if (transition != null) {
controller.setTransition(transition);
@@ -589,6 +590,13 @@
cancel("transit_sleep");
return;
}
+ if (mKeyguardLocked) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "[%d] RecentsController.merge: keyguard is locked", mInstanceId);
+ // We will not accept new changes if we are swiping over the keyguard.
+ cancel(true /* toHome */, false /* withScreenshots */, "keyguard_locked");
+ return;
+ }
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.merge", mInstanceId);
// Keep all tasks in one list because order matters.
@@ -1105,22 +1113,17 @@
* An interface for a mixed handler to receive information about recents requests (since these
* come into this handler directly vs from WMCore request).
*/
- public interface RecentsMixedHandler {
+ public interface RecentsMixedHandler extends Transitions.TransitionHandler {
/**
* Called when a recents request comes in. The handler can add operations to outWCT. If
- * the handler wants to "accept" the transition, it should return itself; otherwise, it
- * should return `null`.
+ * the handler wants to "accept" the transition, it should return a Consumer accepting the
+ * IBinder for the transition. If not, it should return `null`.
*
* If a mixed-handler accepts this recents, it will be the de-facto handler for this
* transition and is required to call the associated {@link #startAnimation},
* {@link #mergeAnimation}, and {@link #onTransitionConsumed} methods.
*/
- Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT);
-
- /**
- * Reports the transition token associated with the accepted recents request. If there was
- * a problem starting the request, this will be called with `null`.
- */
- void setRecentsTransition(@Nullable IBinder transition);
+ @Nullable
+ Consumer<IBinder> handleRecentsRequest(WindowContainerTransaction outWCT);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 918a5a4..ce7fef2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -37,11 +38,13 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.os.IBinder;
+import android.util.ArrayMap;
import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.protolog.common.ProtoLog;
@@ -61,7 +64,9 @@
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
+import java.util.Map;
import java.util.Optional;
+import java.util.function.Consumer;
/**
* A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -79,7 +84,7 @@
private UnfoldTransitionHandler mUnfoldHandler;
private ActivityEmbeddingController mActivityEmbeddingController;
- private static class MixedTransition {
+ private class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
/** Both the display and split-state (enter/exit) is changing */
@@ -94,14 +99,17 @@
/** Keyguard exit/occlude/unocclude transition. */
static final int TYPE_KEYGUARD = 5;
+ /** Recents transition on top of the lock screen. */
+ static final int TYPE_RECENTS_DURING_KEYGUARD = 6;
+
/** Recents Transition while in desktop mode. */
- static final int TYPE_RECENTS_DURING_DESKTOP = 6;
+ static final int TYPE_RECENTS_DURING_DESKTOP = 7;
/** Fold/Unfold transition. */
- static final int TYPE_UNFOLD = 7;
+ static final int TYPE_UNFOLD = 8;
/** Enter pip from one of the Activity Embedding windows. */
- static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 8;
+ static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 9;
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -117,7 +125,10 @@
final IBinder mTransition;
Transitions.TransitionHandler mLeftoversHandler = null;
+ TransitionInfo mInfo = null;
WindowContainerTransaction mFinishWCT = null;
+ SurfaceControl.Transaction mFinishT = null;
+ Transitions.TransitionFinishCallback mFinishCB = null;
/**
* Whether the transition has request for remote transition while mLeftoversHandler
@@ -138,6 +149,37 @@
mTransition = transition;
}
+ boolean startSubAnimation(Transitions.TransitionHandler handler, TransitionInfo info,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
+ if (mInfo != null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "startSubAnimation #%d.%d", mInfo.getDebugId(), info.getDebugId());
+ }
+ mInFlightSubAnimations++;
+ if (!handler.startAnimation(
+ mTransition, info, startT, finishT, wct -> onSubAnimationFinished(info, wct))) {
+ mInFlightSubAnimations--;
+ return false;
+ }
+ return true;
+ }
+
+ void onSubAnimationFinished(TransitionInfo info, WindowContainerTransaction wct) {
+ mInFlightSubAnimations--;
+ if (mInfo != null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "onSubAnimationFinished #%d.%d remaining=%d",
+ mInfo.getDebugId(), info.getDebugId(), mInFlightSubAnimations);
+ }
+
+ joinFinishArgs(wct);
+
+ if (mInFlightSubAnimations == 0) {
+ mActiveTransitions.remove(MixedTransition.this);
+ mFinishCB.onTransitionFinished(mFinishWCT);
+ }
+ }
+
void joinFinishArgs(WindowContainerTransaction wct) {
if (wct != null) {
if (mFinishWCT == null) {
@@ -271,39 +313,46 @@
}
@Override
- public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
+ public Consumer<IBinder> handleRecentsRequest(WindowContainerTransaction outWCT) {
if (mRecentsHandler != null) {
if (mSplitHandler.isSplitScreenVisible()) {
- return this;
+ return this::setRecentsTransitionDuringSplit;
+ } else if (mKeyguardHandler.isKeyguardShowing()) {
+ return this::setRecentsTransitionDuringKeyguard;
} else if (mDesktopTasksController != null
// Check on the default display. Recents/gesture nav is only available there
&& mDesktopTasksController.getVisibleTaskCount(DEFAULT_DISPLAY) > 0) {
- return this;
+ return this::setRecentsTransitionDuringDesktop;
}
}
return null;
}
- @Override
- public void setRecentsTransition(IBinder transition) {
- if (mSplitHandler.isSplitScreenVisible()) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
- + "Split-Screen is foreground, so treat it as Mixed.");
- final MixedTransition mixed = new MixedTransition(
- MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
- mixed.mLeftoversHandler = mRecentsHandler;
- mActiveTransitions.add(mixed);
- } else if (DesktopModeStatus.isEnabled()) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
- + "desktop mode is active, so treat it as Mixed.");
- final MixedTransition mixed = new MixedTransition(
- MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
- mixed.mLeftoversHandler = mRecentsHandler;
- mActiveTransitions.add(mixed);
- } else {
- throw new IllegalStateException("Accepted a recents transition but don't know how to"
- + " handle it");
- }
+ private void setRecentsTransitionDuringSplit(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "Split-Screen is foreground, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
+ }
+
+ private void setRecentsTransitionDuringKeyguard(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "keyguard is visible, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
+ }
+
+ private void setRecentsTransitionDuringDesktop(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
+ + "desktop mode is active, so treat it as Mixed.");
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition);
+ mixed.mLeftoversHandler = mRecentsHandler;
+ mActiveTransitions.add(mixed);
}
private TransitionInfo subCopy(@NonNull TransitionInfo info,
@@ -410,6 +459,9 @@
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
return animateKeyguard(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) {
+ return animateRecentsDuringKeyguard(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction,
finishCallback);
@@ -764,24 +816,28 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct) -> {
- mixed.mInFlightSubAnimations--;
- if (mixed.mInFlightSubAnimations == 0) {
- mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct);
- }
- };
- mixed.mInFlightSubAnimations++;
+ if (mixed.mFinishT == null) {
+ mixed.mFinishT = finishTransaction;
+ mixed.mFinishCB = finishCallback;
+ }
// Sync pip state.
if (mPipHandler != null) {
mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
}
- if (!mKeyguardHandler.startAnimation(
- mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
- mixed.mInFlightSubAnimations--;
- return false;
+ return mixed.startSubAnimation(mKeyguardHandler, info, startTransaction, finishTransaction);
+ }
+
+ private boolean animateRecentsDuringKeyguard(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ if (mixed.mInfo == null) {
+ mixed.mInfo = info;
+ mixed.mFinishT = finishTransaction;
+ mixed.mFinishCB = finishCallback;
}
- return true;
+ return mixed.startSubAnimation(mRecentsHandler, info, startTransaction, finishTransaction);
}
private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed,
@@ -905,6 +961,15 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) {
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
+ handoverTransitionLeashes(mixed, info, t, mixed.mFinishT);
+ if (animateKeyguard(mixed, info, t, mixed.mFinishT, mixed.mFinishCB)) {
+ finishCallback.onTransitionFinished(null);
+ }
+ }
+ mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
finishCallback);
@@ -947,4 +1012,38 @@
mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, aborted, finishT);
}
}
+
+ /**
+ * Update an incoming {@link TransitionInfo} with the leashes from an ongoing
+ * {@link MixedTransition} so that it can take over some parts of the animation without
+ * reparenting to new transition roots.
+ */
+ private static void handoverTransitionLeashes(@NonNull MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT) {
+
+ // Show the roots in case they contain new changes not present in the original transition.
+ for (int j = info.getRootCount() - 1; j >= 0; --j) {
+ startT.show(info.getRoot(j).getLeash());
+ }
+
+ // Find all of the leashes from the original transition.
+ Map<WindowContainerToken, TransitionInfo.Change> originalChanges = new ArrayMap<>();
+ for (TransitionInfo.Change oldChange : mixed.mInfo.getChanges()) {
+ if (oldChange.getContainer() != null) {
+ originalChanges.put(oldChange.getContainer(), oldChange);
+ }
+ }
+
+ // Merge the animation leashes by re-using the original ones if we see the same container
+ // in the new transition and the old.
+ for (TransitionInfo.Change newChange : info.getChanges()) {
+ if (originalChanges.containsKey(newChange.getContainer())) {
+ final TransitionInfo.Change oldChange = originalChanges.get(newChange.getContainer());
+ startT.reparent(newChange.getLeash(), null);
+ newChange.setLeash(oldChange.getLeash());
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 030f601..4355ed2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -83,7 +83,6 @@
mMainExecutor.execute(() -> {
finishCallback.onTransitionFinished(wct);
});
- Log.d("b/302551868", "OneShotRemoteHandler#start remote anim null");
mRemote = null;
}
};
@@ -107,7 +106,6 @@
mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
}
finishCallback.onTransitionFinished(null /* wct */);
- Log.d("b/302551868", "OneShotRemoteHandler#exception remote anim null");
mRemote = null;
}
return true;
@@ -127,7 +125,6 @@
// so just assume the worst-case and clear the local transaction.
t.clear();
mMainExecutor.execute(() -> finishCallback.onTransitionFinished(wct));
- Log.d("b/302551868", "OneShotRemoteHandler#merge remote anim null");
mRemote = null;
}
};
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index 1941d66..652a2ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -70,8 +70,8 @@
private int mMarginMenuStart;
private int mMenuHeight;
private int mMenuWidth;
-
private final int mCaptionHeight;
+ private HandleMenuAnimator mHandleMenuAnimator;
HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY,
@@ -111,20 +111,19 @@
mHandleMenuWindow = mParentDecor.addWindow(
R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu",
t, ssg, x, y, mMenuWidth, mMenuHeight);
+ final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView();
+ mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight);
}
/**
* Animates the appearance of the handle menu and its three pills.
*/
private void animateHandleMenu() {
- final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView();
- final HandleMenuAnimator handleMenuAnimator = new HandleMenuAnimator(handleMenuView,
- mMenuWidth, mCaptionHeight);
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
|| mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
- handleMenuAnimator.animateCaptionHandleExpandToOpen();
+ mHandleMenuAnimator.animateCaptionHandleExpandToOpen();
} else {
- handleMenuAnimator.animateOpen();
+ mHandleMenuAnimator.animateOpen();
}
}
@@ -328,8 +327,16 @@
}
void close() {
- mHandleMenuWindow.releaseView();
- mHandleMenuWindow = null;
+ final Runnable after = () -> {
+ mHandleMenuWindow.releaseView();
+ mHandleMenuWindow = null;
+ };
+ if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
+ mHandleMenuAnimator.animateCollapseIntoHandleClose(after);
+ } else {
+ mHandleMenuAnimator.animateClose(after);
+ }
}
static final class Builder {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
index 531de1f..8c5d4a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt
@@ -26,6 +26,7 @@
import android.view.View.TRANSLATION_Y
import android.view.View.TRANSLATION_Z
import android.view.ViewGroup
+import androidx.core.animation.doOnEnd
import androidx.core.view.children
import com.android.wm.shell.R
import com.android.wm.shell.animation.Interpolators
@@ -37,27 +38,36 @@
private val captionHeight: Float
) {
companion object {
- private const val MENU_Y_TRANSLATION_DURATION: Long = 150
- private const val HEADER_NONFREEFORM_SCALE_DURATION: Long = 150
- private const val HEADER_FREEFORM_SCALE_DURATION: Long = 217
- private const val HEADER_ELEVATION_DURATION: Long = 83
- private const val HEADER_CONTENT_ALPHA_DURATION: Long = 100
- private const val BODY_SCALE_DURATION: Long = 180
- private const val BODY_ALPHA_DURATION: Long = 150
- private const val BODY_ELEVATION_DURATION: Long = 83
- private const val BODY_CONTENT_ALPHA_DURATION: Long = 167
+ // Open animation constants
+ private const val MENU_Y_TRANSLATION_OPEN_DURATION: Long = 150
+ private const val HEADER_NONFREEFORM_SCALE_OPEN_DURATION: Long = 150
+ private const val HEADER_FREEFORM_SCALE_OPEN_DURATION: Long = 217
+ private const val HEADER_ELEVATION_OPEN_DURATION: Long = 83
+ private const val HEADER_CONTENT_ALPHA_OPEN_DURATION: Long = 100
+ private const val BODY_SCALE_OPEN_DURATION: Long = 180
+ private const val BODY_ALPHA_OPEN_DURATION: Long = 150
+ private const val BODY_ELEVATION_OPEN_DURATION: Long = 83
+ private const val BODY_CONTENT_ALPHA_OPEN_DURATION: Long = 167
- private const val ELEVATION_DELAY: Long = 33
- private const val HEADER_CONTENT_ALPHA_DELAY: Long = 67
- private const val BODY_SCALE_DELAY: Long = 50
- private const val BODY_ALPHA_DELAY: Long = 133
+ private const val ELEVATION_OPEN_DELAY: Long = 33
+ private const val HEADER_CONTENT_ALPHA_OPEN_DELAY: Long = 67
+ private const val BODY_SCALE_OPEN_DELAY: Long = 50
+ private const val BODY_ALPHA_OPEN_DELAY: Long = 133
private const val HALF_INITIAL_SCALE: Float = 0.5f
private const val NONFREEFORM_HEADER_INITIAL_SCALE_X: Float = 0.6f
private const val NONFREEFORM_HEADER_INITIAL_SCALE_Y: Float = 0.05f
+
+ // Close animation constants
+ private const val HEADER_CLOSE_DELAY: Long = 20
+ private const val HEADER_CLOSE_DURATION: Long = 50
+ private const val HEADER_CONTENT_OPACITY_CLOSE_DELAY: Long = 25
+ private const val HEADER_CONTENT_OPACITY_CLOSE_DURATION: Long = 25
+ private const val BODY_CLOSE_DURATION: Long = 50
}
private val animators: MutableList<Animator> = mutableListOf()
+ private var runningAnimation: AnimatorSet? = null
private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill)
private val windowingPill: ViewGroup = handleMenu.requireViewById(R.id.windowing_pill)
@@ -67,9 +77,9 @@
fun animateOpen() {
prepareMenuForAnimation()
appInfoPillExpand()
- animateAppInfoPill()
- animateWindowingPill()
- animateMoreActionsPill()
+ animateAppInfoPillOpen()
+ animateWindowingPillOpen()
+ animateMoreActionsPillOpen()
runAnimations()
}
@@ -81,13 +91,44 @@
fun animateCaptionHandleExpandToOpen() {
prepareMenuForAnimation()
captionHandleExpandIntoAppInfoPill()
- animateAppInfoPill()
- animateWindowingPill()
- animateMoreActionsPill()
+ animateAppInfoPillOpen()
+ animateWindowingPillOpen()
+ animateMoreActionsPillOpen()
runAnimations()
}
/**
+ * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then,
+ * the app info pill will collapse into the shape of the caption handle in full screen and split
+ * screen.
+ *
+ * @param after runs after the animation finishes.
+ */
+ fun animateCollapseIntoHandleClose(after: Runnable) {
+ appInfoCollapseToHandle()
+ animateAppInfoPillFadeOut()
+ windowingPillClose()
+ moreActionsPillClose()
+ runAnimations(after)
+ }
+
+ /**
+ * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then,
+ * the app info pill will collapse into the shape of the caption handle in full screen and split
+ * screen.
+ *
+ * @param after runs after animation finishes.
+ *
+ */
+ fun animateClose(after: Runnable) {
+ appInfoPillCollapse()
+ animateAppInfoPillFadeOut()
+ windowingPillClose()
+ moreActionsPillClose()
+ runAnimations(after)
+ }
+
+ /**
* Prepares the handle menu for animation. Presets the opacity of necessary menu components.
* Presets pivots of handle menu and body pills for scaling animation.
*/
@@ -108,20 +149,20 @@
moreActionsPill.pivotY = appInfoPill.measuredHeight.toFloat()
}
- private fun animateAppInfoPill() {
+ private fun animateAppInfoPillOpen() {
// Header Elevation Animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = HEADER_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = HEADER_ELEVATION_OPEN_DURATION
}
// Content Opacity Animation
appInfoPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = HEADER_CONTENT_ALPHA_DELAY
- duration = HEADER_CONTENT_ALPHA_DURATION
+ startDelay = HEADER_CONTENT_ALPHA_OPEN_DELAY
+ duration = HEADER_CONTENT_ALPHA_OPEN_DURATION
}
}
}
@@ -130,17 +171,17 @@
// Header scaling animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X, 1f)
- .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION }
+ .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION }
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y, 1f)
- .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION }
+ .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION }
// Downward y-translation animation
val yStart: Float = -captionHeight / 2
animators +=
ObjectAnimator.ofFloat(handleMenu, TRANSLATION_Y, yStart, 0f).apply {
- duration = MENU_Y_TRANSLATION_DURATION
+ duration = MENU_Y_TRANSLATION_OPEN_DURATION
}
}
@@ -148,98 +189,217 @@
// Header scaling animation
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- duration = HEADER_FREEFORM_SCALE_DURATION
+ duration = HEADER_FREEFORM_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- duration = HEADER_FREEFORM_SCALE_DURATION
+ duration = HEADER_FREEFORM_SCALE_OPEN_DURATION
}
}
- private fun animateWindowingPill() {
+ private fun animateWindowingPillOpen() {
// Windowing X & Y Scaling Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
// Windowing Opacity Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_ALPHA_OPEN_DURATION
}
// Windowing Elevation Animation
animators +=
ObjectAnimator.ofFloat(windowingPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = BODY_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = BODY_ELEVATION_OPEN_DURATION
}
// Windowing Content Opacity Animation
windowingPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_CONTENT_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_CONTENT_ALPHA_OPEN_DURATION
interpolator = Interpolators.FAST_OUT_SLOW_IN
}
}
}
- private fun animateMoreActionsPill() {
+ private fun animateMoreActionsPillOpen() {
// More Actions X & Y Scaling Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
animators +=
ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply {
- startDelay = BODY_SCALE_DELAY
- duration = BODY_SCALE_DURATION
+ startDelay = BODY_SCALE_OPEN_DELAY
+ duration = BODY_SCALE_OPEN_DURATION
}
// More Actions Opacity Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_ALPHA_OPEN_DURATION
}
// More Actions Elevation Animation
animators +=
ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Z, 1f).apply {
- startDelay = ELEVATION_DELAY
- duration = BODY_ELEVATION_DURATION
+ startDelay = ELEVATION_OPEN_DELAY
+ duration = BODY_ELEVATION_OPEN_DURATION
}
// More Actions Content Opacity Animation
moreActionsPill.children.forEach {
animators +=
ObjectAnimator.ofFloat(it, ALPHA, 1f).apply {
- startDelay = BODY_ALPHA_DELAY
- duration = BODY_CONTENT_ALPHA_DURATION
+ startDelay = BODY_ALPHA_OPEN_DELAY
+ duration = BODY_CONTENT_ALPHA_OPEN_DURATION
interpolator = Interpolators.FAST_OUT_SLOW_IN
}
}
}
- /** Runs the list of animators concurrently. */
- private fun runAnimations() {
- val animatorSet = AnimatorSet()
- animatorSet.playTogether(animators)
- animatorSet.start()
- animators.clear()
+ private fun appInfoPillCollapse() {
+ // Header scaling animation
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_X, 0f).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, 0f).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ }
+
+ private fun appInfoCollapseToHandle() {
+ // Header X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ // Upward y-translation animation
+ val yStart: Float = -captionHeight / 2
+ animators +=
+ ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Y, yStart).apply {
+ startDelay = HEADER_CLOSE_DELAY
+ duration = HEADER_CLOSE_DURATION
+ }
+ }
+
+ private fun animateAppInfoPillFadeOut() {
+ // Header Content Opacity Animation
+ appInfoPill.children.forEach {
+ animators +=
+ ObjectAnimator.ofFloat(it, ALPHA, 0f).apply {
+ startDelay = HEADER_CONTENT_OPACITY_CLOSE_DELAY
+ duration = HEADER_CONTENT_OPACITY_CLOSE_DURATION
+ }
+ }
+ }
+
+ private fun windowingPillClose() {
+ // Windowing X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // windowing Animation
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+ }
+
+ private fun moreActionsPillClose() {
+ // More Actions X & Y Scaling Animation
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // More Actions Opacity Animation
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+
+ // upward more actions pill y-translation animation
+ val yStart: Float = -captionHeight / 2
+ animators +=
+ ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Y, yStart).apply {
+ duration = BODY_CLOSE_DURATION
+ }
+ }
+
+ /**
+ * Runs the list of hide animators concurrently.
+ *
+ * @param after runs after animation finishes.
+ */
+ private fun runAnimations(after: Runnable? = null) {
+ runningAnimation?.apply {
+ // Remove all listeners, so that after runnable isn't triggered upon cancel.
+ removeAllListeners()
+ // If an animation runs while running animation is triggered, gracefully cancel.
+ cancel()
+ }
+
+ runningAnimation = AnimatorSet().apply {
+ playTogether(animators)
+ animators.clear()
+ doOnEnd {
+ after?.run()
+ runningAnimation = null
+ }
+ start()
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 081c8ae..9c1a88e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -16,6 +16,10 @@
package com.android.wm.shell;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -40,7 +44,6 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.TaskInfo;
import android.content.LocusId;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -356,7 +359,7 @@
public void testOnSizeCompatActivityChanged() {
final RunningTaskInfo taskInfo1 = createTaskInfo(12, WINDOWING_MODE_FULLSCREEN);
taskInfo1.displayId = DEFAULT_DISPLAY;
- taskInfo1.topActivityInSizeCompat = false;
+ taskInfo1.appCompatTaskInfo.topActivityInSizeCompat = false;
final TrackingTaskListener taskListener = new TrackingTaskListener();
mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN);
mOrganizer.onTaskAppeared(taskInfo1, null);
@@ -369,7 +372,7 @@
final RunningTaskInfo taskInfo2 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo2.displayId = taskInfo1.displayId;
- taskInfo2.topActivityInSizeCompat = true;
+ taskInfo2.appCompatTaskInfo.topActivityInSizeCompat = true;
taskInfo2.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo2);
verify(mCompatUI).onCompatInfoChanged(taskInfo2, taskListener);
@@ -379,7 +382,7 @@
final RunningTaskInfo taskInfo3 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo3.displayId = taskInfo1.displayId;
- taskInfo3.topActivityInSizeCompat = true;
+ taskInfo3.appCompatTaskInfo.topActivityInSizeCompat = true;
taskInfo3.isVisible = false;
mOrganizer.onTaskInfoChanged(taskInfo3);
verify(mCompatUI).onCompatInfoChanged(taskInfo3, null /* taskListener */);
@@ -393,7 +396,7 @@
public void testOnEligibleForLetterboxEducationActivityChanged() {
final RunningTaskInfo taskInfo1 = createTaskInfo(12, WINDOWING_MODE_FULLSCREEN);
taskInfo1.displayId = DEFAULT_DISPLAY;
- taskInfo1.topActivityEligibleForLetterboxEducation = false;
+ taskInfo1.appCompatTaskInfo.topActivityEligibleForLetterboxEducation = false;
final TrackingTaskListener taskListener = new TrackingTaskListener();
mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN);
mOrganizer.onTaskAppeared(taskInfo1, null);
@@ -408,7 +411,7 @@
final RunningTaskInfo taskInfo2 =
createTaskInfo(taskInfo1.taskId, WINDOWING_MODE_FULLSCREEN);
taskInfo2.displayId = taskInfo1.displayId;
- taskInfo2.topActivityEligibleForLetterboxEducation = true;
+ taskInfo2.appCompatTaskInfo.topActivityEligibleForLetterboxEducation = true;
taskInfo2.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo2);
verify(mCompatUI).onCompatInfoChanged(taskInfo2, taskListener);
@@ -418,7 +421,7 @@
final RunningTaskInfo taskInfo3 =
createTaskInfo(taskInfo1.taskId, WINDOWING_MODE_FULLSCREEN);
taskInfo3.displayId = taskInfo1.displayId;
- taskInfo3.topActivityEligibleForLetterboxEducation = true;
+ taskInfo3.appCompatTaskInfo.topActivityEligibleForLetterboxEducation = true;
taskInfo3.isVisible = false;
mOrganizer.onTaskInfoChanged(taskInfo3);
verify(mCompatUI).onCompatInfoChanged(taskInfo3, null /* taskListener */);
@@ -432,7 +435,7 @@
public void testOnCameraCompatActivityChanged() {
final RunningTaskInfo taskInfo1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN);
taskInfo1.displayId = DEFAULT_DISPLAY;
- taskInfo1.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+ taskInfo1.appCompatTaskInfo.cameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
final TrackingTaskListener taskListener = new TrackingTaskListener();
mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN);
mOrganizer.onTaskAppeared(taskInfo1, null);
@@ -446,7 +449,8 @@
final RunningTaskInfo taskInfo2 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo2.displayId = taskInfo1.displayId;
- taskInfo2.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+ taskInfo2.appCompatTaskInfo.cameraCompatControlState =
+ CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
taskInfo2.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo2);
verify(mCompatUI).onCompatInfoChanged(taskInfo2, taskListener);
@@ -457,7 +461,8 @@
final RunningTaskInfo taskInfo3 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo3.displayId = taskInfo1.displayId;
- taskInfo3.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+ taskInfo3.appCompatTaskInfo.cameraCompatControlState =
+ CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
taskInfo3.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo3);
verify(mCompatUI).onCompatInfoChanged(taskInfo3, taskListener);
@@ -468,8 +473,9 @@
final RunningTaskInfo taskInfo4 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo4.displayId = taskInfo1.displayId;
- taskInfo4.topActivityInSizeCompat = true;
- taskInfo4.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+ taskInfo4.appCompatTaskInfo.topActivityInSizeCompat = true;
+ taskInfo4.appCompatTaskInfo.cameraCompatControlState =
+ CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
taskInfo4.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo4);
verify(mCompatUI).onCompatInfoChanged(taskInfo4, taskListener);
@@ -479,7 +485,8 @@
final RunningTaskInfo taskInfo5 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo5.displayId = taskInfo1.displayId;
- taskInfo5.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+ taskInfo5.appCompatTaskInfo.cameraCompatControlState =
+ CAMERA_COMPAT_CONTROL_DISMISSED;
taskInfo5.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo5);
verify(mCompatUI).onCompatInfoChanged(taskInfo5, null /* taskListener */);
@@ -489,7 +496,8 @@
final RunningTaskInfo taskInfo6 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo6.displayId = taskInfo1.displayId;
- taskInfo6.cameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+ taskInfo6.appCompatTaskInfo.cameraCompatControlState =
+ CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
taskInfo6.isVisible = false;
mOrganizer.onTaskInfoChanged(taskInfo6);
verify(mCompatUI).onCompatInfoChanged(taskInfo6, null /* taskListener */);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 6cf5450..a67fd37 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -132,8 +132,9 @@
new ShellBackAnimationRegistry(
new CrossActivityAnimation(mContext, mAnimationBackground),
new CrossTaskBackAnimation(mContext, mAnimationBackground),
+ /* dialogCloseAnimation= */ null,
new CustomizeActivityAnimation(mContext, mAnimationBackground),
- null);
+ /* defaultBackToHomeAnimation= */ null);
mController =
new BackAnimationController(
mShellInit,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index f85d707..fef81af 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -16,8 +16,8 @@
package com.android.wm.shell.compatui;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -34,8 +34,8 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.content.Context;
import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
@@ -688,8 +688,8 @@
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.displayId = displayId;
- taskInfo.topActivityInSizeCompat = hasSizeCompat;
- taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
+ taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
taskInfo.isVisible = isVisible;
taskInfo.isFocused = isFocused;
taskInfo.isTopActivityTransparent = isTopActivityTransparent;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index 3bce2b8..23a4e39 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -16,10 +16,10 @@
package com.android.wm.shell.compatui;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -28,8 +28,8 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.testing.AndroidTestingRunner;
import android.util.Pair;
import android.view.LayoutInflater;
@@ -219,8 +219,8 @@
@CameraCompatControlState int cameraCompatControlState) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
- taskInfo.topActivityInSizeCompat = hasSizeCompat;
- taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
+ taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 4c837e6..d4b97ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -16,10 +16,10 @@
package com.android.wm.shell.compatui;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
+import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -464,11 +465,11 @@
}
private static TaskInfo createTaskInfo(boolean hasSizeCompat,
- @TaskInfo.CameraCompatControlState int cameraCompatControlState) {
+ @AppCompatTaskInfo.CameraCompatControlState int cameraCompatControlState) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
- taskInfo.topActivityInSizeCompat = hasSizeCompat;
- taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
+ taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
return taskInfo;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
index 9200b3c9..a60a1cb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
@@ -477,7 +477,7 @@
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.userId = userId;
taskInfo.taskId = TASK_ID;
- taskInfo.topActivityEligibleForLetterboxEducation = eligible;
+ taskInfo.appCompatTaskInfo.topActivityEligibleForLetterboxEducation = eligible;
taskInfo.configuration.windowConfiguration.setBounds(bounds);
return taskInfo;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
index f460d1b..38d6ea1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
@@ -16,7 +16,7 @@
package com.android.wm.shell.compatui;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -25,8 +25,8 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.content.ComponentName;
import android.testing.AndroidTestingRunner;
import android.util.Pair;
@@ -147,8 +147,8 @@
@CameraCompatControlState int cameraCompatControlState) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
- taskInfo.topActivityInSizeCompat = hasSizeCompat;
- taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat;
+ taskInfo.appCompatTaskInfo.cameraCompatControlState = cameraCompatControlState;
taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
return taskInfo;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
index 5a4d6c8..0652939 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -381,8 +381,9 @@
boolean topActivityBoundsLetterboxed) {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.taskId = TASK_ID;
- taskInfo.topActivityEligibleForUserAspectRatioButton = eligibleForUserAspectRatioButton;
- taskInfo.topActivityBoundsLetterboxed = topActivityBoundsLetterboxed;
+ taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton =
+ eligibleForUserAspectRatioButton;
+ taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed = topActivityBoundsLetterboxed;
taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK;
taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity");
return taskInfo;
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index ef4dce5..caffdfc 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -17,18 +17,18 @@
#ifndef ANDROID_GRAPHICS_PAINT_H_
#define ANDROID_GRAPHICS_PAINT_H_
+#include "Typeface.h"
+
+#include <cutils/compiler.h>
+
#include <SkFont.h>
#include <SkPaint.h>
#include <SkSamplingOptions.h>
-#include <cutils/compiler.h>
-#include <minikin/FamilyVariant.h>
-#include <minikin/FontFamily.h>
-#include <minikin/FontFeature.h>
-#include <minikin/Hyphenator.h>
-
#include <string>
-#include "Typeface.h"
+#include <minikin/FontFamily.h>
+#include <minikin/FamilyVariant.h>
+#include <minikin/Hyphenator.h>
namespace android {
@@ -82,15 +82,11 @@
float getWordSpacing() const { return mWordSpacing; }
- void setFontFeatureSettings(std::string_view fontFeatures) {
- mFontFeatureSettings = minikin::FontFeature::parse(fontFeatures);
+ void setFontFeatureSettings(const std::string& fontFeatureSettings) {
+ mFontFeatureSettings = fontFeatureSettings;
}
- void resetFontFeatures() { mFontFeatureSettings.clear(); }
-
- const std::vector<minikin::FontFeature>& getFontFeatureSettings() const {
- return mFontFeatureSettings;
- }
+ std::string getFontFeatureSettings() const { return mFontFeatureSettings; }
void setMinikinLocaleListId(uint32_t minikinLocaleListId) {
mMinikinLocaleListId = minikinLocaleListId;
@@ -174,7 +170,7 @@
float mLetterSpacing = 0;
float mWordSpacing = 0;
- std::vector<minikin::FontFeature> mFontFeatureSettings;
+ std::string mFontFeatureSettings;
uint32_t mMinikinLocaleListId;
std::optional<minikin::FamilyVariant> mFamilyVariant;
uint32_t mHyphenEdit = 0;
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index d84b73d..8c71d6f 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -33,7 +33,6 @@
#include <cassert>
#include <cstring>
#include <memory>
-#include <string_view>
#include <vector>
#include "ColorFilter.h"
@@ -691,11 +690,10 @@
jstring settings) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
if (!settings) {
- paint->resetFontFeatures();
+ paint->setFontFeatureSettings(std::string());
} else {
ScopedUtfChars settingsChars(env, settings);
- paint->setFontFeatureSettings(
- std::string_view(settingsChars.c_str(), settingsChars.size()));
+ paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
}
}
diff --git a/location/api/lint-baseline.txt b/location/api/lint-baseline.txt
new file mode 100644
index 0000000..5e3ef01
--- /dev/null
+++ b/location/api/lint-baseline.txt
@@ -0,0 +1,27 @@
+// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
diff --git a/location/api/module-lib-lint-baseline.txt b/location/api/module-lib-lint-baseline.txt
index 7cd6a86..3b1be7db 100644
--- a/location/api/module-lib-lint-baseline.txt
+++ b/location/api/module-lib-lint-baseline.txt
@@ -1,4 +1,36 @@
// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#injectGnssMeasurementCorrections(android.location.GnssMeasurementCorrections):
+ Method 'injectGnssMeasurementCorrections' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+
+
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
diff --git a/location/api/system-lint-baseline.txt b/location/api/system-lint-baseline.txt
index 043a082..066a40a 100644
--- a/location/api/system-lint-baseline.txt
+++ b/location/api/system-lint-baseline.txt
@@ -1,4 +1,36 @@
// Baseline format: 1.0
+RequiresPermission: android.location.LocationManager#addGpsStatusListener(android.location.GpsStatus.Listener):
+ Method 'addGpsStatusListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addNmeaListener(java.util.concurrent.Executor, android.location.OnNmeaMessageListener):
+ Method 'addNmeaListener' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#addProximityAlert(double, double, float, long, android.app.PendingIntent):
+ Method 'addProximityAlert' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#injectGnssMeasurementCorrections(android.location.GnssMeasurementCorrections):
+ Method 'injectGnssMeasurementCorrections' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(android.location.GnssRequest, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
+ Method 'registerGnssMeasurementsCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
+ Method 'registerGnssNavigationMessageCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
+ Method 'registerGnssStatusCallback' documentation mentions permissions already declared by @RequiresPermission
+
+
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index 48cd8b6..c9a8864 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -26,6 +26,7 @@
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "frameworks-base-testutils",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"testng",
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index 4952e01..774de5f 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -16,7 +16,11 @@
package android.media.projection;
+import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
+
+import android.annotation.EnforcePermission;
import android.os.IBinder;
+import android.os.PermissionEnforcer;
import android.os.RemoteException;
/**
@@ -28,6 +32,10 @@
IBinder mLaunchCookie = null;
IMediaProjectionCallback mIMediaProjectionCallback = null;
+ FakeIMediaProjection(PermissionEnforcer enforcer) {
+ super(enforcer);
+ }
+
@Override
public void start(IMediaProjectionCallback callback) throws RemoteException {
mIMediaProjectionCallback = callback;
@@ -56,7 +64,9 @@
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public int applyVirtualDisplayFlags(int flags) throws RemoteException {
+ applyVirtualDisplayFlags_enforcePermission();
return 0;
}
@@ -69,22 +79,30 @@
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public IBinder getLaunchCookie() throws RemoteException {
+ getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void setLaunchCookie(IBinder launchCookie) throws RemoteException {
+ setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public boolean isValid() throws RemoteException {
+ isValid_enforcePermission();
return true;
}
@Override
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void notifyVirtualDisplayCreated(int displayId) throws RemoteException {
+ notifyVirtualDisplayCreated_enforcePermission();
}
}
diff --git a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
index 2a5674e..2e0396f 100644
--- a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
+++ b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
@@ -16,7 +16,7 @@
package android.media.projection;
-
+import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
import static android.media.projection.MediaProjection.MEDIA_PROJECTION_REQUIRES_CALLBACK;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -42,6 +42,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
import android.view.Display;
@@ -80,7 +81,7 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
// Fake the connection to the system server.
- private final FakeIMediaProjection mFakeIMediaProjection = new FakeIMediaProjection();
+ private FakeIMediaProjection mFakeIMediaProjection;
// Callback registered by an app.
private MediaProjection mMediaProjection;
@@ -112,7 +113,10 @@
.strictness(Strictness.LENIENT)
.startMocking();
+ FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+ permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION);
// Support the MediaProjection instance.
+ mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer);
mFakeIMediaProjection.setLaunchCookie(mock(IBinder.class));
mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection,
mDisplayManager);
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 4f50ef5..889d7c8 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -45,7 +45,7 @@
<string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
<string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓「<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>」<strong></strong>的應用程式沿用在「<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>」<strong></strong>上的權限嗎?"</string>
- <string name="permission_sync_summary" msgid="765497944331294275">"這可能包括 <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> 的<strong>麥克風</strong>、<strong>相機</strong>和<strong>位置資訊存取權</strong>以及機密權限。<br/><br/>你隨時可透過 <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> 的「設定」變更這些權限。"</string>
+ <string name="permission_sync_summary" msgid="765497944331294275">"這可能包括 <strong><xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g></strong> 的<strong>麥克風</strong>、<strong>相機</strong>和<strong>位置資訊存取權</strong>以及私密資訊權限。<br/><br/>你隨時可透過 <strong><xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g></strong> 的「設定」變更這些權限。"</string>
<string name="vendor_header_button_description" msgid="7994879208461111473">"更多資訊"</string>
<string name="permission_phone" msgid="2661081078692784919">"電話"</string>
<string name="permission_sms" msgid="6337141296535774786">"簡訊"</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 81cbd5a..281696d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -50,6 +50,7 @@
import com.android.credentialmanager.GetFlowUtils
import com.android.credentialmanager.getflow.CredentialEntryInfo
import com.android.credentialmanager.getflow.ProviderDisplayInfo
+import com.android.credentialmanager.getflow.ProviderInfo
import com.android.credentialmanager.getflow.toProviderDisplayInfo
import org.json.JSONObject
import java.util.concurrent.Executors
@@ -155,6 +156,31 @@
}
val entryIconMap: Map<String, Icon> =
getEntryToIconMap(getCredResponse.candidateProviderDataList)
+ val autofillIdToProvidersMap: Map<AutofillId, List<ProviderInfo>> =
+ mapAutofillIdToProviders(providerList)
+ val fillResponseBuilder = FillResponse.Builder()
+ var validFillResponse = false
+ autofillIdToProvidersMap.forEach { (autofillId, providers) ->
+ validFillResponse = processProvidersForAutofillId(
+ filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder)
+ .or(validFillResponse)
+ }
+ if (!validFillResponse) {
+ return null
+ }
+ return fillResponseBuilder.build()
+ }
+
+ private fun processProvidersForAutofillId(
+ filLRequest: FillRequest,
+ autofillId: AutofillId,
+ providerList: List<ProviderInfo>,
+ entryIconMap: Map<String, Icon>,
+ fillResponseBuilder: FillResponse.Builder
+ ): Boolean {
+ if (providerList.isEmpty()) {
+ return false
+ }
var totalEntryCount = 0
providerList.forEach { provider ->
totalEntryCount += provider.credentialEntryList.size
@@ -169,77 +195,145 @@
maxItemCount = maxItemCount.coerceAtMost(inlineMaxSuggestedCount)
}
var i = 0
- val fillResponseBuilder = FillResponse.Builder()
- var emptyFillResponse = true
+ var datasetAdded = false
providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
val primaryEntry = it.sortedCredentialEntryList.first()
- // In regular CredMan bottomsheet, only one primary entry per username is displayed.
- // But since the credential requests from different fields are allocated into a single
- // request for autofill, there will be duplicate primary entries, especially for
- // username/pw autofill fields. These primary entries will be the same entries except
- // their autofillIds will point to different autofill fields. Process all primary
- // fields.
- // TODO(b/307435163): Merge credential options
- it.sortedCredentialEntryList.forEach entryLoop@ { credentialEntry ->
- if (!isSameCredentialEntry(primaryEntry, credentialEntry)) {
- // Encountering different credential entry means all the duplicate primary
- // entries have been processed.
- return@usernameLoop
- }
- val autofillId: AutofillId? = credentialEntry
- .fillInIntent
- ?.getParcelableExtra(
- CredentialProviderService.EXTRA_AUTOFILL_ID,
- AutofillId::class.java)
- val pendingIntent = credentialEntry.pendingIntent
- if (autofillId == null || pendingIntent == null) {
- Log.e(TAG, "AutofillId or pendingIntent was missing from the entry.")
- return@entryLoop
- }
- var inlinePresentation: InlinePresentation? = null
- // Create inline presentation
- if (inlinePresentationSpecs != null && i < maxItemCount) {
- val spec: InlinePresentationSpec
- if (i < inlinePresentationSpecsCount) {
- spec = inlinePresentationSpecs[i]
- } else {
- spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
- }
- val sliceBuilder = InlineSuggestionUi
- .newContentBuilder(pendingIntent)
- .setTitle(credentialEntry.userName)
- val icon: Icon =
- entryIconMap[credentialEntry.entryKey + credentialEntry.entrySubkey]
- ?: getDefaultIcon()
- sliceBuilder.setStartIcon(icon)
- inlinePresentation = InlinePresentation(
- sliceBuilder.build().slice, spec, /* pinned= */ false)
- }
- i++
+ val pendingIntent = primaryEntry.pendingIntent
+ if (pendingIntent == null || primaryEntry.fillInIntent == null) {
+ // FillInIntent will not be null because autofillId was retrieved from it.
+ Log.e(TAG, "PendingIntent was missing from the entry.")
+ return@usernameLoop
+ }
+ if (inlinePresentationSpecs == null || i >= maxItemCount) {
+ Log.e(TAG, "Skipping because reached the max item count.")
+ return@usernameLoop
+ }
+ // Create inline presentation
+ val spec: InlinePresentationSpec
+ if (i < inlinePresentationSpecsCount) {
+ spec = inlinePresentationSpecs[i]
+ } else {
+ spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
+ }
+ val sliceBuilder = InlineSuggestionUi
+ .newContentBuilder(pendingIntent)
+ .setTitle(primaryEntry.userName)
+ val icon: Icon
+ if (primaryEntry.icon == null) {
+ // The empty entry icon has non-null icon reference but null drawable reference.
+ // If the drawable reference is null, then use the default icon.
+ icon = getDefaultIcon()
+ } else {
+ icon = entryIconMap[primaryEntry.entryKey + primaryEntry.entrySubkey]
+ ?: getDefaultIcon()
+ }
+ sliceBuilder.setStartIcon(icon)
+ val inlinePresentation = InlinePresentation(
+ sliceBuilder.build().slice, spec, /* pinned= */ false)
+ i++
- val dataSetBuilder = Dataset.Builder()
- val presentationBuilder = Presentations.Builder()
- if (inlinePresentation != null) {
- presentationBuilder.setInlinePresentation(inlinePresentation)
- }
- fillResponseBuilder.addDataset(
- dataSetBuilder
- .setField(
- autofillId,
- Field.Builder().setPresentations(
- presentationBuilder.build())
- .build())
- .setAuthentication(pendingIntent.intentSender)
- .setAuthenticationExtras(credentialEntry.fillInIntent.extras)
- .build())
- emptyFillResponse = false
+ val dataSetBuilder = Dataset.Builder()
+ val presentationBuilder = Presentations.Builder()
+ .setInlinePresentation(inlinePresentation)
+
+ fillResponseBuilder.addDataset(
+ dataSetBuilder
+ .setField(
+ autofillId,
+ Field.Builder().setPresentations(
+ presentationBuilder.build())
+ .build())
+ .setAuthentication(pendingIntent.intentSender)
+ .setAuthenticationExtras(primaryEntry.fillInIntent.extras)
+ .build())
+ datasetAdded = true
+ }
+ return datasetAdded
+ }
+
+ /**
+ * Maps Autofill Id to provider list. For example, passing in a provider info
+ *
+ * ProviderInfo {
+ * id1,
+ * displayName1
+ * [entry1(autofillId1), entry2(autofillId2), entry3(autofillId3)],
+ * ...
+ * }
+ *
+ * will result in
+ *
+ * { autofillId1: ProviderInfo {
+ * id1,
+ * displayName1,
+ * [entry1(autofillId1)],
+ * ...
+ * }, autofillId2: ProviderInfo {
+ * id1,
+ * displayName1,
+ * [entry2(autofillId2)],
+ * ...
+ * }, autofillId3: ProviderInfo {
+ * id1,
+ * displayName1,
+ * [entry3(autofillId3)],
+ * ...
+ * }
+ * }
+ */
+ private fun mapAutofillIdToProviders(
+ providerList: List<ProviderInfo>
+ ): Map<AutofillId, List<ProviderInfo>> {
+ val autofillIdToProviders: MutableMap<AutofillId, MutableList<ProviderInfo>> =
+ mutableMapOf()
+ providerList.forEach { provider ->
+ val autofillIdToCredentialEntries:
+ MutableMap<AutofillId, MutableList<CredentialEntryInfo>> =
+ mapAutofillIdToCredentialEntries(provider.credentialEntryList)
+ autofillIdToCredentialEntries.forEach { (autofillId, entries) ->
+ autofillIdToProviders.getOrPut(autofillId) { mutableListOf() }
+ .add(copyProviderInfo(provider, entries))
}
}
- if (emptyFillResponse) {
- return null
+ return autofillIdToProviders
+ }
+
+ private fun mapAutofillIdToCredentialEntries(
+ credentialEntryList: List<CredentialEntryInfo>
+ ): MutableMap<AutofillId, MutableList<CredentialEntryInfo>> {
+ val autofillIdToCredentialEntries:
+ MutableMap<AutofillId, MutableList<CredentialEntryInfo>> = mutableMapOf()
+ credentialEntryList.forEach entryLoop@ { credentialEntry ->
+ val autofillId: AutofillId? = credentialEntry
+ .fillInIntent
+ ?.getParcelableExtra(
+ CredentialProviderService.EXTRA_AUTOFILL_ID,
+ AutofillId::class.java)
+ if (autofillId == null) {
+ Log.e(TAG, "AutofillId is missing from credential entry. Credential" +
+ " Integration might be disabled.")
+ return@entryLoop
+ }
+ autofillIdToCredentialEntries.getOrPut(autofillId) { mutableListOf() }
+ .add(credentialEntry)
}
- return fillResponseBuilder.build()
+ return autofillIdToCredentialEntries
+ }
+
+ private fun copyProviderInfo(
+ providerInfo: ProviderInfo,
+ credentialList: List<CredentialEntryInfo>
+ ): ProviderInfo {
+ return ProviderInfo(
+ providerInfo.id,
+ providerInfo.icon,
+ providerInfo.displayName,
+ credentialList,
+ providerInfo.authenticationEntryList,
+ providerInfo.remoteEntry,
+ providerInfo.actionEntryList
+ )
}
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
@@ -353,15 +447,4 @@
}
return result
}
-
- private fun isSameCredentialEntry(
- info1: CredentialEntryInfo,
- info2: CredentialEntryInfo
- ): Boolean {
- return info1.providerId == info2.providerId &&
- info1.lastUsedTimeMillis == info2.lastUsedTimeMillis &&
- info1.credentialType == info2.credentialType &&
- info1.displayName == info2.displayName &&
- info1.userName == info2.userName
- }
}
\ No newline at end of file
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 6001155..2b5fcd8 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -24,8 +24,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
-import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.ColorInt;
@@ -41,9 +41,9 @@
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
-public class MainSwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener {
+public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListener {
- private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
+ private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
@ColorInt
private int mBackgroundColor;
@@ -51,8 +51,8 @@
private int mBackgroundActivatedColor;
protected TextView mTextView;
- protected Switch mSwitch;
- private View mFrameView;
+ protected CompoundButton mSwitch;
+ private final View mFrameView;
public MainSwitchBar(Context context) {
this(context, null);
@@ -84,8 +84,8 @@
setClickable(true);
mFrameView = findViewById(R.id.frame);
- mTextView = (TextView) findViewById(R.id.switch_text);
- mSwitch = (Switch) findViewById(android.R.id.switch_widget);
+ mTextView = findViewById(R.id.switch_text);
+ mSwitch = findViewById(android.R.id.switch_widget);
addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
if (mSwitch.getVisibility() == VISIBLE) {
@@ -136,13 +136,6 @@
}
/**
- * Return the Switch
- */
- public final Switch getSwitch() {
- return mSwitch;
- }
-
- /**
* Set the title text
*/
public void setTitle(CharSequence text) {
@@ -192,7 +185,7 @@
/**
* Adds a listener for switch changes
*/
- public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
}
@@ -201,7 +194,7 @@
/**
* Remove a listener for switch changes
*/
- public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
mSwitchChangeListeners.remove(listener);
}
@@ -223,9 +216,8 @@
private void propagateChecked(boolean isChecked) {
setBackground(isChecked);
- final int count = mSwitchChangeListeners.size();
- for (int n = 0; n < count; n++) {
- mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
+ for (OnCheckedChangeListener changeListener : mSwitchChangeListeners) {
+ changeListener.onCheckedChanged(mSwitch, isChecked);
}
}
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index 11a6804..b294d4e 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -19,24 +19,25 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
-import android.widget.Switch;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.widget.mainswitch.R;
+
import java.util.ArrayList;
import java.util.List;
-import com.android.settingslib.widget.mainswitch.R;
-
/**
* MainSwitchPreference is a Preference with a customized Switch.
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
-public class MainSwitchPreference extends TwoStatePreference implements OnMainSwitchChangeListener {
+public class MainSwitchPreference extends TwoStatePreference implements OnCheckedChangeListener {
- private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
+ private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>();
private MainSwitchBar mMainSwitchBar;
@@ -120,7 +121,7 @@
}
@Override
- public void onSwitchChanged(Switch switchView, boolean isChecked) {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
super.setChecked(isChecked);
}
@@ -138,7 +139,7 @@
/**
* Adds a listener for switch changes
*/
- public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
}
@@ -151,7 +152,7 @@
/**
* Remove a listener for switch changes
*/
- public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
+ public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
mSwitchChangeListeners.remove(listener);
if (mMainSwitchBar != null) {
mMainSwitchBar.removeOnSwitchChangeListener(listener);
@@ -159,7 +160,7 @@
}
private void registerListenerToSwitchBar() {
- for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) {
+ for (OnCheckedChangeListener listener : mSwitchChangeListeners) {
mMainSwitchBar.addOnSwitchChangeListener(listener);
}
}
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java
deleted file mode 100644
index 03868f9..0000000
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/OnMainSwitchChangeListener.java
+++ /dev/null
@@ -1,32 +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.settingslib.widget;
-
-import android.widget.Switch;
-
-import com.android.settingslib.widget.mainswitch.R;
-
-/**
- * Called when the checked state of the Switch has changed.
- */
-public interface OnMainSwitchChangeListener {
- /**
- * @param switchView The Switch view whose state has changed.
- * @param isChecked The new checked state of switchView.
- */
- void onSwitchChanged(Switch switchView, boolean isChecked);
-}
diff --git a/packages/SettingsLib/Spa/gallery/res/values/strings.xml b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
index ec60f8c..18a6db0 100644
--- a/packages/SettingsLib/Spa/gallery/res/values/strings.xml
+++ b/packages/SettingsLib/Spa/gallery/res/values/strings.xml
@@ -26,4 +26,9 @@
<string name="single_line_summary_preference_summary" translatable="false">A very long summary to show case a preference which only shows a single line summary.</string>
<!-- Footer text with two links. [DO NOT TRANSLATE] -->
<string name="footer_with_two_links" translatable="false">Annotated string with <a href="https://www.android.com/">link 1</a> and <a href="https://source.android.com/">link 2</a>.</string>
+
+ <!-- Sample title -->
+ <string name="sample_title" translatable="false">Lorem ipsum</string>
+ <!-- Sample text -->
+ <string name="sample_text" translatable="false">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent a rhoncus tellus. Nulla facilisi. Pellentesque erat ex, maximus viae turpis</string>
</resources>
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index d62b490..b1e1585 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -22,6 +22,7 @@
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.card.CardPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -98,6 +99,7 @@
SettingsExposedDropdownMenuCheckBoxProvider,
SettingsTextFieldPasswordPageProvider,
SearchScaffoldPageProvider,
+ CardPageProvider,
),
rootPages = listOf(
HomePageProvider.createSettingsPage(),
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
new file mode 100644
index 0000000..e914d5c
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.gallery.card
+
+import android.os.Bundle
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.WarningAmber
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.gallery.R
+import com.android.settingslib.spa.widget.card.CardButton
+import com.android.settingslib.spa.widget.card.SettingsCard
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+object CardPageProvider : SettingsPageProvider {
+ override val name = "ActionButton"
+
+ override fun getTitle(arguments: Bundle?) = TITLE
+
+ @Composable
+ override fun Page(arguments: Bundle?) {
+ RegularScaffold(title = TITLE) {
+ SettingsCardWithIcon()
+ SettingsCardWithoutIcon()
+ }
+ }
+
+ @Composable
+ private fun SettingsCardWithIcon() {
+ SettingsCard(
+ title = stringResource(R.string.sample_title),
+ text = stringResource(R.string.sample_text),
+ imageVector = Icons.Outlined.WarningAmber,
+ buttons = listOf(
+ CardButton(text = "Action") {},
+ CardButton(text = "Action", isMain = true) {},
+ )
+ )
+ }
+
+ @Composable
+ private fun SettingsCardWithoutIcon() {
+ SettingsCard(
+ title = stringResource(R.string.sample_title),
+ text = stringResource(R.string.sample_text),
+ buttons = listOf(
+ CardButton(text = "Action") {},
+ )
+ )
+ }
+
+ fun buildInjectEntry(): SettingsEntryBuilder {
+ return SettingsEntryBuilder.createInject(owner = createSettingsPage())
+ .setUiLayoutFn {
+ Preference(object : PreferenceModel {
+ override val title = TITLE
+ override val onClick = navigator(name)
+ })
+ }
+ }
+
+ private const val TITLE = "Sample Card"
+}
+
+@Preview
+@Composable
+private fun CardPagePreview() {
+ SettingsTheme {
+ CardPageProvider.Page(null)
+ }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
index b339b44..f52ceec 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
@@ -28,6 +28,7 @@
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.card.CardPageProvider
import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -69,6 +70,7 @@
ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
AlertDialogPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
EditorMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+ CardPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
)
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
index a1ab35b..eac06e3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SearchScaffoldPageProvider.kt
@@ -50,7 +50,7 @@
@Composable
private fun Page() {
- SearchScaffold(title = TITLE) { bottomPadding, searchQuery ->
- PlaceholderTitle("Search query: ${searchQuery.value}")
+ SearchScaffold(title = TITLE) { _, searchQuery ->
+ PlaceholderTitle("Search query: ${searchQuery()}")
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
index ba88546..b97fb9c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/RuntimeUtils.kt
@@ -29,12 +29,6 @@
}
/**
- * Remember the [State] initialized with the [this].
- */
-@Composable
-fun <T> T.toState(): State<T> = remember { stateOf(this) }
-
-/**
* Return a new [State] initialized with the passed in [value].
*/
fun <T> stateOf(value: T) = object : State<T> {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
index 494e69b..7842948 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
@@ -18,11 +18,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
-/** A StateFlow holder which value could be set or sync from [State]. */
+/** A StateFlow holder which value could be set or sync from callback. */
class StateFlowBridge<T> {
private val stateFlow = MutableStateFlow<T?>(null)
val flow = stateFlow.filterNotNull()
@@ -34,9 +33,10 @@
}
@Composable
- fun Sync(state: State<T>) {
- LaunchedEffect(state.value) {
- stateFlow.value = state.value
+ fun Sync(callback: () -> T) {
+ val value = callback()
+ LaunchedEffect(value) {
+ stateFlow.value = value
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
new file mode 100644
index 0000000..98873e0
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.card
+
+import android.content.res.Configuration
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.WarningAmber
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraLarge
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.ui.SettingsBody
+import com.android.settingslib.spa.widget.ui.SettingsTitle
+
+data class CardButton(
+ val text: String,
+ val isMain: Boolean = false,
+ val onClick: () -> Unit,
+)
+
+@Composable
+fun SettingsCard(
+ title: String,
+ text: String,
+ imageVector: ImageVector? = null,
+ buttons: List<CardButton> = emptyList(),
+) {
+ Card(
+ shape = CornerExtraLarge,
+ colors = CardDefaults.cardColors(
+ containerColor = SettingsTheme.colorScheme.surface,
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(
+ horizontal = SettingsDimension.itemPaddingEnd,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
+ ) {
+ Column(
+ modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+ ) {
+ CardIcon(imageVector)
+ SettingsTitle(title)
+ SettingsBody(text)
+ Buttons(buttons)
+ }
+ }
+}
+
+@Composable
+private fun CardIcon(imageVector: ImageVector?) {
+ if (imageVector != null) {
+ Icon(
+ imageVector = imageVector,
+ contentDescription = null,
+ modifier = Modifier.size(SettingsDimension.itemIconSize),
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ }
+}
+
+@Composable
+private fun Buttons(buttons: List<CardButton>) {
+ if (buttons.isNotEmpty()) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = SettingsDimension.itemPaddingAround),
+ horizontalArrangement = Arrangement.spacedBy(
+ space = SettingsDimension.itemPaddingEnd,
+ alignment = Alignment.End,
+ ),
+ ) {
+ for (button in buttons) {
+ Button(button)
+ }
+ }
+ }
+}
+
+@Composable
+private fun Button(button: CardButton) {
+ if (button.isMain) {
+ Button(
+ onClick = button.onClick,
+ colors = ButtonDefaults.buttonColors(
+ containerColor = SettingsTheme.colorScheme.primaryContainer,
+ ),
+ ) {
+ Text(
+ text = button.text,
+ color = SettingsTheme.colorScheme.onPrimaryContainer,
+ )
+ }
+ } else {
+ OutlinedButton(onClick = button.onClick) {
+ Text(
+ text = button.text,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ }
+ }
+}
+
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
+@Composable
+private fun SettingsCardPreviewLight() {
+ SettingsCardPreview()
+}
+
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun SettingsCardPreviewDark() {
+ SettingsCardPreview()
+}
+
+@Composable
+private fun SettingsCardPreview() {
+ SettingsTheme {
+ SettingsCard(
+ title = "Lorem ipsum",
+ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ imageVector = Icons.Outlined.WarningAmber,
+ buttons = listOf(
+ CardButton(text = "Action") {},
+ CardButton(text = "Action", isMain = true) {},
+ )
+ )
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 696e877..c87178d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -37,8 +37,6 @@
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -72,7 +70,7 @@
fun SearchScaffold(
title: String,
actions: @Composable RowScope.() -> Unit = {},
- content: @Composable (bottomPadding: Dp, searchQuery: State<String>) -> Unit,
+ content: @Composable (bottomPadding: Dp, searchQuery: () -> String) -> Unit,
) {
ActivityTitle(title)
var isSearchMode by rememberSaveable { mutableStateOf(false) }
@@ -100,12 +98,9 @@
.focusable()
.fillMaxSize()
) {
- content(
- paddingValues.calculateBottomPadding(),
- remember {
- derivedStateOf { if (isSearchMode) viewModel.searchQuery.text else "" }
- },
- )
+ content(paddingValues.calculateBottomPadding()) {
+ if (isSearchMode) viewModel.searchQuery.text else ""
+ }
}
}
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
index f0e57b9..9b7ef08 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
@@ -18,7 +18,6 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -56,7 +55,7 @@
val stateFlowBridge = StateFlowBridge<String>()
composeTestRule.setContent {
- stateFlowBridge.Sync(stateOf("A"))
+ stateFlowBridge.Sync { "A" }
}
val first = stateFlowBridge.flow.firstWithTimeoutOrNull()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
new file mode 100644
index 0000000..0ec8507
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.card
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SettingsCardTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @Test
+ fun settingsCard_titleDisplayed() {
+ composeTestRule.setContent {
+ SettingsCard(
+ title = TITLE,
+ text = "",
+ )
+ }
+
+ composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+ }
+
+ @Test
+ fun settingsCard_textDisplayed() {
+ composeTestRule.setContent {
+ SettingsCard(
+ title = "",
+ text = TEXT,
+ )
+ }
+
+ composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
+ }
+
+ @Test
+ fun settingsCard_buttonDisplayed() {
+ composeTestRule.setContent {
+ SettingsCard(
+ title = "",
+ text = "",
+ buttons = listOf(
+ CardButton(text = TEXT) {}
+ ),
+ )
+ }
+
+ composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
+ }
+
+ @Test
+ fun settingsCard_buttonCanBeClicked() {
+ var buttonClicked = false
+ composeTestRule.setContent {
+ SettingsCard(
+ title = "",
+ text = "",
+ buttons = listOf(
+ CardButton(text = TEXT) { buttonClicked = true }
+ ),
+ )
+ }
+
+ composeTestRule.onNodeWithText(TEXT).performClick()
+
+ assertThat(buttonClicked).isTrue()
+ }
+
+ private companion object {
+ const val TITLE = "Title"
+ const val TEXT = "Text"
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
index c3e1d54..826a0d4 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt
@@ -19,7 +19,6 @@
import android.content.Context
import androidx.appcompat.R
import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.State
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
@@ -60,7 +59,7 @@
fun initialState_searchQueryIsEmpty() {
val searchQuery = setContent()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -72,7 +71,7 @@
composeTestRule.onNodeWithText(TITLE).assertDoesNotExist()
onSearchHint().assertIsDisplayed()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -87,7 +86,7 @@
composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
onSearchHint().assertDoesNotExist()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
@Test
@@ -98,7 +97,7 @@
onSearchHint().performTextInput(QUERY)
onClearButton().assertIsDisplayed()
- assertThat(searchQuery.value).isEqualTo(QUERY)
+ assertThat(searchQuery()).isEqualTo(QUERY)
}
@Test
@@ -110,11 +109,11 @@
onClearButton().performClick()
onClearButton().assertDoesNotExist()
- assertThat(searchQuery.value).isEqualTo("")
+ assertThat(searchQuery()).isEqualTo("")
}
- private fun setContent(): State<String> {
- lateinit var actualSearchQuery: State<String>
+ private fun setContent(): () -> String {
+ lateinit var actualSearchQuery: () -> String
composeTestRule.setContent {
SearchScaffold(title = TITLE) { _, searchQuery ->
SideEffect {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
new file mode 100644
index 0000000..2c60db4
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.framework.common
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+
+/**
+ * A [BroadcastReceiver] flow for the given [intentFilter].
+ */
+fun Context.broadcastReceiverAsUserFlow(
+ intentFilter: IntentFilter,
+ userHandle: UserHandle,
+): Flow<Intent> = callbackFlow {
+ val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ trySend(intent)
+ }
+ }
+ registerReceiverAsUser(
+ broadcastReceiver,
+ userHandle,
+ intentFilter,
+ null,
+ null,
+ Context.RECEIVER_NOT_EXPORTED,
+ )
+
+ awaitClose { unregisterReceiver(broadcastReceiver) }
+}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
index ad907cf..7d6ee19 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
@@ -17,14 +17,14 @@
package com.android.settingslib.spaprivileged.framework.compose
import android.content.BroadcastReceiver
-import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
-import com.android.settingslib.spa.framework.compose.LifecycleEffect
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
+import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverAsUserFlow
/**
* A [BroadcastReceiver] which registered when on start and unregistered when on stop.
@@ -35,27 +35,6 @@
userHandle: UserHandle,
onReceive: (Intent) -> Unit,
) {
- val context = LocalContext.current
- val broadcastReceiver = remember {
- object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- onReceive(intent)
- }
- }
- }
- LifecycleEffect(
- onStart = {
- context.registerReceiverAsUser(
- broadcastReceiver,
- userHandle,
- intentFilter,
- null,
- null,
- Context.RECEIVER_NOT_EXPORTED,
- )
- },
- onStop = {
- context.unregisterReceiver(broadcastReceiver)
- },
- )
+ LocalContext.current.broadcastReceiverAsUserFlow(intentFilter, userHandle)
+ .collectLatestWithLifecycle(LocalLifecycleOwner.current, action = onReceive)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt
index 8e702ea..8e28bf8 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt
@@ -23,21 +23,24 @@
import kotlin.reflect.KProperty
import kotlinx.coroutines.flow.Flow
-fun Context.settingsGlobalBoolean(name: String): ReadWriteProperty<Any?, Boolean> =
- SettingsGlobalBooleanDelegate(this, name)
+fun Context.settingsGlobalBoolean(name: String, defaultValue: Boolean = false):
+ ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue)
-fun Context.settingsGlobalBooleanFlow(name: String): Flow<Boolean> {
- val value by settingsGlobalBoolean(name)
+fun Context.settingsGlobalBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> {
+ val value by settingsGlobalBoolean(name, defaultValue)
return settingsGlobalFlow(name) { value }
}
-private class SettingsGlobalBooleanDelegate(context: Context, private val name: String) :
- ReadWriteProperty<Any?, Boolean> {
+private class SettingsGlobalBooleanDelegate(
+ context: Context,
+ private val name: String,
+ private val defaultValue: Boolean = false,
+) : ReadWriteProperty<Any?, Boolean> {
private val contentResolver: ContentResolver = context.contentResolver
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean =
- Settings.Global.getInt(contentResolver, name, 0) != 0
+ Settings.Global.getInt(contentResolver, name, if (defaultValue) 1 else 0) != 0
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
Settings.Global.putInt(contentResolver, name, if (value) 1 else 0)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index 7c45b64..68da143 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -65,8 +65,8 @@
)
data class AppListState(
- val showSystem: State<Boolean>,
- val searchQuery: State<String>,
+ val showSystem: () -> Boolean,
+ val searchQuery: () -> String,
)
data class AppListInput<T : AppRecord>(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 07e4235..c69b5df 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -17,8 +17,10 @@
package com.android.settingslib.spaprivileged.template.app
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction
import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
@@ -47,13 +49,13 @@
header: @Composable () -> Unit = {},
appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
) {
- val showSystem = rememberSaveable { mutableStateOf(false) }
+ var showSystem by rememberSaveable { mutableStateOf(false) }
SearchScaffold(
title = title,
actions = {
if (!noMoreOptions) {
MoreOptionsAction {
- ShowSystemAction(showSystem.value) { showSystem.value = it }
+ ShowSystemAction(showSystem) { showSystem = it }
moreOptions()
}
}
@@ -68,7 +70,7 @@
),
listModel = listModel,
state = AppListState(
- showSystem = showSystem,
+ showSystem = { showSystem },
searchQuery = searchQuery,
),
header = header,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
new file mode 100644
index 0000000..dfb8e22
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.framework.common
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.isNull
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+class BroadcastReceiverAsUserFlowTest {
+
+ private var registeredBroadcastReceiver: BroadcastReceiver? = null
+
+ private val context = mock<Context> {
+ on {
+ registerReceiverAsUser(
+ any(),
+ eq(USER_HANDLE),
+ eq(INTENT_FILTER),
+ isNull(),
+ isNull(),
+ eq(Context.RECEIVER_NOT_EXPORTED),
+ )
+ } doAnswer {
+ registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
+ null
+ }
+ }
+
+ @Test
+ fun broadcastReceiverAsUserFlow_registered() = runBlocking {
+ val flow = context.broadcastReceiverAsUserFlow(INTENT_FILTER, USER_HANDLE)
+
+ flow.firstWithTimeoutOrNull()
+
+ assertThat(registeredBroadcastReceiver).isNotNull()
+ }
+
+ @Test
+ fun broadcastReceiverAsUserFlow_isCalledOnReceive() = runBlocking {
+ var onReceiveIsCalled = false
+ launch {
+ context.broadcastReceiverAsUserFlow(INTENT_FILTER, USER_HANDLE).first {
+ onReceiveIsCalled = true
+ true
+ }
+ }
+
+ delay(100)
+ registeredBroadcastReceiver!!.onReceive(context, Intent())
+ delay(100)
+
+ assertThat(onReceiveIsCalled).isTrue()
+ }
+
+ private companion object {
+ val USER_HANDLE: UserHandle = UserHandle.of(0)
+
+ val INTENT_FILTER = IntentFilter()
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
index 2c8fb66..f812f95 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
@@ -23,38 +23,32 @@
import android.os.UserHandle
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
-import org.mockito.kotlin.whenever
+import org.mockito.kotlin.mock
@RunWith(AndroidJUnit4::class)
class DisposableBroadcastReceiverAsUserTest {
@get:Rule
val composeTestRule = createComposeRule()
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var context: Context
-
private var registeredBroadcastReceiver: BroadcastReceiver? = null
- @Before
- fun setUp() {
- whenever(
- context.registerReceiverAsUser(
+ private val context = mock<Context> {
+ on {
+ registerReceiverAsUser(
any(),
eq(USER_HANDLE),
eq(INTENT_FILTER),
@@ -62,7 +56,7 @@
isNull(),
eq(Context.RECEIVER_NOT_EXPORTED),
)
- ).then {
+ } doAnswer {
registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
null
}
@@ -71,7 +65,10 @@
@Test
fun broadcastReceiver_registered() {
composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
+ CompositionLocalProvider(
+ LocalContext provides context,
+ LocalLifecycleOwner provides TestLifecycleOwner(),
+ ) {
DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {}
}
}
@@ -80,10 +77,13 @@
}
@Test
- fun broadcastReceiver_isCalledOnReceive() {
+ fun broadcastReceiver_isCalledOnReceive() = runBlocking {
var onReceiveIsCalled = false
composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
+ CompositionLocalProvider(
+ LocalContext provides context,
+ LocalLifecycleOwner provides TestLifecycleOwner(),
+ ) {
DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {
onReceiveIsCalled = true
}
@@ -91,6 +91,7 @@
}
registeredBroadcastReceiver!!.onReceive(context, Intent())
+ delay(100)
assertThat(onReceiveIsCalled).isTrue()
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index 840bca8..44973a7 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -19,6 +19,8 @@
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
+import android.content.pm.FakeFeatureFlagsImpl
+import android.content.pm.Flags
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.PackageManager.ResolveInfoFlags
@@ -29,76 +31,62 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.R
-import com.android.settingslib.spaprivileged.framework.common.userManager
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
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.Mock
-import org.mockito.Spy
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
-import android.content.pm.FakeFeatureFlagsImpl
-import android.content.pm.Flags
@RunWith(AndroidJUnit4::class)
class AppListRepositoryTest {
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
+ private val resources = mock<Resources> {
+ on { getStringArray(R.array.config_hideWhenDisabled_packageNames) } doReturn emptyArray()
+ }
- @Spy
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- @Mock
- private lateinit var resources: Resources
-
- @Mock
- private lateinit var packageManager: PackageManager
-
- @Mock
- private lateinit var userManager: UserManager
-
- private lateinit var repository: AppListRepository
-
- @Before
- fun setUp() {
- whenever(context.resources).thenReturn(resources)
- whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames))
- .thenReturn(emptyArray())
- whenever(context.packageManager).thenReturn(packageManager)
- whenever(context.userManager).thenReturn(userManager)
- whenever(packageManager.getInstalledModules(any())).thenReturn(emptyList())
- whenever(packageManager.getHomeActivities(any())).thenAnswer {
+ private val packageManager = mock<PackageManager> {
+ on { getInstalledModules(any()) } doReturn emptyList()
+ on { getHomeActivities(any()) } doAnswer {
@Suppress("UNCHECKED_CAST")
val resolveInfos = it.arguments[0] as MutableList<ResolveInfo>
resolveInfos += resolveInfoOf(packageName = HOME_APP.packageName)
null
}
- whenever(
- packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), any<Int>())
- ).thenReturn(listOf(resolveInfoOf(packageName = IN_LAUNCHER_APP.packageName)))
- whenever(userManager.getUserInfo(ADMIN_USER_ID)).thenReturn(UserInfo().apply {
- flags = UserInfo.FLAG_ADMIN
- })
- whenever(userManager.getProfileIdsWithDisabled(ADMIN_USER_ID))
- .thenReturn(intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID))
-
- repository = AppListRepositoryImpl(context)
+ on { queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), any<Int>()) } doReturn
+ listOf(resolveInfoOf(packageName = IN_LAUNCHER_APP.packageName))
}
+ private val mockUserManager = mock<UserManager> {
+ on { getUserInfo(ADMIN_USER_ID) } doReturn UserInfo().apply {
+ flags = UserInfo.FLAG_ADMIN
+ }
+ on { getProfileIdsWithDisabled(ADMIN_USER_ID) } doReturn
+ intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID)
+ }
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { resources } doReturn resources
+ on { packageManager } doReturn packageManager
+ on { getSystemService(UserManager::class.java) } doReturn mockUserManager
+ }
+
+ private val repository = AppListRepositoryImpl(context)
+
private fun mockInstalledApplications(apps: List<ApplicationInfo>, userId: Int) {
- whenever(
- packageManager.getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(userId))
- ).thenReturn(apps)
+ packageManager.stub {
+ on { getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(userId)) } doReturn
+ apps
+ }
}
@Test
@@ -135,13 +123,13 @@
)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ )
}
@Test
@@ -154,11 +142,10 @@
)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value and PackageManager.MATCH_ANY_USER.toLong())
- .isGreaterThan(0L)
- }
+ }.firstValue
+ assertThat(flags.value and PackageManager.MATCH_ANY_USER.toLong()).isGreaterThan(0L)
}
@Test
@@ -278,14 +265,14 @@
val appList = repository.loadApps(userId = ADMIN_USER_ID)
assertThat(appList).containsExactly(NORMAL_APP, ARCHIVED_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- (PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() or
- PackageManager.MATCH_ARCHIVED_PACKAGES
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ (PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() or
+ PackageManager.MATCH_ARCHIVED_PACKAGES
+ )
}
@Test
@@ -294,13 +281,13 @@
val appList = repository.loadApps(userId = ADMIN_USER_ID)
assertThat(appList).containsExactly(NORMAL_APP)
- argumentCaptor<ApplicationInfoFlags> {
+ val flags = argumentCaptor<ApplicationInfoFlags> {
verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID))
- assertThat(firstValue.value).isEqualTo(
- PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- )
- }
+ }.firstValue
+ assertThat(flags.value).isEqualTo(
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ )
}
@Test
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
index 82fbee9..4d90076 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
@@ -55,8 +55,8 @@
val inputState by setContent()
val state = inputState!!.state
- assertThat(state.showSystem.value).isFalse()
- assertThat(state.searchQuery.value).isEqualTo("")
+ assertThat(state.showSystem()).isFalse()
+ assertThat(state.searchQuery()).isEqualTo("")
}
@Test
@@ -67,7 +67,7 @@
composeTestRule.onNodeWithText(context.getString(R.string.menu_show_system)).performClick()
val state = inputState!!.state
- assertThat(state.showSystem.value).isTrue()
+ assertThat(state.showSystem()).isTrue()
}
@Test
@@ -94,7 +94,7 @@
val inputState by setContent(noMoreOptions = true)
val state = inputState!!.state
- assertThat(state.showSystem.value).isFalse()
+ assertThat(state.showSystem()).isFalse()
}
private fun setContent(
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
index 124ced6..c6409e7 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
@@ -30,7 +30,6 @@
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppEntry
@@ -140,7 +139,7 @@
matchAnyUserForAdmin = false,
),
listModel = TestAppListModel(enableGrouping = enableGrouping),
- state = AppListState(showSystem = stateOf(false), searchQuery = stateOf("")),
+ state = AppListState(showSystem = { false }, searchQuery = { "" }),
header = header,
bottomPadding = 0.dp,
)
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 4ac7467..115d126 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktief, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batterykrag"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktief, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterykrag, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterykrag"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batterykrag"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterykrag, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterykrag"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktief"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktief, net links"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktief, net regs"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktief, links en regs"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Aanvaar dat programme moderne formate steun"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Wys kodewisselingkennisgewings"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Deaktiveer kodewisselingkas"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Lopende dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Sien en beheer dienste wat tans aktief is"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Hierdie foon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Hierdie tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Maak toestel wakker om hier te speel"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Toestel is nie goedgekeur om te speel nie"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan nie hierdie media hier speel nie"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index cc1d29d..97de8d9 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ንቁ፣ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ገቢር፣ ግ፦ <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"ባትሪ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"ግ፦ <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="2952823007648782646">"ግራ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"ቀኝ <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="7084887715570971441">"ገቢር፣ ግራ ብቻ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ገቢር፣ ቀኝ ብቻ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ገቢር፣ ግራ እና ቀኝ"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"መተግበሪያዎች ዘመናዊ ቅርጸቶችን እንደሚደግፉ አድርገው ይቁጠሩ"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ትራንስኮዲንግ ማሳወቂያዎችን አሳይ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"የትራንስኮዲንግ መሸጎጫን አሰናክል"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"አሂድ አገልግሎቶች"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ይህ ስልክ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ይህ ጡባዊ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምፅ ማውጫ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"እዚህ ጋር ለመጫወት መሣሪያን ያንቁ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"መሣሪያ ለማጫወት አልጸደቀም"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ይህን ሚዲያ እዚህ ጋር ማጫወት አይቻልም"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
<string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 541a330..b2cd5fe 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"نشط، ومستوى البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"مفعّلة، مستوى البطارية: <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" msgid="2893696778200201555">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"مستوى البطارية: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"نشط"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"السمّاعة الطبية اليسرى فقط مفعَّلة"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"السمّاعة الطبية اليمنى فقط مفعَّلة"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"السمّاعتان اليسرى واليمنى مفعَّلتان"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"افتراض أن التطبيق يتوافق مع التنسيقات الحديثة"</string>
<string name="transcode_notification" msgid="5560515979793436168">"إظهار إشعارات تحويل الترميز"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"إيقاف ذاكرة التخزين المؤقت لميزة \"تحويل الترميز\""</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"الخدمات قيد التشغيل"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"تطبيق WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"هذا الهاتف"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"هذا الجهاز اللوحي"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"نشِّط الجهاز للتشغيل هنا"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"غير مسموح له بتشغيل وسائط"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"هذه الوسائط غير متوافقة"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
<string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index cdad1fa..4e9326e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"সক্ৰিয়, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"সক্ৰিয়"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"কেৱল বাঁওফালৰটো সক্ৰিয় হৈছে"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"কেৱল সোঁফালৰটো সক্ৰিয় হৈছে"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"বাওঁ আৰু সোঁ দুয়োফালৰ সক্ৰিয় হৈছে"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"এপে আধুনিক ফৰ্মেট সমৰ্থন কৰে বুলি ধৰি লওক"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ট্ৰান্সক\'ডিঙৰ জাননী দেখুৱাওক"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ট্ৰান্সক\'ডিঙৰ কেশ্ব অক্ষম কৰক"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"চলিত সেৱা"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফ’নটো"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"এই টেবলেটটো"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ইয়াত প্লে\' কৰিবলৈ ডিভাইচটো সক্ৰিয় কৰক"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"প্লে\' কৰিবলৈ ডিভাইচটো অনুমোদিত নহয়"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ইয়াত এই মিডিয়াটো প্লে\' কৰিব নোৱাৰি"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
<string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
@@ -576,7 +608,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"সীমিত প্ৰ\'ফাইল"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"নতুন ব্যৱহাৰকাৰী যোগ কৰিবনে?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"আপুনি অতিৰিক্ত ব্যৱহাৰকাৰীক যোগ কৰি এই ডিভাইচটো অন্য় ব্য়ক্তিৰ সৈতে শ্বেয়াৰ কৰিব পাৰে। প্ৰতিজন ব্যৱহাৰকাৰীৰ বাবে নিজাকৈ ঠাই আছে যাক তেওঁলোকে এপ্, ৱালপেপাৰ আৰু অন্য়ান্য় বস্তুৰ বাবে নিজৰ উপযোগিতা অনুযায়ী ব্যৱহাৰ কৰিব পাৰে। ব্যৱহাৰকাৰীসকলে সকলোকে প্ৰভাৱান্বিত কৰা ৱাই-ফাইৰ নিচিনা ডিভাইচৰ ছেটিং সাল-সলনি কৰিবও পাৰে।\n\nআপুনি যেতিয়া কোনো নতুন ব্যৱহাৰকাৰীক যোগ কৰে সেই ব্য়ক্তিজনে নিজেই নিজৰ বাবে ঠাই ছেট আপ কৰিব লাগিব।\n\nসকলো ব্যৱহাৰকাৰীয়ে অন্য় ব্যৱহাৰকাৰীৰ বাবে এপ্সমূহ আপডে’ট কৰিব পাৰে। সাধ্য় সুবিধাসমূহৰ ছেটিং আৰু সেৱাসমূহ নতুন ব্যৱহাৰকাৰীলৈ স্থানান্তৰ নহ\'বও পাৰে।"</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ ঠাই ছেট আপ কৰাৰ প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে অন্য সকলো ব্যৱহাৰকাৰীৰ বাবে এপ্ আপডে\'ট কৰিব পাৰে।"</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"আপুনি যেতিয়া এগৰাকী নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ ঠাই ছেট আপ কৰাৰ প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে অন্য সকলো ব্যৱহাৰকাৰীৰ বাবে এপ্ আপডে\'ট কৰিব পাৰে।"</string>
<string name="user_grant_admin_title" msgid="5157031020083343984">"এই ব্যৱহাৰকাৰীগৰাকীক এগৰাকী প্ৰশাসক বনাবনে?"</string>
<string name="user_grant_admin_message" msgid="1673791931033486709">"প্ৰশাসকৰ ওচৰত কিছুমান বিশেষাধিকাৰ আছে, যিবোৰ অন্য ব্যৱহাৰকাৰীৰ নাই। এগৰাকী প্ৰশাসকে সকলো ব্যৱহাৰকাৰীক পৰিচালনা কৰিব, এই ডিভাইচটো আপডে’ট অথবা ৰিছেট কৰিব, ছেটিং সংশোধন কৰিব, ইনষ্টল কৰি থোৱা আটাইবোৰ এপ্ চাব আৰু অন্য লোকৰ বাবে প্ৰশাসকৰ বিশেষাধিকাৰ প্ৰদান কৰিব অথবা প্ৰত্যাহাৰ কৰিব পাৰে।"</string>
<string name="user_grant_admin_button" msgid="5441486731331725756">"প্ৰশাসক বনাওক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d0f18f1..c16d058 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiv, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batareya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batareya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, yalnız sol"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, yalnız sağ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, sol və sağ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Tətbiqlərin müasir formatları dəstəklədiyini qəbul edin"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Kod dəyişmə bildirişlərini göstərin"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Keşin kodlaşdırılmasını deaktiv edin"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"İşləyən xidmətlər"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"İşlək xidmətlərə baxış və onların idarəedilməsi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView servisi"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu planşet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Burada oxutmaqçün cihazı oyat"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Cihaz oxutmaq üçün təsdiqlənməyib"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Bu medianı burada oxutmaq olmur"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 21534ee..e326c64 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivan, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, 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" msgid="2893696778200201555">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Baterija, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"Leva <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Aktivno, samo s leve strane"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, s desne strane"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, s leve i desne strane"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Podrazumevaj da aplikacije podržavaju moderne formate"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Prikazuj obaveštenja o transkodiranju"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Onemogući keš transkodiranja"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Probudite uređaj da biste pustili ovde"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Uređaj nije odobren za reprodukciju"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ne možete da pustite ovaj medijski fajl ovde"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 6ad88d4..2458eac 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Уключана, зарад <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Актыўна, Л: акумулятар: <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" msgid="2893696778200201555">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: акумулятар: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Уключана"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Уключана, толькі для левага вуха"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Уключана, толькі для правага вуха"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Уключана, для левага і правага вуха"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Лічыца, што праграмы падтрымліваюць сучасныя фарматы"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Паказваць апавяшчэнні пра перакадзіраванне"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Адключыць кэш перакадзіравання"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запушчаныя службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Прагляд запушчаных службаў i кіраванне iмi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Гэты тэлефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Гэты планшэт"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Для прайгравання на гэтай прыладзе абудзіце яе"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Для прайгравання на прыладзе патрабуецца ўхваленне"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Тут не ўдаецца прайграць мультымедыя"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
<string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 486fc9b..74641d1 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активно. Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активно. Л: <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" msgid="2893696778200201555">"Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно – само лявото"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно – само дясното"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно – лявото и дясното"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Предполагане, че приложенията поддържат съвременни формати"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Показване на известията за прекодиране"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Деактивиране на кеша за прекодиране"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Изпълнявани услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Този телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Този таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Активирайте устройството, за да възпроизведете съдържанието тук"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Устройството не е одобрено да възпроизвежда съдържание"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Мултимедийното съдържание не може да се възпроизведе тук"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
<string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 1d1d82e..c102722 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"চালু আছে, চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"চালু, 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" msgid="2893696778200201555">"চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"চালু আছে"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"শুধুমাত্র বাঁদিকের হিয়ারিং এড অ্যাক্টিভ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"শুধুমাত্র ডানদিকের হিয়ারিং এড অ্যাক্টিভ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"বাঁ ও ডানদিকের হিয়ারিং এড, অ্যাক্টিভ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"অ্যাপ মর্ডার্ন ফর্ম্যাটে কাজ করবে বলে ধরে নিন"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ট্রান্সকোডিং বিজ্ঞপ্তি দেখুন"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ক্যাশে ট্রান্সকোডিং বন্ধ করুন"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"এখন চলছে যে পরিষেবাগুলি"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফোন"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"এই ট্যাবলেট"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"এখানে চালানোর জন্য ডিভাইসকে জাগান"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"চালানোর জন্য ডিভাইসের অনুমতি নেই"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"এখানে এই মিডিয়া চালানো যাচ্ছে না"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
<string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f489b12..c4ef89b 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivan, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Lijevo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Desno <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">"Spremljeno"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevi"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desni"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevi i desni"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavještenja o transkodiranju"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Onemogućite keš memoriju za transkodiranje"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivirajte uređaj da reproducirate ovdje"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Uređaj nije odobren za reprodukciju"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Nije moguće ovdje reproducirati medij"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index e98b7c4..5d1b46d 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Actiu, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Actiu, E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateria"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateria"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Esquerre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Dret: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<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="7084887715570971441">"Actiu, només l\'esquerre"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actiu, només el dret"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actiu, esquerre i dret"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Assumeix que les aplicacions són compatibles amb formats moderns"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostra les notificacions de transcodificació"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desactiva la memòria cau per a la transcodificació"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serveis en execució"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualitza i controla els serveis en execució"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Aquest telèfon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Aquesta tauleta"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositiu per reproduir aquí"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"El dispositiu no està aprovat per reproduir contingut"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No es pot reproduir aquest contingut multimèdia aquí"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 27024a2..91aef96 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivní, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivní, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterie, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterie"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Baterie <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterie, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterie"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Vlevo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Vpravo <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="7084887715570971441">"Aktivní, pouze levé"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivní, pouze pravé"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivní, levé a pravé"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Předpokládat, že aplikace podporují moderní formáty"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Zobrazit oznámení o překódování"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Deaktivovat mezipaměť pro překódování"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spuštěné služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok s reproduktorem"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Zařízení je třeba probudit"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Není schváleno k přehrávání"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tato média zde přehrát nelze"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
<string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 6da7456..1cbe27c 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivt, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri. Højre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, kun venstre"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, kun højre"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, venstre og højre"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Gå ud fra, at apps understøtter moderne formater"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Vis notifikationer for omkodning"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Deaktiver omkodningscache"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Kørende tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vis og administrer kørende tjenester"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Denne tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Væk enheden for at afspille her"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheden er ikke godkendt"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Mediet kan ikke afspilles her"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 7c65e94..caeed8c 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiv, Akkustand 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" msgid="2893696778200201555">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Akkustand 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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, nur links"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, nur rechts"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, links und rechts"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Voraussetzen, dass Apps moderne Formate unterstützen"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Benachrichtigungen zur Transcodierung anzeigen"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Cache für Transcodierung deaktivieren"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Dieses Smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Dieses Tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock-Lautsprecher"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Gerät aktivieren, um hier etwas wiedergeben zu lassen"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Gerät nicht für die Wiedergabe zugelassen"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Diese Medien können hier nicht wiedergegeben werden"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus & und wieder ein."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
<string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index cc4bb1e..a70e9b8 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Ενεργό, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Ενεργό, Α: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Α: <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="2952823007648782646">"Αριστερό <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Δεξί <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="7084887715570971441">"Ενεργό, μόνο το αριστερό"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ενεργό, μόνο το δεξί"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ενεργό, αριστερό και δεξί"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Να θεωρείται ότι οι εφαρμογές χρησιμοποιούν σύγχρονες μορφές"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Εμφάνιση ειδοποιήσεων διακωδικοποίησης"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Απενεργοποίηση κρυφής μνήμης για διακωδικοποίηση"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Υπηρεσίες που εκτελούνται"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Αυτό το tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Αφύπνιση συσκευής για αναπαραγωγή εδώ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Η συσκευή δεν έχει εγκριθεί για αναπαραγωγή"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Δεν είναι δυνατή η αναπαραγωγή αυτού του πολυμέσου εδώ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
<string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 98c7b73..04fa675 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Active, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Active, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disable transcoding cache"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wake up device to play here"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Device not approved to play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Can\'t play this media here"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 16dfb5b..364820d 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Active, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Active, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Battery <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Active, left only"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string>
@@ -432,6 +436,9 @@
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disable transcoding cache"</string>
+ <string name="widevine_settings_title" msgid="4023329801172572917">"Widevine settings"</string>
+ <string name="force_l3_fallback_title" msgid="4987972688770202547">"Force L3 fallback"</string>
+ <string name="force_l3_fallback_summary" msgid="3080790841069996016">"Select to force L3 fallback"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -542,6 +549,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -553,6 +562,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wake up device to play here"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Device not approved to play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Cant play this media here"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off & back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 98c7b73..04fa675 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Active, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Active, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disable transcoding cache"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wake up device to play here"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Device not approved to play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Can\'t play this media here"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 98c7b73..04fa675 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Active, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Active, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Active"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disable transcoding cache"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wake up device to play here"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Device not approved to play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Can\'t play this media here"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 9a91eda..7215550 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Active, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Active, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Battery <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Active, left only"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string>
@@ -432,6 +436,9 @@
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disable transcoding cache"</string>
+ <string name="widevine_settings_title" msgid="4023329801172572917">"Widevine settings"</string>
+ <string name="force_l3_fallback_title" msgid="4987972688770202547">"Force L3 fallback"</string>
+ <string name="force_l3_fallback_summary" msgid="3080790841069996016">"Select to force L3 fallback"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -542,6 +549,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -553,6 +562,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wake up device to play here"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Device not approved to play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Cant play this media here"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off & back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help & feedback"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 080f8d9..5ceffab 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Activado (batería: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>)"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Activo, I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Batería: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, 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="2952823007648782646">"Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activado"</string>
+ <string name="bluetooth_saved_device" msgid="4895871321722311428">"Guardado"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo; solo oído izquierdo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo; solo oído derecho"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activo; oídos izquierdo y derecho"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Suponer que las apps admiten formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Inhabilitar caché de transcodificación"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"En ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar servicios actuales en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Conector de la bocina"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositivo para reproducir aquí"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"El dispositivo no está aprobado para reproducir"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No se puede reproducir el contenido multimedia aquí"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f9dfa3e..a6e8a50 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Activo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Activo L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo, solo oído izquierdo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo, solo oído derecho"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activo, oídos izquierdo y derecho"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Considerar que las aplicaciones admiten formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Inhabilitar almacenamiento en caché para transcodificaciones"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicios en ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Consulta y controla los servicios en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa el dispositivo para reproducir contenido aquí"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo no aprobado para reproducir contenido"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"No se puede reproducir el contenido multimedia aquí"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 30e7790..ca2e9fe 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiivne, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> akut"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiivne, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> akut, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> akut"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> akut"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> akut, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> akut"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivne"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivne, ainult vasak"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivne, ainult parem"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivne, vasak ja parem"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Oleta, et rakendused toetavad kaasaegseid vorminguid"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Kuva transkodeerimise märguanded"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Transkodeerimise vahemälu keelamine"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käitatud teenused"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"See telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"See tahvelarvuti"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Äratage seade siin esitamiseks"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Seade ei ole esitamiseks heaks kiidetud"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Seda meediat ei saa siin esitada"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
<string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index fca1d1d..7abd4b0 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktibo. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktibo. Ezk. gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Esk- gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ezk. gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Esk- gailuaren bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Ezkerrekoa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Eskuinekoa: <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">"Gordeta"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktibo, ezkerrekoa soilik"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktibo, eskuinekoa soilik"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktibo, ezkerreko eta eskuineko audifonoak"</string>
@@ -115,9 +119,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Kalitate handiko audioa: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Kalitate handiko audioa"</string>
<string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"Audifonoak"</string>
- <string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Kontsumo txikiko Bluetooth bidezko audioa"</string>
+ <string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"Kontsumo txikiko audioa"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"Audifonoetara konektatuta"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audio-ra konektatuta"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Kontsumo txikiko audiora konektatuta"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Euskarriaren audiora konektatuta"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefonoaren audiora konektatuta"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Fitxategi-transferentziako zerbitzarira konektatuta"</string>
@@ -432,6 +436,9 @@
<string name="transcode_default" msgid="3784803084573509491">"Arduratu aplikazioek formatu modernoak onartzeaz"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Erakutsi transkodetze-jakinarazpenak"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desgaitu transkodetze-cachea"</string>
+ <string name="widevine_settings_title" msgid="4023329801172572917">"Widevine-ren ezarpenak"</string>
+ <string name="force_l3_fallback_title" msgid="4987972688770202547">"Behartu L3 ordezko aukera"</string>
+ <string name="force_l3_fallback_summary" msgid="3080790841069996016">"Hautatu L3 ordezko aukera behartu nahi duzun"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string>
@@ -542,6 +549,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefono hau"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tableta hau"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
@@ -553,6 +562,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktibatu gailua hemen erreproduzitzeko"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Gailua ez dago erreproduzitzeko onartuta"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ezin da erreproduzitu multimedia-eduki hau hemen"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f1c7d20..97d048f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"فعال، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> شارژ باتری"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"فعال، چپ: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> شارژ باتری"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"چپ: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"فعال"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"فعال، فقط چپ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، فقط راست"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، چپ و راست"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"فرض شود برنامهها از قالبهای مدرن پشتیبانی میکنند"</string>
<string name="transcode_notification" msgid="5560515979793436168">"نمایش اعلانهای تراتبدیل"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"غیرفعال کردن حافظه پنهان تراتبدیل"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"سرویسهای در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"مشاهده و کنترل سرویسهای در حال اجرای فعلی"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وبنما"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"هماکنون"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"این تلفن"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"این رایانه لوحی"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"برای پخش در اینجا، دستگاه را بیدار کنید"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"دستگاه برای پخش تأیید نشده است"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"نمیتوان این رسانه را اینجا پخش کرد"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
<string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 73c63f7..0adfc3a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiivinen, akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiivinen, V: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, O: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, O: akku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiivinen"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivinen, vain vasen"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivinen, vain oikea"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivinen, vasen ja oikea"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Oleta, että sovellukset tukevat nykyaikaisia formaatteja"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Näytä transkoodausilmoituksia"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Poista välimuistin transkoodaus käytöstä"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tämä puhelin"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tämä tabletti"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivoi laite, jotta voit toistaa sillä"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Laitetta ei ole hyväksytty toistoa varten"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Mediaa ei voi toistaa tällä"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
<string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cd1db07..de62739 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Actif, pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Actif, G : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"G : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D : charge à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actif, gauche seulement"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, droite seulement"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, gauche et droite"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Désactiver le cache de transcodage"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activez l\'appareil pour faire jouer le contenu ici"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"L\'appareil n\'est pas autorisé à faire jouer le contenu"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossible de faire jouer ce contenu multimédia ici"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e7b778c8..fea9bdd 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Actif, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Actif, G : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de la batterie, D : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de la batterie"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"G : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de la batterie, D : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de la batterie"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Actif"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actif, gauche uniquement"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actif, droit uniquement"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actifs, gauche et droit"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Supposer que les applications sont compatibles avec les formats modernes"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Désactiver la cache de transcodage"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Cette tablette"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activez l\'appareil pour y lire du contenu"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Appareil non autorisé à lire du contenu"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossible de lire ce contenu multimédia ici"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 64821e0..62bdf09 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Dispositivo activo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Activado. E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activo"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo (só o esquerdo)"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo (só o dereito)"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activos (o esquerdo e o dereito)"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Considerar que as aplicacións admiten formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificacións de transcodificación"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desactivar memoria caché para a transcodificación"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizos en uso"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Comproba e controla os servizos actualmente en uso"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Esta tableta"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activa o dispositivo para reproducir o contido aquí"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo non está autorizado para reproducir contido"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Non se pode reproducir este produto multimedia aquí"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 512c8ff..6b422fa 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"સક્રિય, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"સક્રિય, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"બૅટરી <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ડાબી બાજુ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"જમણી બાજુ <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="7084887715570971441">"સક્રિય, માત્ર ડાબું"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"સક્રિય, માત્ર જમણું"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"સક્રિય, ડાબું અને જમણું બન્ને"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ધારો કે ઍપ આધુનિક ફૉર્મેટ પર કામ કરે છે"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ફૉર્મેટ બદલવાની પ્રક્રિયાના નોટિફિકેશન બતાવો"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ફૉર્મેટ બદલવાની પ્રક્રિયાની કૅશ મેમરી બંધ કરો"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"આ ફોન"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"આ ટૅબ્લેટ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"અહીં ચલાવવા માટે ડિવાઇસને સક્રિય કરો"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ડિવાઇસ દ્વારા ચલાવવાની મંજૂરી આપવામાં આવી નથી"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"અહીં આ મીડિયા ચલાવી શકતા નથી"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
<string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index a2fd3ec..482c9e9 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"चालू, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"चालू, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"बाएं ईयरबड में <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी बची है"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"दाएं ईयरबड में <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="7084887715570971441">"सिर्फ़ बाईं तरफ़ वाला चालू है"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"सिर्फ़ दाईं तरफ़ वाला चालू है"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"बाईं और दाईं तरफ़ वाला चालू है"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, नए फ़ॉर्मैट के साथ काम करेंगे"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ट्रांसकोडिंग की सूचनाएं दिखाएं"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"कैश को ट्रांसकोड करने की सुविधा बंद करें"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"चालू सेवाएं"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"इस समय चल रही सेवाओं को देखें और कंट्रोल करें"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यह फ़ोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यह टैबलेट"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"मीडिया को यहां चलाने के लिए, डिवाइस को अनलॉक करें"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"डिवाइस को मीडिया चलाने की अनुमति नहीं दी गई है"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"इस मीडिया को यहां नहीं चलाया जा सकता"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
<string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index a16be41..b433748 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivan, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Baterija <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Lijevo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Desno <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">"Spremljeno"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevo i desno"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavijesti o konvertiranju"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Onemogući predmemoriju za konvertiranje"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pregledajte i kontrolirajte trenutačno pokrenute usluge"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Aktivirajte i reproducirajte ovdje"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Nije odobreno za reprodukciju"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Nemoguća je reprodukcija medija"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index ba7ab8a..7c93b2f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktív, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>-os töltöttség"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktív, B: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>-os töltöttség, J: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>-os töltöttség"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akkumulátor: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Akkumulátor: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"B: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>-os töltöttség, J: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>-os töltöttség"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Bal: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Jobb: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<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="7084887715570971441">"Aktív, csak bal"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktív, csak jobb"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktív, bal és jobb"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Annak feltételezése, hogy az alkalmazások támogatják a modern formátumokat"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Átkódolási értesítések megjelenítése"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Átkódolási gyorsítótár kikapcsolása"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Futó szolgáltatások"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ez a telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ez a táblagép"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Lejátszáshoz ébressze fel az eszközt"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Az eszköz nem játszhat le"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"A tartalom nem játszható le itt"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
<string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 243950f..1a189b1 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Ակտիվ է։ Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Ակտիվ է, Ա` Մարտկոցի լիցքը՝ <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" msgid="2893696778200201555">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ա՝ Մարտկոցի լիցքը՝ <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Ակտիվ է"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ակտիվ, միայն ձախ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ակտիվ, միայն աջ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ակտիվ, ձախ և աջ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Ցույց տալ տրանսկոդավորման մասին ծանուցումները"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Անջատել տրանսկոդավորման քեշը"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Այս հեռախոսը"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Այս պլանշետը"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Արթնացրեք սարքը՝ այստեղ նվագարկելու համար"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Նվագարկելու համար հաստատեք սարքը"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Չհաջողվեց նվագարկել մեդիա ֆայլն այստեղ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
<string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 5405334..cd8ab5a42 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktif, baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktif, Kr: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterai, Kn: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterai"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Kr: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterai, Kn: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterai"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, hanya kiri"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, hanya kanan"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Asumsikan aplikasi mendukung format modern"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Tampilkan notifikasi transcoding"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Nonaktifkan cache transcoding"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Layanan yang sedang berjalan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kontrol layanan yang sedang berjalan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ponsel ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Mengaktifkan perangkat untuk memutar di sini"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Perangkat tidak disetujui untuk memutar"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tidak dapat memutar media ini di sini"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 1b0a735..5621526 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Tengt, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Virkt, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> rafhlaða, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlaða"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> rafhlaða, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlaða"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Virkt"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Virkt, aðeins vinstra"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Virkt, aðeins hægra"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Virkt, vinstra og hægra"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Gera ráð fyrir að forrit styðji nútímasnið"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Sýna umkóðunartilkynningar"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Slökkva á skyndiminni umkóðunar"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Þjónustur í gangi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Skoða og stjórna þjónustum í gangi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Þessi sími"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Þessi spjaldtölva"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vektu tæki til að spila hér"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Tæki er ekki samþykkt til spilunar"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Ekki er hægt að spila þetta efni hér"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
<string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 44b6db6..9079750 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Attivo - Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Attivo, S: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"S: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: batteria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Attivo"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Attiva, solo sinistra"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Attiva, solo destra"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Attivo, destra e sinistra"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Presupponi che le app supportino i formati moderni"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostra notifiche relative alla transcodifica"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Disattiva memorizzazione nella cache per la transcodifica"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizi in esecuzione"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo smartphone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Questo tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Riattiva il dispositivo per riprodurre qui"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo non approvato per la riproduzione"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Impossibile riprodurre questo contenuto multimediale qui"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
<string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index d8fd33e..296ee5a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"פעיל, טעינת הסוללה: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"פעיל, שמאל: <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" msgid="2893696778200201555">"טעינת הסוללה: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"שמאל: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"פעיל"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"פועל: שמאל בלבד"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"פועל: ימין בלבד"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"פועל: ימין ושמאל"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"הנחת העבודה היא שאפליקציות תומכות בפורמטים מודרניים"</string>
<string name="transcode_notification" msgid="5560515979793436168">"הצגת התראות לגבי המרת קידוד"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"השבתת השמירה של המרת הקידוד במטמון"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"יישום WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"הטלפון הזה"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"הטאבלט הזה"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"הרמקול של אביזר העגינה"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"צריך להעיר את המכשיר"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"המכשיר לא אושר"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"אי אפשר להפעיל מדיה"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
<string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a4cf078..547da2c 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"有効、バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"有効、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" msgid="2893696778200201555">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"左 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"右 <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="7084887715570971441">"有効、左のみ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"有効、右のみ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"有効、左と右"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"アプリによる最新形式のサポートを想定"</string>
<string name="transcode_notification" msgid="5560515979793436168">"コード変換に関する通知の表示"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"コード変換のキャッシュを無効にする"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"実行中のサービス"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"現在実行中のサービスを表示して制御する"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"このデバイス"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"このタブレット"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"デバイスの起動が必要です"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"再生が許可されていません"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"このメディアは再生できません"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
<string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 0385d64..3fb9274 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"აქტიურია, ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>-ს შეადგენს"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"აქტიური, მარცხენა: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ბატარეა"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"მარცხენა: <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="2952823007648782646">"მარცხენა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"მარჯვენა <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="7084887715570971441">"აქტიური, მხოლოდ მარცხნივ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"აქტიური, მხოლოდ მარჯვნივ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"აქტიური, მარცხნივ და მარჯვნივ"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"დაშვება, რომ აპებს აქვთ თანამედროვე ფორმატების მხარდაჭერა"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ტრანსკოდირების შეტყობინებების ჩვენება"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ტრანსკოდირების ქეშის გათიშვა"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"მიმდინარე სერვისები"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ეს ტელეფონი"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ეს ტაბლეტი"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"დინამიკის სამაგრი"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"დაკავშირებული მოწყობილობა"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"დასაკრავად გამოაღვიძეთ ტელეფონი"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"მოწყობილობა არ არის ავტორიზებული დასაკრავად"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ამ მედიის აქ დაკვრა შეუძლებელია"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
<string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index a9a5519..4753d81 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Қосулы, батарея қуаты: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Қосулы, С: батарея заряды – <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" msgid="2893696778200201555">"Батарея қуаты: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"С: батарея заряды – <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Қосулы"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Тек сол жағы қосулы"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Тек оң жағы қосулы"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Екеуі де қосулы"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Қолданбалар қазіргі заманғы форматтарды қолдайды делік"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Қайта кодтау хабарландыруларын көрсету"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Қайта кодтау кэшін өшіру"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Қосылып тұрған қызметтер"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Қазір істеп тұрған қызметтерді көру және басқару"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Осы телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Осы планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Қондыру динамигі"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Осы жерде ойнату үшін құрылғыны ұйқы режимінен шығарыңыз."</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Ойнату үшін авторизация керек."</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Бұл мультимедиа файлын осы жерде ойнату мүмкін емес."</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
<string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 6cb6bc0f..2033319 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"សកម្ម ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"សកម្ម, 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" msgid="2893696778200201555">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ឆ្វេង <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"ស្ដាំ <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="7084887715570971441">"សកម្ម ខាងឆ្វេងតែប៉ុណ្ណោះ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"សកម្មខាងស្ដាំតែប៉ុណ្ណោះ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"សកម្មខាងឆ្វេង និងស្ដាំ"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"សន្មតថាកម្មវិធីអាចប្រើទម្រង់ទំនើបបាន"</string>
<string name="transcode_notification" msgid="5560515979793436168">"បង្ហាញការជូនដំណឹងអំពីការបំប្លែងកូដ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"បិទឃ្លាំងបម្រុងសម្រាប់ការបំប្លែងកូដ"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"សេវាកម្មកំពុងដំណើរការ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"មើល និងគ្រប់គ្រងសេវាកម្មកំពុងដំណើរការបច្ចុប្បន្ន"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ថេប្លេតនេះ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបករណ៍បំពងសំឡេងដែលមានជើងភ្ជាប់"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ឧបករណ៍ដែលបានភ្ជាប់"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ដាស់ឧបករណ៍ឱ្យចាក់នៅទីនេះ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ឧបករណ៍មិនព្រមឱ្យចាក់ទេ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"មិនអាចចាក់មេឌៀនេះនៅទីនេះបានទេ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string>
<string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index fa695e8..71b3e6e 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ಸಕ್ರಿಯ, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ಸಕ್ರಿಯ, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಇದೆ"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ಎಡ ಭಾಗದ ಬ್ಯಾಟರಿ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"ಬಲ ಭಾಗದ ಬ್ಯಾಟರಿ <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="7084887715570971441">"ಎಡಕಿವಿಯ ಸಾಧನ ಮಾತ್ರ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ಬಲಕಿವಿಯ ಸಾಧನ ಮಾತ್ರ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ಎಡ ಮತ್ತು ಬಲಕಿವಿಯ ಸಾಧನಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಕ್ಯಾಷ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧನವನ್ನು ಎಚ್ಚರಿಸಿ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ಪ್ಲೇ ಮಾಡಲು ಸಾಧನವನ್ನು ಅನುಮೋದಿಸಲಾಗಿಲ್ಲ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ಈ ಮಾಧ್ಯಮವನ್ನು ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
<string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6299b66..ae1822b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"활성, 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"활성, 왼쪽: 배터리 <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" msgid="2893696778200201555">"배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"왼쪽: 배터리 <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"활성"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"활성, 왼쪽만"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"활성, 오른쪽만"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"활성, 왼쪽 및 오른쪽"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"앱이 최신 형식을 지원하는 것으로 가정"</string>
<string name="transcode_notification" msgid="5560515979793436168">"트랜스코딩 알림 표시"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"트랜스코딩 캐시 사용 중지"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"실행 중인 서비스"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"현재 실행 중인 서비스 보기 및 제어"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"이 휴대전화"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"태블릿"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"기기 절전 모드 해제 후 여기에서 재생"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"기기에서 재생을 승인하지 않음"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"여기에서 이 미디어를 재생할 수 없음"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
<string name="help_label" msgid="3528360748637781274">"고객센터"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index bd0ad9b..956b272 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Иштеп жатат, батарея: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активдүү, сол: Батареянын деңгээли <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" msgid="2893696778200201555">"Батареянын деңгээли: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Сол: Батареянын деңгээли <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Жигердүү"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Иштеп жатат, сол кулак гана"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Жигердүү, оң кулакчын гана"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Жигердүү, сол жана оң кулакчын"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Транскоддоо билдирмелерин көрсөтүү"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Транскоддоо кешин өчүрүү"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ушул телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ушул планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекети үчүн динамик"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Угуу үчүн түзмөктү уйкудан чыгарыңыз"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Ойнотуу үчүн уруксат алышыңыз керек"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Медиа файлды ойното албайсыз"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
<string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 2be0376..c716e5f 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ເປີດໃຊ້ຢູ່, ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ເປີດໃຊ້, 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" msgid="2893696778200201555">"ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ອອນລາຍ"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ນຳໃຊ້ຢູ່, ຊ້າຍເທົ່ານັ້ນ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ນຳໃຊ້ຢູ່, ຂວາເທົ່ານັ້ນ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ນຳໃຊ້ຢູ່, ຊ້າຍ ແລະ ຂວາ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ສົມມຸດວ່າແອັບຮອງຮັບຮູບແບບສະໄໝໃໝ່"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ສະແດງການແຈ້ງເຕືອນການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ປິດການນຳໃຊ້ແຄສການປ່ຽນຮູບແບບລະຫັດ"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະ ຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ແທັບເລັດນີ້"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ປຸກອຸປະກອນເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ອຸປະກອນບໍ່ອະນຸມັດໃຫ້ຫຼິ້ນ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ຫຼິ້ນມີເດຍນີ້ຢູ່ບ່ອນນີ້ບໍ່ໄດ້"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
<string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index dd03307..e7ad359 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktyvus, akumuliatoriaus įkrova: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktyvi, KAIRĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, DEŠINĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumuliatoriaus įkrova: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"KAIRĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, DEŠINĖ: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktyvus"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktyvus, tik kairysis"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktyvus, tik dešinysis"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktyvus, kairysis ir dešinysis"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Manoma, kad programos palaiko modernius formatus"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Rodyti perkodavimo pranešimus"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Išjungti talpyklos perkodavimą"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Vykdomos paslaugos"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis telefonas"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetinis kompiuteris"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Pažadinkite įrenginį, kad galėtumėte čia leisti"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Įrenginys nepatvirtintas, kad būtų galima leisti"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Čia negalima leisti šio medijos failo"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
<string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 1a12a9a..4c21e1e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktīvs, akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktīvs, L: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: akumulatora uzlādes līmenis <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktīvs"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ierīce aktīva, tikai kreisā auss"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ierīce aktīva, tikai labā auss"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ierīces aktīvas, kreisā un labā auss"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Pieņemt, ka lietotnēs tiek atbalstīti moderni formāti"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Rādīt paziņojumus par pārkodēšanu"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Atspējot saglabāšanu kešatmiņā pārkodēšanai"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktīvie pakalpojumi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis tālrunis"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Šis planšetdators"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Lai atskaņotu šeit, aktivizējiet ierīci."</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Ierīce nav apstiprināta atskaņošanai."</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Šo multivides saturu nevar atskaņot šeit."</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
<string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f1ab5ef..fd40304 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активен, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активен, Л: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <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="2952823007648782646">"Одлево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Оддесно: <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="7084887715570971441">"Активно, само лево"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно, само десно"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно, лево и десно"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Претпостави дека апликациите поддржуваат модерни формати"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Прикажувај известувања за транскодирање"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Оневозможи го кешот на транскодирањето"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Погледнете и контролирајте услуги што се моментално активни"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Примена на WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Пред малку"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овој телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овој таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Разбудете го уредот за да пуштате тука"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Уредот не е одобрен за репродукција"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Овие аудиовизуелни содржини не може да се пуштат тука"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
<string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 91d8d3c..066469c 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"സജീവം, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"സജീവം, ഇടത്ത്: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"ബാറ്ററി ചാർജ് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ആണ്"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"ഇടത്ത്: <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="2952823007648782646">"ഇടത് വശത്ത് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"വലത് വശത്ത് <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="7084887715570971441">"സജീവമാണ്, ഇടത്തേത് മാത്രം"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"സജീവമാണ്, വലത്തേത് മാത്രം"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"സജീവമാണ്, ഇടത്തേതും വലത്തേതും"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ആപ്പുകൾ ആധുനിക ഫോർമാറ്റുകളെ പിന്തുണയ്ക്കുമെന്ന് കരുതുക"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ട്രാൻസ്കോഡ് ചെയ്യൽ അറിയിപ്പുകൾ കാണിക്കുക"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ട്രാൻസ്കോഡ് ചെയ്യൽ കാഷെ പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ഈ ടാബ്ലെറ്റ്"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്പീക്കർ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്റ്റ് ചെയ്ത ഉപകരണം"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"പ്ലേ ചെയ്യാൻ ഉപകരണം സജീവമാക്കുക"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ഉപകരണത്തിന് പ്ലേ ചെയ്യാനുള്ള അനുമതിയില്ല"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ഈ മീഡിയ ഇവിടെ പ്ലേ ചെയ്യാൻ കഴിയില്ല"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
<string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index be3e2370..dba6d8d 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Идэвхтэй, батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Идэвхтэй, Зүүн: Батарей <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" msgid="2893696778200201555">"Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Зүүн: Батарей <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Идэвхтэй"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Идэвхтэй, зөвхөн зүүн тал"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Идэвхтэй, зөвхөн баруун тал"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Идэвхтэй, зүүн болон баруун тал"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Аппыг орчин үеийн форматыг дэмждэг гэж үздэг"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Хөрвүүлгийн мэдэгдэл харуулах"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Хөрвүүлгийн завсрын санах ойг идэвхгүй болгох"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ажиллаж байгаа үйлчилгээнүүд"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Энэ утас"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Энэ таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Энд тоглуулахын тулд төхөөрөмжийг сэрээнэ үү"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Төхөөрөмжийг тоглуулахыг зөвшөөрөөгүй"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Энэ медиаг энд тоглуулах боломжгүй"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
<string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 80207db..f6ddef2 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"अॅक्टिव्ह, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"अॅक्टिव्ह, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"अॅक्टिव्ह"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"फक्त डावे अॅक्टिव्ह आहे"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"फक्त उजवे अॅक्टिव्ह आहे"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"डावे आणि उजवे अॅक्टिव्ह आहे"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिंग सूचना दाखवा"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ट्रान्सकोडिंग कॅशे बंद करा"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"हा फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"हा टॅबलेट"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"येथे प्ले करण्यासाठी डिव्हाइस सुरू करा"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"डिव्हाइसला प्ले करण्यासाठी मंजुरी नाही"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"हा मीडिया येथे प्ले करू शकत नाही"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
<string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 7d2ebd1..d1aba52 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktif, bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktif, Ki: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ka: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ki: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ka: bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktif"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, kiri sahaja"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, kanan sahaja"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Mengambil alih sokongan apl format moden"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Tunjukkan pemberitahuan transpengekodan"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Lumpuhkan cache transpengekodan"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Perkhidmatan dijalankan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefon ini"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tablet ini"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Bangkitkan peranti untuk main di sini"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Peranti tidak diluluskan untuk main"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Tidak dapat memainkan media ini di sini"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 484c084..8fa6a73 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ဖွင့်ထားသည်၊ ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"သုံးနေသည်၊ 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" msgid="2893696778200201555">"ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ဖွင့်ထားသည်"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ဖွင့်ထားသည်၊ ဘယ်သီးသန့်"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ဖွင့်ထားသည်၊ ညာသီးသန့်"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ဖွင့်ထားသည်၊ ဘယ်နှင့် ညာ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ဤအက်ပ်များက ဖော်မက်အသစ်များကို ပံ့ပိုးသည်"</string>
<string name="transcode_notification" msgid="5560515979793436168">"အမျိုးအစားပြောင်းခြင်း အကြောင်းကြားချက်များကို ပြရန်"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"အမျိူးအစားပြောင်းခြင်း ကက်ရှ်ကို ပိတ်ရန်"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"လက်ရှိ ဝန်ဆောင်မှုများကို ကြည့်ရှု ထိန်းသိမ်းသည်"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ဤဖုန်း"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ဤတက်ဘလက်"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ဒီမှာဖွင့်ရန် စက်ပစ္စည်းကိုနှိုးပါ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"စက်ပစ္စည်းက ဖွင့်ခွင့်မပြုပါ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ဤမီဒီယာကို ဒီမှာဖွင့်၍မရပါ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
<string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 816966c..84ba728 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiv, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bare venstre"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bare høyre"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, venstre og høyre"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Anta at apper støtter moderne formater"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Vis omkodingsvarsler"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Slå av omkodingsbuffer"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Se og kontroller tjenester som kjører"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Dette nettbrettet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vekk enheten for å spille her"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten er ikke godkjent til å spille av"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan ikke spille av dette her"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
<string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 415e2aa..4e6d87f 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"सक्रिय, ब्याट्रीको स्तर: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"सक्रिय, 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" msgid="2893696778200201555">"ब्याट्रीको स्तर: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"सक्रिय"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"बायाँ मात्र अन छ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"सक्रिय, दायाँ मात्र"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"सक्रिय, बायाँ र दायाँ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाइयोस्"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ट्रान्सकोडिङको क्यास अफ गर्नुहोस्"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यो फोन"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"यो ट्याब्लेट"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"यो मिडिया यहाँ प्ले गर्न डिभाइस सक्रिय गर्नुहोस्"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"यो डिभाइसलाई मिडिया प्ले गर्ने अनुमति छैन"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"यो मिडिया यसमा प्ले गर्न मिल्दैन"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि अन गर्नुहोस्"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
<string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index bd5d7f7..f20cb97 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Actief, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batterij"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Actief, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterij, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterij"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Batterij <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterij, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterij"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Links <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Actief, alleen links"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actief, alleen rechts"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actief, links en rechts"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Aannemen dat apps moderne indelingen ondersteunen"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Transcoderingsmeldingen tonen"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Transcodering van cache uitzetten"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Actieve services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Bekijk en beheer services die momenteel actief zijn"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Deze telefoon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Deze tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activeer het apparaat om hier af te spelen"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Apparaat niet goedgekeurd voor afspelen"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kan deze media hier niet afspelen"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index d93a7a0..534d217 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ସକ୍ରିୟ, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବ୍ୟାଟେରୀ"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ସକ୍ରିୟ, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବ୍ୟାଟେରୀ"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"ବେଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ବାମ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"ଡାହାଣ <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="7084887715570971441">"ସକ୍ରିୟ, କେବଳ ବାମ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ସକ୍ରିୟ, କେବଳ ଡାହାଣ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ସକ୍ରିୟ, ବାମ ଏବଂ ଡାହାଣ"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ଧରିନିଅନ୍ତୁ ଆପଗୁଡ଼ିକ ଆଧୁନିକ ଫର୍ମାଟଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ଟ୍ରାନ୍ସକୋଡିଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ଟ୍ରାନ୍ସକୋଡିଂ କ୍ୟାଶକୁ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ଏହି ଟାବଲେଟ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ଏଠାରେ ପ୍ଲେ କରିବା ପାଇଁ ଡିଭାଇସକୁ ସକ୍ରିୟ କରନ୍ତୁ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ପ୍ଲେ କରିବା ପାଇଁ ଡିଭାଇସକୁ ଅନୁମୋଦନ କରାଯାଇନାହିଁ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ଏଠାରେ ମିଡିଆ ପ୍ଲେ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
<string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e9242c8..f0f656ef 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ਕਿਰਿਆਸ਼ੀਲ, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ਕਿਰਿਆਸ਼ੀਲ, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਖੱਬਾ"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਸੱਜਾ"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ਕਿਰਿਆਸ਼ੀਲ, ਖੱਬਾ ਅਤੇ ਸੱਜਾ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਕੈਸ਼ੇ ਬੰਦ ਕਰੋ"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲੀਕਰਨ"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ਇਹ ਟੈਬਲੈੱਟ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ਇੱਥੇ ਮੀਡੀਆ ਚਲਾਉਣ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ਡੀਵਾਈਸ ਨੂੰ ਮੀਡੀਆ ਚਲਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ਇਸ ਮੀਡੀਆ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਚਲਾਇਆ ਜਾ ਸਕਦਾ"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
<string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 02224fb..af9b73f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktywne, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterii"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktywna, L: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Urządzenie aktywne"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktywne, tylko lewa strona"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktywne, tylko prawa strona"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktywny, lewa i prawa strona"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Zakładaj, że aplikacje obsługują nowoczesne formaty"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Pokaż powiadomienia transkodowania"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Wyłącz pamięć podręczną transkodowania"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Uruchomione usługi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Wyświetl obecnie uruchomione usługi i nimi zarządzaj"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ten telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ten tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Wybudź, aby tu odtworzyć"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Urządzenie nie ma uprawnień do odtwarzania"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Nie można odtworzyć tego pliku multimedialnego"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3ee80e5..78e8679 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Ativo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Ativo, E: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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">"Salvo"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas o esquerdo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas o direito"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desativar cache da transcodificação"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ativar dispositivo para tocar aqui"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo não foi aprovado para reprodução"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir essa mídia aqui"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 091d1a8..1be30d1 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Ativo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Ativo, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Bateria. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Ativo, apenas esquerdo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas direito"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Assumir que as apps suportam formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desativar cache de transcodificação"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telemóvel"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregam."</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ative o dispositivo para reproduzir aqui"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispositivo não aprovado para reprodução"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir este conteúdo multimédia aqui"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3ee80e5..78e8679 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Ativo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Ativo, E: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"E: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: Bateria do <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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">"Salvo"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas o esquerdo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas o direito"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Desativar cache da transcodificação"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ativar dispositivo para tocar aqui"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"O dispositivo não foi aprovado para reprodução"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Não é possível reproduzir essa mídia aqui"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f0b75ad..4c6fef6 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Activ, baterie <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Activ, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterie, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterie"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterie, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterie"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Activ"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activ, numai stânga"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activ, numai dreapta"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activ, stânga și dreapta"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Presupune că aplicațiile acceptă formatele moderne"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Vezi notificările privind transcodarea"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Dezactivează memoria cache pentru transcodare"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vezi și controlează serviciile care funcționează în prezent"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Această tabletă"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Activează dispozitivul pentru a reda aici"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Dispozitivul nu este aprobat pentru redare"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Conținutul media nu poate fi redat aici"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Oprește și repornește dispozitivul."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
<string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 33697eb..ec64802 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активно. Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активно. Л: батарея <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" msgid="2893696778200201555">"Уровень заряда: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: батарея <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активно"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активен, только левое ухо"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активен, только правое ухо"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активен, оба уха"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Считать, что приложения поддерживают современные форматы кодирования"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Показывать уведомления о перекодировании"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Отключить кеш перекодирования"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Работающие службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Просмотр работающих служб и управление ими"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Этот смартфон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Этот планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Для воспроизведения выведите устройство из спящего режима."</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Для воспроизведения необходима авторизация."</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Невозможно воспроизвести медиафайл."</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
<string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index e198c5b..2aa69e5 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ක්රියාකාරී, බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ක්රියාත්මක, ව: බැටරිය <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" msgid="2893696778200201555">"බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"ව: බැටරිය <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"ක්රියාකාරී"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"සක්රිය, වම පමණි"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"සක්රිය, දකුණ පමණි"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"සක්රිය, වම සහ දකුණ"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"යෙදුම් නවීන ආකෘති සඳහා සහාය දක්වයි යැයි උපකල්පනය කරමු"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ට්රාන්ස්කෝඩින් දැනුම්දීම් පෙන්වන්න"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ට්රාන්ස්කොඩින් හැඹිලිය අබල කරන්න"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ධාවනය වන සේවා"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්රියාත්මක කිරීම"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"මෙම ටැබ්ලටය"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"මෙහි වාදනය කිරීමට උපාංගය අවදි කරන්න"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"උපාංගය වාදනය කිරීමට අනුමත කර නැත"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"මෙම මාධ්ය මෙහි වාදනය කළ නොහැක"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
<string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 95dd4ae..1f5ebff 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktívne, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktívne, Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktívne"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktívne, iba ľavá strana"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktívne, iba pravá strana"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktívne, ľavá aj pravá strana"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Prepdokladať, že aplikácie podporujú moderné formáty"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Zobraziť upozornenia prekódovania"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Deaktivácia vyrovnávacej pamäte prekódovania"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spustené služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Zobrazovať a riadiť aktuálne spustené služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefón"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Tento tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ak chcete prehrávať obsah tu, prebuďte zariadenie"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Prehrávanie v tomto zariadení nie je schválené"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Médium sa tu nedá prehrať"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
<string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 0a046c4..4809cbb 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivno, baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo levo"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, levo in desno"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Aplikacije naj bi podpirale sodobne oblike zapisov"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Prikaz obvestil o prekodiranju"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Onemogoči predpomnilnik za prekodiranje"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Zagnane storitve"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Preglejte in nadzorujte storitve, ki so trenutno zagnane."</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ta telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ta tablični računalnik"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Zbudite napravo za predvajanje tu"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Naprava ni odobrena za predvajanje."</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Te predstavnosti ni mogoče predvajati tukaj."</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 4b977d5..627ad8f 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiv, L: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateria <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktive, vetëm majtas"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktive, vetëm djathtas"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktive, majtas dhe djathtas"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Supozo se aplikacionet i mbështetin formatet moderne"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Shfaq njoftimet e transkodimit"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Çaktivizo memorien specifike të transkodimit"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Shërbimet në ekzekutim"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ky telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ky tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Riaktivizoje pajisjen për të luajtur këtu"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Pajisja nuk është miratuar për të luajtur"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Kjo media nuk mund të luhet këtu"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
<string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 1f7745f..4bac270 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активан, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активно, Л: <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" msgid="2893696778200201555">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Батерија, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <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="2952823007648782646">"Лева <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"Десна <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="7084887715570971441">"Активно, само с леве стране"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно, с десне стране"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно, с леве и десне стране"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Подразумевај да апликације подржавају модерне формате"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Приказуј обавештења о транскодирању"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Онемогући кеш транскодирања"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Покренуте услуге"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Приказ и контрола тренутно покренутих услуга"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овај телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Овај таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Пробудите уређај да бисте пустили овде"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Уређај није одобрен за репродукцију"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Не можете да пустите овај медијски фајл овде"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
<string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index aeda002..b202635 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktiv, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri. H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri. H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktiv"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bara vänster"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bara höger"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, vänster och höger"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Anta att appar har stöd för moderna format"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Visa aviseringar för omkodning"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Inaktivera cacheminne för omkodning"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktiva tjänster"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visa och styr aktiva tjänster"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Den här telefonen"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Den här surfplattan"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Väck enheten för att spela upp här"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Enheten är inte godkänd"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Det går inte att spela upp detta här"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 704cf2a..c63b610 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Inatumika, betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Inatumika, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ya betri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ya betri"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ya betri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ya betri"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Kushoto <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Inatumika, kushoto pekee"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Inatumika, kulia pekee"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Inatumika, kushoto na kulia"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Chukulia kuwa programu zinatumia miundo ya kisasa"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Onyesha arifa za kubadilisha muundo wa faili"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Zima kipengele cha akiba ya kubadilisha muundo wa faili"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Huduma zinazoendeshwa"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Onyesha na udhibiti huduma zinazoendeshwa kwa sasa"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Simu hii"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Kompyuta kibao hii"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Washa skrini ya kifaa ili ucheze maudhui hapa"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Kifaa hakijaidhinishwa ili kucheza maudhui"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Huwezi kucheza maudhui haya hapa"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
<string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7ab577c..49351e8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"செயலில் உள்ளது, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"செயலில் உள்ளது, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"செயலில் உள்ளது"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"இடது பக்கம் மட்டும் செயலில் உள்ளது"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"வலது பக்கம் மட்டும் செயலில் உள்ளது"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"வலது மற்றும் இடது பக்கம் செயலில் உள்ளது"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ஆப்ஸ் மாடர்ன் வடிவங்களை ஆதரிக்கும்படி அமை"</string>
<string name="transcode_notification" msgid="5560515979793436168">"குறிமாற்ற அறிவிப்புகளைக் காட்டு"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"குறிமாற்றத்திற்கான தற்காலிக சேமிப்பை முடக்குதல்"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"இயங்கும் சேவைகள்"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"இந்த மொபைல்"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"இந்த டேப்லெட்"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"இங்கே பிளே செய்ய உங்கள் சாதனத்தைச் சார்ஜ் செய்யுங்கள்"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"பிளே செய்வதற்குச் சாதனம் அனுமதிக்கப்படவில்லை"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"இந்த மீடியாவை இங்கே பிளே செய்ய முடியவில்லை"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
<string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 8e6e635..89e7bb7 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"యాక్టివ్గా ఉంది, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"యాక్టివ్, 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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"బ్యాటరీ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ఎడమ వైపు <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"కుడి వైపు <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="7084887715570971441">"యాక్టివ్గా ఉంది, ఎడమవైపు మాత్రమే యాక్టివ్గా ఉంది"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"యాక్టివ్గా ఉంది, కుడివైపు యాక్టివ్గా ఉంది"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"యాక్టివ్గా ఉంది, ఎడమవైపు, కుడివైపు యాక్టివ్గా ఉంది"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"యాప్లు ఆధునిక ఫార్మాట్లకు సపోర్ట్ చేస్తాయని అనుకోండి"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్కోడింగ్ నోటిఫికేషన్లను చూపండి"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ట్రాన్స్కోడింగ్ కాష్ను డిజేబుల్ చేయండి"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సర్వీస్లు"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్లను చూడండి, కంట్రోల్ చేయండి"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ఈ ఫోన్"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"ఈ టాబ్లెట్"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్టర్నల్ పరికరం"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ఇక్కడ ప్లే చేయడానికి పరికరాన్ని మేల్కొలపండి"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"ప్లే చేయడానికి పరికరానికి అనుమతి లేదు"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"ఈ మీడియాను ఇక్కడ ప్లే చేయడం సాధ్యపడదు."</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
<string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 5933acb..aecfc6f 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"ใช้งานอยู่ แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"ใช้งานอยู่ 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" msgid="2893696778200201555">"แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"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="2952823007648782646">"ฝั่งซ้าย <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"ฝั่งขวา <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="7084887715570971441">"ใช้งานอยู่ เฉพาะข้างซ้าย"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ใช้งานอยู่ เฉพาะข้างขวา"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ใช้งานอยู่ ข้างซ้ายและขวา"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"ถือว่าแอปรองรับรูปแบบสมัยใหม่"</string>
<string name="transcode_notification" msgid="5560515979793436168">"แสดงการแจ้งเตือนการแปลง"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ปิดใช้แคชสำหรับการแปลง"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"บริการที่ทำงานอยู่"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"แท็บเล็ตเครื่องนี้"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นวางลำโพง"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"ปลุกระบบอุปกรณ์เพื่อเล่นที่นี่"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"อุปกรณ์ไม่อนุมัติให้เล่น"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"เล่นสื่อนี้ที่นี่ไม่ได้"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
<string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a268dc6..c579dea 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktibo, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktibo, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Baterya <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya"</string>
+ <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Kaliwa <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"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="7084887715570971441">"Aktibo, kaliwa lang"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktibo, kanan lang"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktibo, kaliwa at kanan"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Ipagpalagay na sinusuportahan ng mga app ang mga modernong format"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Ipakita ang mga notification sa pag-transcode"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"I-disable ang cache ng pag-transcode"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Mga tumatakbong serbisyo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ang teleponong ito"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Ang tablet na ito"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"I-wake ang device para i-play dito"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Hindi naaprubahan ang device para sa pag-play"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Hindi ma-play ang media na ito rito"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9d4502f..64cb61b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Etkin, pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Etkin, Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pil, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pil, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Etkin"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Yalnızca sol tarafta etkin"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Yalnızca sağ tarafta etkin"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Sol ve sağ tarafta etkin"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Uygulamaların modern biçimleri desteklediğini varsay"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Kod dönüştürme bildirimlerini göster"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Kod dönüştürme önbelleğini devre dışı bırak"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Çalışan hizmetler"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Bu tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Burada oynatmak için cihazı uyandırın"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Cihaz, oynatma işlemini onaylamadı"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Bu medya burada oynatılamıyor"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9d1fa4c..a52a5e72 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активовано, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активний. Л: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Активовано"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активовано, лише лівий"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активовано, лише правий"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активовано, лівий і правий"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Вважати, що додатки підтримують сучасні формати"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Показувати сповіщення про перекодування"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Вимкнути кеш перекодування"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запущені сервіси"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Переглянути й налаштувати запущені сервіси"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Цей телефон"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Цей планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Виведіть із режиму сну, щоб відтворювати"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Не схвалено для відтворення"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Цей медіаконтент не підтримується"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
<string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 94f09a6..0d4dc6c4 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"فعال، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"فعال، بائيں: <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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"بیٹری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"بائيں: <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="2952823007648782646">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> چھوڑ دیا"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"دائیں <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="7084887715570971441">"فعال، صرف بائیں طرف"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، صرف دائیں طرف"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، صرف بائیں اور دائیں طرف"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"فرض کریں کہ ایپس جدید فارمیٹس کو سپورٹ کرتی ہیں"</string>
<string name="transcode_notification" msgid="5560515979793436168">"ٹرانسکوڈنگ اطلاعات دکھائیں"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ٹرانسکوڈنگ کیش غیر فعال کریں"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView کا نفاذ"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"یہ فون"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"یہ ٹیبلیٹ"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"یہاں چلانے کے لیے آلہ کو اٹھائیں"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"آلہ کو چلانے کے لیے اجازت نہیں دی گئی ہے"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"یہاں اس میڈیا کو چلایا نہیں جا سکتا"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
<string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 446c0fd..2be1fcd 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Faol, batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Faol, L: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Faol"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Faol, faqat chap"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Faol, faqat oʻng"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Faol, chap va oʻng"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Ilovalarda zamonaviy kodlash formatlari ishlaydi deb hisoblash"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Transkripsiya bildirishnomalarini chiqarish"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Transkripsiya keshini faolsizlantirish"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Shu telefon"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Shu planshet"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Ijro etish uchun qurilmani uyqu rejimidan chiqaring."</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Qurilmada ijro ruxsati yoʻq"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Media fayl ijro etilmaydi"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
<string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 0285619..bc903d7 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Đang hoạt động, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Đang hoạt động, Trái: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Phải: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Trái: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Phải: Mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Đang hoạt động"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Đang hoạt động, chỉ tai bên trái"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Đang hoạt động, chỉ tai phải"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Đang hoạt động, cả tai phải và tai trái"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Giả định rằng các ứng dụng hỗ trợ định dạng hiện đại"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Hiện thông báo chuyển mã"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Vô hiệu hóa bộ nhớ đệm dùng để chuyển mã"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Các dịch vụ đang chạy"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Xem và kiểm soát các dịch vụ đang chạy"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Điện thoại này"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Máy tính bảng này"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Đánh thức thiết bị để phát tại đây"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Thiết bị chưa được phép phát"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Không thể phát nội dung nghe nhìn này tại đây"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
<string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index db8fc1d..007c797 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -97,8 +97,12 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"使用中,电池电量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"使用中,左:<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" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 的电量"</string>
+ <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"电池电量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:目前电量为 <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="2952823007648782646">"左耳机电池电量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level_untethered_right" msgid="6525710737740083276">"右耳机电池电量 <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="7084887715570971441">"使用中,仅左耳助听器"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,仅右耳助听器"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳助听器"</string>
@@ -432,6 +436,12 @@
<string name="transcode_default" msgid="3784803084573509491">"假设应用支持现代格式"</string>
<string name="transcode_notification" msgid="5560515979793436168">"显示转码通知"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"停用转码缓存"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在运行的服务"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看和控制当前正在运行的服务"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string>
@@ -542,6 +552,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"这部手机"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"这台平板电脑"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
@@ -553,6 +565,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"若要在此设备上播放,请唤醒设备"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"设备未获准播放"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"无法在此设备上播放该媒体内容"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
<string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 84cab33..f454a68 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"使用中,電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"已啟用,左:<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" msgid="2893696778200201555">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:<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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新型格式"</string>
<string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"停用轉碼快取"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"此手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"此平板電腦"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"必須喚醒裝置才能在此播放"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"裝置未獲核准播放"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"無法在此播放此媒體內容"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f1fbc03..1d04030 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"使用中,電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"已啟用,左:目前電量為 <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" msgid="2893696778200201555">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"左:目前電量為 <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>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"使用中"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新格式"</string>
<string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"停用轉碼快取"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在運作的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並管理目前正在執行的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"這支手機"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"這台平板電腦"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"必須喚醒裝置才能在此播放"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"裝置未獲准播放"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"無法在此播放這個媒體內容"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index cb89d4e..c0c3b48 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -97,8 +97,16 @@
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Kuyasebenza, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Kuyasebenza, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ibhethri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri"</string>
+ <!-- no translation found for tv_bluetooth_battery_level (8786353985605532846) -->
+ <skip />
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ibhethri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri"</string>
+ <!-- no translation found for bluetooth_battery_level_untethered_left (2952823007648782646) -->
+ <skip />
+ <!-- no translation found for bluetooth_battery_level_untethered_right (6525710737740083276) -->
+ <skip />
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Iyasebenza"</string>
+ <!-- no translation found for bluetooth_saved_device (4895871321722311428) -->
+ <skip />
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Iyasebenza, ngakwesokunxele kuphela"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Iyasebenza, ngakwesokudla kuphela"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Iyasebenza, ngakwesokunxele nakwesokudla"</string>
@@ -432,6 +440,12 @@
<string name="transcode_default" msgid="3784803084573509491">"Kuthathe njengokungathi izinhlelo zokusebenza zisekela amafomethi esimanje"</string>
<string name="transcode_notification" msgid="5560515979793436168">"Bonisa izaziso zokudlulisela ikhodi"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"Khubaza inqolobane yokudlulisela ikhodi"</string>
+ <!-- no translation found for widevine_settings_title (4023329801172572917) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_title (4987972688770202547) -->
+ <skip />
+ <!-- no translation found for force_l3_fallback_summary (3080790841069996016) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"Amasevisi asebenzayo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Buka futhi ulawule amasevisi asebenzayo okwamanje"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string>
@@ -542,6 +556,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string>
<string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Le foni"</string>
<string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Le thebulethi"</string>
+ <!-- no translation found for media_transfer_this_device_name (8899776297775466649) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
@@ -553,6 +569,22 @@
<string name="media_output_status_device_in_low_power_mode" msgid="8184631698321758451">"Vusa idivayisi ukuze udlale lapha"</string>
<string name="media_output_status_unauthorized" msgid="5880222828273853838">"Idivayisi ayigunyaziwe ukuthi idlale"</string>
<string name="media_output_status_track_unsupported" msgid="5576313219317709664">"Awukwazi ukudlala le midiya lapha"</string>
+ <!-- no translation found for tv_media_transfer_connected (5145011475885290725) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_fallback_title (3674360098755328601) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_fallback_title (3098685494578519940) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_arc_subtitle (1040017851325069082) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_earc_subtitle (645191413103303077) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_default (38102257053315304) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_hdmi (2229000864416329818) -->
+ <skip />
+ <!-- no translation found for tv_media_transfer_internal_speakers (2433193551482972117) -->
+ <skip />
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
<string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
index 88dcc0d..83c106b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java
@@ -16,9 +16,16 @@
package com.android.settingslib.fuelgauge;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.List;
public final class BatteryUtils {
@@ -30,4 +37,35 @@
return context.registerReceiver(
/*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
+
+ /** Gets the current active accessibility related packages. */
+ public static ArraySet<String> getA11yPackageNames(Context context) {
+ context = context.getApplicationContext();
+ final ArraySet<String> packageNames = new ArraySet<>();
+ final String defaultTtsPackageName = Settings.Secure.getString(
+ context.getContentResolver(), Settings.Secure.TTS_DEFAULT_SYNTH);
+ if (defaultTtsPackageName != null) {
+ packageNames.add(defaultTtsPackageName);
+ }
+ // Checks the current active packages.
+ final AccessibilityManager accessibilityManager =
+ context.getSystemService(AccessibilityManager.class);
+ if (!accessibilityManager.isEnabled()) {
+ return packageNames;
+ }
+ final List<AccessibilityServiceInfo> serviceInfoList =
+ accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ if (serviceInfoList == null || serviceInfoList.isEmpty()) {
+ return packageNames;
+ }
+ for (AccessibilityServiceInfo serviceInfo : serviceInfoList) {
+ final ComponentName serviceComponent = ComponentName.unflattenFromString(
+ serviceInfo.getId());
+ if (serviceComponent != null) {
+ packageNames.add(serviceComponent.getPackageName());
+ }
+ }
+ return packageNames;
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
new file mode 100644
index 0000000..c3e0c0b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatteryUtilsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowAccessibilityManager;
+
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryUtilsTest {
+ private static final String DEFAULT_TTS_PACKAGE = "com.abc.talkback";
+ private static final String ACCESSIBILITY_PACKAGE = "com.def.talkback";
+
+ private Context mContext;
+ private AccessibilityManager mAccessibilityManager;
+ private ShadowAccessibilityManager mShadowAccessibilityManager;
+
+ @Mock
+ private AccessibilityServiceInfo mAccessibilityServiceInfo1;
+ @Mock
+ private AccessibilityServiceInfo mAccessibilityServiceInfo2;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ doReturn(mContext).when(mContext).getApplicationContext();
+ mAccessibilityManager = spy(mContext.getSystemService(AccessibilityManager.class));
+ mShadowAccessibilityManager = shadowOf(mAccessibilityManager);
+ doReturn(mAccessibilityManager).when(mContext)
+ .getSystemService(AccessibilityManager.class);
+
+ setTtsPackageName(DEFAULT_TTS_PACKAGE);
+ doReturn(Arrays.asList(mAccessibilityServiceInfo1, mAccessibilityServiceInfo2))
+ .when(mAccessibilityManager)
+ .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ doReturn(ACCESSIBILITY_PACKAGE + "/.TalkbackService").when(mAccessibilityServiceInfo1)
+ .getId();
+ doReturn("dummy_package_name").when(mAccessibilityServiceInfo2).getId();
+ }
+
+ @Test
+ public void getBatteryIntent_registerReceiver() {
+ BatteryUtils.getBatteryIntent(mContext);
+ verify(mContext).registerReceiver(eq(null), any(IntentFilter.class));
+ }
+
+ @Test
+ public void getA11yPackageNames_returnDefaultTtsPackageName() {
+ mShadowAccessibilityManager.setEnabled(false);
+
+ assertThat(BatteryUtils.getA11yPackageNames(mContext))
+ .containsExactly(DEFAULT_TTS_PACKAGE);
+ }
+
+ @Test
+ public void getA11yPackageNames_returnExpectedPackageNames() {
+ mShadowAccessibilityManager.setEnabled(true);
+
+ assertThat(BatteryUtils.getA11yPackageNames(mContext))
+ .containsExactly(DEFAULT_TTS_PACKAGE, ACCESSIBILITY_PACKAGE);
+ }
+
+ private void setTtsPackageName(String defaultTtsPackageName) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.TTS_DEFAULT_SYNTH, defaultTtsPackageName);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
index 942e915..74a282f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
@@ -21,30 +21,25 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.text.TextUtils;
import android.view.View;
-import android.widget.Switch;
+import android.widget.CompoundButton;
import android.widget.TextView;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settingslib.widget.mainswitch.R;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class MainSwitchBarTest {
- private Context mContext;
- private MainSwitchBar mBar;
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final MainSwitchBar mBar = new MainSwitchBar(mContext);
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mBar = new MainSwitchBar(mContext);
- }
+ private final CompoundButton mSwitch = mBar.findViewById(android.R.id.switch_widget);
@Test
public void setChecked_true_shouldChecked() {
@@ -60,7 +55,7 @@
mBar.setTitle(title);
final TextView textView = ((TextView) mBar.findViewById(R.id.switch_text));
- assertThat(textView.getText()).isEqualTo(title);
+ assertThat(textView.getText().toString()).isEqualTo(title);
}
@Test
@@ -69,23 +64,18 @@
mBar.setTitle(title);
- final Switch switchObj = mBar.getSwitch();
- assertThat(TextUtils.isEmpty(switchObj.getContentDescription())).isTrue();
+ assertThat(mSwitch.getContentDescription()).isNull();
}
@Test
public void getSwitch_shouldNotNull() {
- final Switch switchObj = mBar.getSwitch();
-
- assertThat(switchObj).isNotNull();
+ assertThat(mSwitch).isNotNull();
}
@Test
public void getSwitch_shouldNotFocusableAndClickable() {
- final Switch switchObj = mBar.getSwitch();
-
- assertThat(switchObj.isFocusable()).isFalse();
- assertThat(switchObj.isClickable()).isFalse();
+ assertThat(mSwitch.isFocusable()).isFalse();
+ assertThat(mSwitch.isClickable()).isFalse();
}
@Test
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c7e5bf9..ed03d94 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -592,6 +592,9 @@
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pSetWfdInfo -->
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
+ <!-- Permission required for CTS test - CtsThreadNetworkTestCases -->
+ <uses-permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"/>
+
<!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
<uses-permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING" />
@@ -864,6 +867,7 @@
<!-- Permissions required for CTS test - CtsVoiceInteractionTestCases -->
<uses-permission android:name="android.permission.RESET_HOTWORD_TRAINING_DATA_EGRESS_COUNT" />
<uses-permission android:name="android.permission.RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA" />
+ <uses-permission android:name="android.permission.GET_BINDING_UID_IMPORTANCE" />
<application
android:label="@string/app_label"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 88abf69..0e9f8b1 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -187,6 +187,8 @@
"androidx.dynamicanimation_dynamicanimation",
"androidx-constraintlayout_constraintlayout",
"androidx.exifinterface_exifinterface",
+ "androidx.room_room-runtime",
+ "androidx.room_room-ktx",
"com.google.android.material_material",
"kotlinx_coroutines_android",
"kotlinx_coroutines",
@@ -207,10 +209,16 @@
],
manifest: "AndroidManifest.xml",
- javacflags: ["-Adagger.fastInit=enabled"],
+ javacflags: [
+ "-Adagger.fastInit=enabled",
+ "-Aroom.schemaLocation=frameworks/base/packages/SystemUI/schemas",
+ ],
kotlincflags: ["-Xjvm-default=all"],
- plugins: ["dagger2-compiler"],
+ plugins: [
+ "androidx.room_room-compiler-plugin",
+ "dagger2-compiler",
+ ],
lint: {
extra_check_modules: ["SystemUILintChecker"],
@@ -466,6 +474,8 @@
"androidx.dynamicanimation_dynamicanimation",
"androidx-constraintlayout_constraintlayout",
"androidx.exifinterface_exifinterface",
+ "androidx.room_room-runtime",
+ "androidx.room_room-ktx",
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"kotlinx_coroutines_test",
@@ -530,7 +540,10 @@
"--extra-packages",
"com.android.systemui",
],
- plugins: ["dagger2-compiler"],
+ plugins: [
+ "androidx.room_room-compiler-plugin",
+ "dagger2-compiler",
+ ],
lint: {
test: true,
extra_check_modules: ["SystemUILintChecker"],
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index d306911..0480b9d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -32,20 +32,6 @@
]
},
{
- // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
- "name": "SystemUIGoogleBiometricsScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
- // The test doesn't run on AOSP Cuttlefish
- "keywords": ["internal"]
- },
- {
// Permission indicators
"name": "CtsPermissionUiTestCases",
"options": [
@@ -73,6 +59,7 @@
]
}
],
+
"auto-end-to-end-postsubmit": [
{
"name": "AndroidAutomotiveHomeTests",
@@ -91,6 +78,7 @@
]
}
],
+
"postsubmit": [
{
// Permission indicators
@@ -100,22 +88,9 @@
"include-filter": "android.permissionui.cts.CameraMicIndicatorsPermissionTest"
}
]
- },
- {
- "name": "SystemUIGoogleScreenshotTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- }
- ]
}
],
+
// v2/sysui/suite/test-mapping-sysui-screenshot-test
"sysui-screenshot-test": [
{
@@ -151,8 +126,27 @@
"exclude-annotation": "android.platform.test.annotations.Postsubmit"
}
]
+ },
+ {
+ // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
+ "name": "SystemUIGoogleBiometricsScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.Postsubmit"
+ }
+ ]
}
],
+
// v2/sysui/suite/test-mapping-sysui-screenshot-test-staged
"sysui-screenshot-test-staged": [
{
@@ -163,12 +157,6 @@
},
{
"include-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
}
]
},
@@ -180,12 +168,18 @@
},
{
"include-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
+ "name": "SystemUIGoogleBiometricsScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
},
{
- "include-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
+ "include-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 96e1e3f..085fc29 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -63,7 +63,7 @@
private static final String TAG = "A11yMenuService";
private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
- private static final long TAKE_SCREENSHOT_DELAY_MS = 100L;
+ private static final long HIDE_UI_DELAY_MS = 100L;
private static final int BRIGHTNESS_UP_INCREMENT_GAMMA =
(int) Math.ceil(BrightnessUtils.GAMMA_SPACE_MAX * 0.11f);
@@ -296,7 +296,14 @@
} else if (viewTag == ShortcutId.ID_RECENT_VALUE.ordinal()) {
performGlobalActionInternal(GLOBAL_ACTION_RECENTS);
} else if (viewTag == ShortcutId.ID_LOCKSCREEN_VALUE.ordinal()) {
- performGlobalActionInternal(GLOBAL_ACTION_LOCK_SCREEN);
+ if (Flags.a11yMenuHideBeforeTakingAction()) {
+ // Delay before locking the screen to give time for the UI to close.
+ mHandler.postDelayed(
+ () -> performGlobalActionInternal(GLOBAL_ACTION_LOCK_SCREEN),
+ HIDE_UI_DELAY_MS);
+ } else {
+ performGlobalActionInternal(GLOBAL_ACTION_LOCK_SCREEN);
+ }
} else if (viewTag == ShortcutId.ID_QUICKSETTING_VALUE.ordinal()) {
performGlobalActionInternal(GLOBAL_ACTION_QUICK_SETTINGS);
} else if (viewTag == ShortcutId.ID_NOTIFICATION_VALUE.ordinal()) {
@@ -306,7 +313,7 @@
// Delay before taking a screenshot to give time for the UI to close.
mHandler.postDelayed(
() -> performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT),
- TAKE_SCREENSHOT_DELAY_MS);
+ HIDE_UI_DELAY_MS);
} else {
performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT);
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 069ba6c..9700bc6 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -15,6 +15,13 @@
}
flag {
+ name: "notification_async_hybrid_view_inflation"
+ namespace: "systemui"
+ description: "Inflates hybrid (single-line) notification views from the background thread."
+ bug: "217799515"
+}
+
+flag {
name: "notifications_footer_view_refactor"
namespace: "systemui"
description: "Enables the refactored version of the footer view in the notification shade "
@@ -39,10 +46,11 @@
}
flag {
- name: "notification_async_hybrid_view_inflation"
+ name: "notifications_live_data_store_refactor"
namespace: "systemui"
- description: "Inflates the hybrid (single-line) notification views form the background thread."
- bug: "217799515"
+ description: "Replaces NotifLiveDataStore with ActiveNotificationListRepository, and updates consumers. "
+ "Should not bring any behavior changes."
+ bug: "308623704"
}
flag {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 87a8c35..17726ab 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.communal.ui.compose
import android.appwidget.AppWidgetHostView
@@ -12,19 +28,26 @@
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Card
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.model.CommunalContentUiModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.res.R
@Composable
fun CommunalHub(
@@ -64,10 +87,17 @@
ContentCard(
modifier = Modifier.size(Dimensions.CardWidth, widget.size.dp()),
model = widget,
+ deleteOnClick = viewModel::onDeleteWidget
)
}
}
}
+ IconButton(onClick = viewModel::onOpenWidgetPicker) {
+ Icon(
+ Icons.Default.Add,
+ LocalContext.current.getString(R.string.button_to_open_widget_picker)
+ )
+ }
}
}
@@ -80,19 +110,36 @@
@Composable
private fun ContentCard(
model: CommunalContentUiModel,
+ deleteOnClick: (id: Int) -> Unit,
modifier: Modifier = Modifier,
) {
- AndroidView(
- modifier = modifier,
- factory = {
- model.view.apply {
- if (this is AppWidgetHostView) {
- val size = SizeF(Dimensions.CardWidth.value, model.size.dp().value)
- updateAppWidgetSize(Bundle.EMPTY, listOf(size))
- }
+ // TODO(b/309009246): update background color
+ Box(
+ modifier = modifier.fillMaxSize().background(Color.White),
+ ) {
+ // TODO(b/308148193): this will be cleaned up soon once the change to convert to
+ // CommunalContentUiModel interface is merged
+ val widgetId = getWidgetId(model.id)
+ widgetId?.let {
+ IconButton(onClick = { deleteOnClick(it) }) {
+ Icon(
+ Icons.Default.Close,
+ LocalContext.current.getString(R.string.button_to_remove_widget)
+ )
}
- },
- )
+ }
+ AndroidView(
+ modifier = modifier,
+ factory = {
+ model.view.apply {
+ if (this is AppWidgetHostView) {
+ val size = SizeF(Dimensions.CardWidth.value, model.size.dp().value)
+ updateAppWidgetSize(Bundle.EMPTY, listOf(size))
+ }
+ }
+ },
+ )
+ }
}
private fun CommunalContentSize.dp(): Dp {
@@ -103,6 +150,10 @@
}
}
+private fun getWidgetId(id: String): Int? {
+ return if (id.startsWith("widget_")) id.substring("widget_".length).toInt() else null
+}
+
// Sizes for the tutorial placeholders.
private val tutorialContentSizes =
listOf(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index 041fc48..009f8bb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -36,7 +36,7 @@
fun SceneScope.animateSharedIntAsState(
value: Int,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Int> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -65,7 +65,7 @@
fun SceneScope.animateSharedFloatAsState(
value: Float,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Float> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -94,7 +94,7 @@
fun SceneScope.animateSharedDpAsState(
value: Dp,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
canOverflow: Boolean = true,
): State<Dp> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow)
@@ -123,7 +123,7 @@
fun SceneScope.animateSharedColorAsState(
value: Color,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
): State<Color> {
return animateSharedValueAsState(value, key, element, ::lerp, canOverflow = false)
}
@@ -145,7 +145,7 @@
internal fun <T> animateSharedValueAsState(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
- element: Element,
+ element: Element?,
key: ValueKey,
value: T,
lerp: (T, T, Float) -> T,
@@ -153,9 +153,9 @@
): State<T> {
val sharedValue =
Snapshot.withoutReadObservation {
- element.sceneValues.getValue(scene.key).sharedValues.getOrPut(key) {
- Element.SharedValue(key, value)
- } as Element.SharedValue<T>
+ val sharedValues =
+ element?.sceneValues?.getValue(scene.key)?.sharedValues ?: scene.sharedValues
+ sharedValues.getOrPut(key) { Element.SharedValue(key, value) } as Element.SharedValue<T>
}
if (value != sharedValue.value) {
@@ -169,7 +169,7 @@
private fun <T> computeValue(
layoutImpl: SceneTransitionLayoutImpl,
- element: Element,
+ element: Element?,
sharedValue: Element.SharedValue<T>,
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
@@ -184,8 +184,14 @@
}
fun sceneValue(scene: SceneKey): Element.SharedValue<T>? {
- val sceneValues = element.sceneValues[scene] ?: return null
- val value = sceneValues.sharedValues[sharedValue.key] ?: return null
+ val sharedValues =
+ if (element == null) {
+ layoutImpl.scene(scene).sharedValues
+ } else {
+ element.sceneValues[scene]?.sharedValues
+ }
+ ?: return null
+ val value = sharedValues[sharedValue.key] ?: return null
return value as Element.SharedValue<T>
}
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 abc62c4..eb10afc 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
@@ -29,6 +29,7 @@
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isSpecified
@@ -110,13 +111,12 @@
}
/** The implementation of [SceneScope.element]. */
-@Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun Modifier.element(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
key: ElementKey,
-): Modifier {
+): Modifier = composed {
val sceneValues = remember(scene, key) { Element.TargetValues() }
val element =
// Get the element associated to [key] if it was already composed in another scene,
@@ -160,7 +160,7 @@
}
}
- return drawWithContent {
+ drawWithContent {
if (shouldDrawElement(layoutImpl, scene, element)) {
drawContent()
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 97d3fff..d0a5f5b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -23,11 +23,11 @@
import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation
import androidx.compose.foundation.gestures.horizontalDrag
import androidx.compose.foundation.gestures.verticalDrag
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerId
@@ -56,7 +56,6 @@
* change in the future.
*/
// TODO(b/291055080): Migrate to the Modifier.Node API.
-@Composable
internal fun Modifier.multiPointerDraggable(
orientation: Orientation,
enabled: Boolean,
@@ -64,7 +63,7 @@
onDragStarted: (startedPosition: Offset, pointersDown: Int) -> Unit,
onDragDelta: (Float) -> Unit,
onDragStopped: (velocity: Float) -> Unit,
-): Modifier {
+): Modifier = composed {
val onDragStarted by rememberUpdatedState(onDragStarted)
val onDragStopped by rememberUpdatedState(onDragStopped)
val onDragDelta by rememberUpdatedState(onDragDelta)
@@ -77,7 +76,7 @@
Velocity(maxF, maxF)
}
- return this.pointerInput(enabled, orientation, maxFlingVelocity) {
+ pointerInput(enabled, orientation, maxFlingVelocity) {
if (!enabled) {
return@pointerInput
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index 3fd6828..2e50a71 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -23,6 +23,7 @@
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.testTag
@@ -44,6 +45,9 @@
var zIndex by mutableFloatStateOf(zIndex)
var size by mutableStateOf(IntSize.Zero)
+ /** The shared values in this scene that are not tied to a specific element. */
+ val sharedValues = SnapshotStateMap<ValueKey, Element.SharedValue<*>>()
+
@Composable
fun Content(modifier: Modifier = Modifier) {
Box(modifier.zIndex(zIndex).onPlaced { size = it.size }.testTag(key.testTag)) {
@@ -60,7 +64,6 @@
private val layoutImpl: SceneTransitionLayoutImpl,
private val scene: Scene,
) : SceneScope {
- @Composable
override fun Modifier.element(key: ElementKey): Modifier {
return element(layoutImpl, scene, key)
}
@@ -69,16 +72,18 @@
override fun <T> animateSharedValueAsState(
value: T,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
lerp: (T, T, Float) -> T,
canOverflow: Boolean
): State<T> {
val element =
- layoutImpl.elements[element]
- ?: error(
- "Element $element is not composed. Make sure to call animateSharedXAsState " +
- "*after* Modifier.element(key)."
- )
+ element?.let { key ->
+ layoutImpl.elements[key]
+ ?: error(
+ "Element $key is not composed. Make sure to call animateSharedXAsState " +
+ "*after* Modifier.element(key)."
+ )
+ }
return animateSharedValueAsState(
layoutImpl,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
new file mode 100644
index 0000000..7563e27
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -0,0 +1,659 @@
+package com.android.compose.animation.scene
+
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.round
+import com.android.compose.nestedscroll.PriorityNestedScrollConnection
+import kotlin.math.absoluteValue
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+@VisibleForTesting
+class SceneGestureHandler(
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ internal val orientation: Orientation,
+ private val coroutineScope: CoroutineScope,
+) : GestureHandler {
+ override val draggable: DraggableHandler = SceneDraggableHandler(this)
+
+ override val nestedScroll: SceneNestedScrollHandler = SceneNestedScrollHandler(this)
+
+ private var transitionState
+ get() = layoutImpl.state.transitionState
+ set(value) {
+ layoutImpl.state.transitionState = value
+ }
+
+ /**
+ * The transition controlled by this gesture handler. It will be set as the [transitionState] in
+ * the [SceneTransitionLayoutImpl] whenever this handler is driving the current transition.
+ *
+ * Note: the initialScene here does not matter, it's only used for initializing the transition
+ * and will be replaced when a drag event starts.
+ */
+ private val swipeTransition = SwipeTransition(initialScene = currentScene)
+
+ internal val currentScene: Scene
+ get() = layoutImpl.scene(transitionState.currentScene)
+
+ @VisibleForTesting
+ val isDrivingTransition
+ get() = transitionState == swipeTransition
+
+ @VisibleForTesting
+ var isAnimatingOffset
+ get() = swipeTransition.isAnimatingOffset
+ private set(value) {
+ swipeTransition.isAnimatingOffset = value
+ }
+
+ internal val swipeTransitionToScene
+ get() = swipeTransition._toScene
+
+ /**
+ * The velocity threshold at which the intent of the user is to swipe up or down. It is the same
+ * as SwipeableV2Defaults.VelocityThreshold.
+ */
+ @VisibleForTesting val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
+
+ /**
+ * The positional threshold at which the intent of the user is to swipe to the next scene. It is
+ * the same as SwipeableV2Defaults.PositionalThreshold.
+ */
+ private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+
+ internal var gestureWithPriority: Any? = null
+
+ internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?) {
+ if (isDrivingTransition) {
+ // This [transition] was already driving the animation: simply take over it.
+ // Stop animating and start from where the current offset.
+ swipeTransition.stopOffsetAnimation()
+ return
+ }
+
+ val transition = transitionState
+ if (transition is TransitionState.Transition) {
+ // TODO(b/290184746): Better handle interruptions here if state != idle.
+ Log.w(
+ TAG,
+ "start from TransitionState.Transition is not fully supported: from" +
+ " ${transition.fromScene} to ${transition.toScene} " +
+ "(progress ${transition.progress})"
+ )
+ }
+
+ val fromScene = currentScene
+
+ swipeTransition._currentScene = fromScene
+ swipeTransition._fromScene = fromScene
+
+ // We don't know where we are transitioning to yet given that the drag just started, so set
+ // it to fromScene, which will effectively be treated the same as Idle(fromScene).
+ swipeTransition._toScene = fromScene
+
+ swipeTransition.stopOffsetAnimation()
+ swipeTransition.dragOffset = 0f
+
+ // Use the layout size in the swipe orientation for swipe distance.
+ // TODO(b/290184746): Also handle custom distances for transitions. With smaller distances,
+ // we will also have to make sure that we correctly handle overscroll.
+ swipeTransition.absoluteDistance =
+ when (orientation) {
+ Orientation.Horizontal -> layoutImpl.size.width
+ Orientation.Vertical -> layoutImpl.size.height
+ }.toFloat()
+
+ val fromEdge =
+ startedPosition?.let { position ->
+ layoutImpl.edgeDetector.edge(
+ layoutImpl.size,
+ position.round(),
+ layoutImpl.density,
+ orientation,
+ )
+ }
+
+ swipeTransition.actionUpOrLeft =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = pointersDown,
+ fromEdge = fromEdge,
+ )
+
+ swipeTransition.actionDownOrRight =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = pointersDown,
+ fromEdge = fromEdge,
+ )
+
+ if (fromEdge == null) {
+ swipeTransition.actionUpOrLeftNoEdge = null
+ swipeTransition.actionDownOrRightNoEdge = null
+ } else {
+ swipeTransition.actionUpOrLeftNoEdge =
+ (swipeTransition.actionUpOrLeft as Swipe).copy(fromEdge = null)
+ swipeTransition.actionDownOrRightNoEdge =
+ (swipeTransition.actionDownOrRight as Swipe).copy(fromEdge = null)
+ }
+
+ if (swipeTransition.absoluteDistance > 0f) {
+ transitionState = swipeTransition
+ }
+ }
+
+ internal fun onDrag(delta: Float) {
+ if (delta == 0f) return
+
+ swipeTransition.dragOffset += delta
+
+ // First check transition.fromScene should be changed for the case where the user quickly
+ // swiped twice in a row to accelerate the transition and go from A => B then B => C really
+ // fast.
+ maybeHandleAcceleratedSwipe()
+
+ val offset = swipeTransition.dragOffset
+ val fromScene = swipeTransition._fromScene
+
+ // Compute the target scene depending on the current offset.
+ val target = fromScene.findTargetSceneAndDistance(offset)
+
+ if (swipeTransition._toScene.key != target.sceneKey) {
+ swipeTransition._toScene = layoutImpl.scenes.getValue(target.sceneKey)
+ }
+
+ if (swipeTransition._distance != target.distance) {
+ swipeTransition._distance = target.distance
+ }
+ }
+
+ /**
+ * Change fromScene in the case where the user quickly swiped multiple times in the same
+ * direction to accelerate the transition from A => B then B => C.
+ */
+ private fun maybeHandleAcceleratedSwipe() {
+ val toScene = swipeTransition._toScene
+ val fromScene = swipeTransition._fromScene
+
+ // If the swipe was not committed, don't do anything.
+ if (fromScene == toScene || swipeTransition._currentScene != toScene) {
+ return
+ }
+
+ // If the offset is past the distance then let's change fromScene so that the user can swipe
+ // to the next screen or go back to the previous one.
+ val offset = swipeTransition.dragOffset
+ val absoluteDistance = swipeTransition.absoluteDistance
+ if (offset <= -absoluteDistance && swipeTransition.upOrLeft(fromScene) == toScene.key) {
+ swipeTransition.dragOffset += absoluteDistance
+ swipeTransition._fromScene = toScene
+ } else if (
+ offset >= absoluteDistance && swipeTransition.downOrRight(fromScene) == toScene.key
+ ) {
+ swipeTransition.dragOffset -= absoluteDistance
+ swipeTransition._fromScene = toScene
+ }
+
+ // Important note: toScene and distance will be updated right after this function is called,
+ // using fromScene and dragOffset.
+ }
+
+ private class TargetScene(
+ val sceneKey: SceneKey,
+ val distance: Float,
+ )
+
+ private fun Scene.findTargetSceneAndDistance(directionOffset: Float): TargetScene {
+ val upOrLeft = swipeTransition.upOrLeft(this)
+ val downOrRight = swipeTransition.downOrRight(this)
+
+ // Compute the target scene depending on the current offset.
+ return when {
+ directionOffset < 0f && upOrLeft != null -> {
+ TargetScene(
+ sceneKey = upOrLeft,
+ distance = -swipeTransition.absoluteDistance,
+ )
+ }
+ directionOffset > 0f && downOrRight != null -> {
+ TargetScene(
+ sceneKey = downOrRight,
+ distance = swipeTransition.absoluteDistance,
+ )
+ }
+ else -> {
+ TargetScene(
+ sceneKey = key,
+ distance = 0f,
+ )
+ }
+ }
+ }
+
+ internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
+ // The state was changed since the drag started; don't do anything.
+ if (!isDrivingTransition) {
+ return
+ }
+
+ fun animateTo(targetScene: Scene, targetOffset: Float) {
+ // If the effective current scene changed, it should be reflected right now in the
+ // current scene state, even before the settle animation is ongoing. That way all the
+ // swipeables and back handlers will be refreshed and the user can for instance quickly
+ // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
+ // immediately go back B => A.
+ if (targetScene != swipeTransition._currentScene) {
+ swipeTransition._currentScene = targetScene
+ layoutImpl.onChangeScene(targetScene.key)
+ }
+
+ animateOffset(
+ initialVelocity = velocity,
+ targetOffset = targetOffset,
+ targetScene = targetScene.key
+ )
+ }
+
+ val fromScene = swipeTransition._fromScene
+ if (canChangeScene) {
+ // If we are halfway between two scenes, we check what the target will be based on the
+ // velocity and offset of the transition, then we launch the animation.
+
+ val toScene = swipeTransition._toScene
+ if (fromScene == toScene) {
+ // We were not animating.
+ transitionState = TransitionState.Idle(fromScene.key)
+ return
+ }
+
+ // Compute the destination scene (and therefore offset) to settle in.
+ val offset = swipeTransition.dragOffset
+ val distance = swipeTransition.distance
+ if (
+ shouldCommitSwipe(
+ offset,
+ distance,
+ velocity,
+ wasCommitted = swipeTransition._currentScene == toScene,
+ )
+ ) {
+ // Animate to the next scene
+ animateTo(targetScene = toScene, targetOffset = distance)
+ } else {
+ // Animate to the initial scene
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ }
+ } else {
+ // We are doing an overscroll animation between scenes. In this case, we can also start
+ // from the idle position.
+
+ val startFromIdlePosition = swipeTransition.dragOffset == 0f
+
+ if (startFromIdlePosition) {
+ // If there is a next scene, we start the overscroll animation.
+ val target = fromScene.findTargetSceneAndDistance(velocity)
+ val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
+ if (isValidTarget) {
+ swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
+ swipeTransition._distance = target.distance
+
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ } else {
+ // We will not animate
+ transitionState = TransitionState.Idle(fromScene.key)
+ }
+ } else {
+ // We were between two scenes: animate to the initial scene.
+ animateTo(targetScene = fromScene, targetOffset = 0f)
+ }
+ }
+ }
+
+ /**
+ * Whether the swipe to the target scene should be committed or not. This is inspired by
+ * SwipeableV2.computeTarget().
+ */
+ private fun shouldCommitSwipe(
+ offset: Float,
+ distance: Float,
+ velocity: Float,
+ wasCommitted: Boolean,
+ ): Boolean {
+ fun isCloserToTarget(): Boolean {
+ return (offset - distance).absoluteValue < offset.absoluteValue
+ }
+
+ // Swiping up or left.
+ if (distance < 0f) {
+ return if (offset > 0f || velocity >= velocityThreshold) {
+ false
+ } else {
+ velocity <= -velocityThreshold ||
+ (offset <= -positionalThreshold && !wasCommitted) ||
+ isCloserToTarget()
+ }
+ }
+
+ // Swiping down or right.
+ return if (offset < 0f || velocity <= -velocityThreshold) {
+ false
+ } else {
+ velocity >= velocityThreshold ||
+ (offset >= positionalThreshold && !wasCommitted) ||
+ isCloserToTarget()
+ }
+ }
+
+ private fun animateOffset(
+ initialVelocity: Float,
+ targetOffset: Float,
+ targetScene: SceneKey,
+ ) {
+ swipeTransition.startOffsetAnimation {
+ coroutineScope.launch {
+ if (!isAnimatingOffset) {
+ swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
+ }
+ isAnimatingOffset = true
+
+ swipeTransition.offsetAnimatable.animateTo(
+ targetOffset,
+ // TODO(b/290184746): Make this spring spec configurable.
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = OffsetVisibilityThreshold
+ ),
+ initialVelocity = initialVelocity,
+ )
+
+ isAnimatingOffset = false
+
+ // Now that the animation is done, the state should be idle. Note that if the state
+ // was changed since this animation started, some external code changed it and we
+ // shouldn't do anything here. Note also that this job will be cancelled in the case
+ // where the user intercepts this swipe.
+ if (isDrivingTransition) {
+ transitionState = TransitionState.Idle(targetScene)
+ }
+ }
+ }
+ }
+
+ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
+ var _currentScene by mutableStateOf(initialScene)
+ override val currentScene: SceneKey
+ get() = _currentScene.key
+
+ var _fromScene by mutableStateOf(initialScene)
+ override val fromScene: SceneKey
+ get() = _fromScene.key
+
+ var _toScene by mutableStateOf(initialScene)
+ override val toScene: SceneKey
+ get() = _toScene.key
+
+ override val progress: Float
+ get() {
+ val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+ if (distance == 0f) {
+ // This can happen only if fromScene == toScene.
+ error(
+ "Transition.progress should be called only when Transition.fromScene != " +
+ "Transition.toScene"
+ )
+ }
+ return offset / distance
+ }
+
+ override val isInitiatedByUserInput = true
+
+ /** The current offset caused by the drag gesture. */
+ var dragOffset by mutableFloatStateOf(0f)
+
+ /**
+ * Whether the offset is animated (the user lifted their finger) or if it is driven by
+ * gesture.
+ */
+ var isAnimatingOffset by mutableStateOf(false)
+
+ // If we are not animating offset, it means the offset is being driven by the user's finger.
+ override val isUserInputOngoing: Boolean
+ get() = !isAnimatingOffset
+
+ /** The animatable used to animate the offset once the user lifted its finger. */
+ val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
+
+ /** Job to check that there is at most one offset animation in progress. */
+ private var offsetAnimationJob: Job? = null
+
+ /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
+ fun startOffsetAnimation(job: () -> Job) {
+ stopOffsetAnimation()
+ offsetAnimationJob = job()
+ }
+
+ /** Stops any ongoing offset animation. */
+ fun stopOffsetAnimation() {
+ offsetAnimationJob?.cancel()
+
+ if (isAnimatingOffset) {
+ isAnimatingOffset = false
+ dragOffset = offsetAnimatable.value
+ }
+ }
+
+ /** The absolute distance between [fromScene] and [toScene]. */
+ var absoluteDistance = 0f
+
+ /**
+ * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
+ * above or to the left of [toScene].
+ */
+ var _distance by mutableFloatStateOf(0f)
+ val distance: Float
+ get() = _distance
+
+ /** The [UserAction]s associated to this swipe. */
+ var actionUpOrLeft: UserAction = Back
+ var actionDownOrRight: UserAction = Back
+ var actionUpOrLeftNoEdge: UserAction? = null
+ var actionDownOrRightNoEdge: UserAction? = null
+
+ fun upOrLeft(scene: Scene): SceneKey? {
+ return scene.userActions[actionUpOrLeft]
+ ?: actionUpOrLeftNoEdge?.let { scene.userActions[it] }
+ }
+
+ fun downOrRight(scene: Scene): SceneKey? {
+ return scene.userActions[actionDownOrRight]
+ ?: actionDownOrRightNoEdge?.let { scene.userActions[it] }
+ }
+ }
+
+ companion object {
+ private const val TAG = "SceneGestureHandler"
+ }
+}
+
+private class SceneDraggableHandler(
+ private val gestureHandler: SceneGestureHandler,
+) : DraggableHandler {
+ override fun onDragStarted(startedPosition: Offset, pointersDown: Int) {
+ gestureHandler.gestureWithPriority = this
+ gestureHandler.onDragStarted(pointersDown, startedPosition)
+ }
+
+ override fun onDelta(pixels: Float) {
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.onDrag(delta = pixels)
+ }
+ }
+
+ override fun onDragStopped(velocity: Float) {
+ if (gestureHandler.gestureWithPriority == this) {
+ gestureHandler.gestureWithPriority = null
+ gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+ }
+ }
+}
+
+@VisibleForTesting
+class SceneNestedScrollHandler(
+ private val gestureHandler: SceneGestureHandler,
+) : NestedScrollHandler {
+ override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
+
+ private fun Offset.toAmount() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> x
+ Orientation.Vertical -> y
+ }
+
+ private fun Velocity.toAmount() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> x
+ Orientation.Vertical -> y
+ }
+
+ private fun Float.toOffset() =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> Offset(x = this, y = 0f)
+ Orientation.Vertical -> Offset(x = 0f, y = this)
+ }
+
+ private fun nestedScrollConnection(): PriorityNestedScrollConnection {
+ // The next potential scene is calculated during the canStart
+ var nextScene: SceneKey? = null
+
+ // This is the scene on which we will have priority during the scroll gesture.
+ var priorityScene: SceneKey? = null
+
+ // If we performed a long gesture before entering priority mode, we would have to avoid
+ // moving on to the next scene.
+ var gestureStartedOnNestedChild = false
+
+ val actionUpOrLeft =
+ Swipe(
+ direction =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = 1,
+ )
+
+ val actionDownOrRight =
+ Swipe(
+ direction =
+ when (gestureHandler.orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = 1,
+ )
+
+ fun findNextScene(amount: Float): SceneKey? {
+ val fromScene = gestureHandler.currentScene
+ return when {
+ amount < 0f -> fromScene.userActions[actionUpOrLeft]
+ amount > 0f -> fromScene.userActions[actionDownOrRight]
+ else -> null
+ }
+ }
+
+ return PriorityNestedScrollConnection(
+ canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
+ gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+
+ val canInterceptPreScroll =
+ gestureHandler.isDrivingTransition &&
+ !gestureStartedOnNestedChild &&
+ offsetAvailable.toAmount() != 0f
+
+ if (!canInterceptPreScroll) return@PriorityNestedScrollConnection false
+
+ nextScene = gestureHandler.swipeTransitionToScene.key
+
+ true
+ },
+ canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
+ val amount = offsetAvailable.toAmount()
+ if (amount == 0f) return@PriorityNestedScrollConnection false
+
+ gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+ nextScene = findNextScene(amount)
+ nextScene != null
+ },
+ canStartPostFling = { velocityAvailable ->
+ val amount = velocityAvailable.toAmount()
+ if (amount == 0f) return@PriorityNestedScrollConnection false
+
+ // We could start an overscroll animation
+ gestureStartedOnNestedChild = true
+ nextScene = findNextScene(amount)
+ nextScene != null
+ },
+ canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
+ onStart = {
+ gestureHandler.gestureWithPriority = this
+ priorityScene = nextScene
+ gestureHandler.onDragStarted(pointersDown = 1, startedPosition = null)
+ },
+ onScroll = { offsetAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Offset.Zero
+ }
+
+ val amount = offsetAvailable.toAmount()
+
+ // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
+ // initiated in a nested child.
+ gestureHandler.onDrag(amount)
+
+ amount.toOffset()
+ },
+ onStop = { velocityAvailable ->
+ if (gestureHandler.gestureWithPriority != this) {
+ return@PriorityNestedScrollConnection Velocity.Zero
+ }
+
+ priorityScene = null
+
+ gestureHandler.onDragStopped(
+ velocity = velocityAvailable.toAmount(),
+ canChangeScene = !gestureStartedOnNestedChild
+ )
+
+ // The onDragStopped animation consumes any remaining velocity.
+ velocityAvailable
+ },
+ )
+ }
+}
+
+/**
+ * The number of pixels below which there won't be a visible difference in the transition and from
+ * which the animation can stop.
+ */
+private const val OffsetVisibilityThreshold = 0.5f
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 1f38e70..35d1f90 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -117,7 +117,7 @@
* TODO(b/291566282): Migrate this to the new Modifier Node API and remove the @Composable
* constraint.
*/
- @Composable fun Modifier.element(key: ElementKey): Modifier
+ fun Modifier.element(key: ElementKey): Modifier
/**
* Create a *movable* element identified by [key].
@@ -142,7 +142,9 @@
*
* @param value the value of this shared value in the current scene.
* @param key the key of this shared value.
- * @param element the element associated with this value.
+ * @param element the element associated with this value. If `null`, this value will be
+ * associated at the scene level, which means that [key] should be used maximum once in the
+ * same scene.
* @param lerp the *linear* interpolation function that should be used to interpolate between
* two different values. Note that it has to be linear because the [fraction] passed to this
* interpolator is already interpolated.
@@ -157,7 +159,7 @@
fun <T> animateSharedValueAsState(
value: T,
key: ValueKey,
- element: ElementKey,
+ element: ElementKey?,
lerp: (start: T, stop: T, fraction: Float) -> T,
canOverflow: Boolean,
): State<T>
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 fd62659..6618eb0 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
@@ -30,7 +30,6 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.layout.LookaheadScope
@@ -131,15 +130,19 @@
}
@Composable
- @OptIn(ExperimentalComposeUiApi::class)
internal fun Content(modifier: Modifier) {
+ val horizontalGestureHandler =
+ rememberSceneGestureHandler(layoutImpl = this, Orientation.Horizontal)
+ val verticalGestureHandler =
+ rememberSceneGestureHandler(layoutImpl = this, Orientation.Vertical)
+
Box(
modifier
// Handle horizontal and vertical swipes on this layout.
// Note: order here is important and will give a slight priority to the vertical
// swipes.
- .swipeToScene(layoutImpl = this, Orientation.Horizontal)
- .swipeToScene(layoutImpl = this, Orientation.Vertical)
+ .swipeToScene(horizontalGestureHandler)
+ .swipeToScene(verticalGestureHandler)
.onSizeChanged { size = it }
) {
LookaheadScope {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 877ac09..8980df8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -16,47 +16,24 @@
package com.android.compose.animation.scene
-import android.util.Log
-import androidx.annotation.VisibleForTesting
-import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.round
-import com.android.compose.nestedscroll.PriorityNestedScrollConnection
-import kotlin.math.absoluteValue
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
/**
* Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state.
*/
-@Composable
-internal fun Modifier.swipeToScene(
- layoutImpl: SceneTransitionLayoutImpl,
- orientation: Orientation,
-): Modifier {
- val gestureHandler = rememberSceneGestureHandler(layoutImpl, orientation)
-
+internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifier {
/** Whether swipe should be enabled in the given [orientation]. */
fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
val currentScene = gestureHandler.currentScene
+ val orientation = gestureHandler.orientation
val canSwipe = currentScene.shouldEnableSwipes(orientation)
val canOppositeSwipe =
currentScene.shouldEnableSwipes(
@@ -84,7 +61,7 @@
}
@Composable
-private fun rememberSceneGestureHandler(
+internal fun rememberSceneGestureHandler(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
): SceneGestureHandler {
@@ -101,641 +78,3 @@
return gestureHandler
}
-
-@VisibleForTesting
-class SceneGestureHandler(
- private val layoutImpl: SceneTransitionLayoutImpl,
- internal val orientation: Orientation,
- private val coroutineScope: CoroutineScope,
-) : GestureHandler {
- override val draggable: DraggableHandler = SceneDraggableHandler(this)
-
- override val nestedScroll: SceneNestedScrollHandler = SceneNestedScrollHandler(this)
-
- private var transitionState
- get() = layoutImpl.state.transitionState
- set(value) {
- layoutImpl.state.transitionState = value
- }
-
- /**
- * The transition controlled by this gesture handler. It will be set as the [transitionState] in
- * the [SceneTransitionLayoutImpl] whenever this handler is driving the current transition.
- *
- * Note: the initialScene here does not matter, it's only used for initializing the transition
- * and will be replaced when a drag event starts.
- */
- private val swipeTransition = SwipeTransition(initialScene = currentScene)
-
- internal val currentScene: Scene
- get() = layoutImpl.scene(transitionState.currentScene)
-
- @VisibleForTesting
- val isDrivingTransition
- get() = transitionState == swipeTransition
-
- @VisibleForTesting
- var isAnimatingOffset
- get() = swipeTransition.isAnimatingOffset
- private set(value) {
- swipeTransition.isAnimatingOffset = value
- }
-
- internal val swipeTransitionToScene
- get() = swipeTransition._toScene
-
- /**
- * The velocity threshold at which the intent of the user is to swipe up or down. It is the same
- * as SwipeableV2Defaults.VelocityThreshold.
- */
- @VisibleForTesting val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
-
- /**
- * The positional threshold at which the intent of the user is to swipe to the next scene. It is
- * the same as SwipeableV2Defaults.PositionalThreshold.
- */
- private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
-
- internal var gestureWithPriority: Any? = null
-
- internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?) {
- if (isDrivingTransition) {
- // This [transition] was already driving the animation: simply take over it.
- // Stop animating and start from where the current offset.
- swipeTransition.stopOffsetAnimation()
- return
- }
-
- val transition = transitionState
- if (transition is TransitionState.Transition) {
- // TODO(b/290184746): Better handle interruptions here if state != idle.
- Log.w(
- TAG,
- "start from TransitionState.Transition is not fully supported: from" +
- " ${transition.fromScene} to ${transition.toScene} " +
- "(progress ${transition.progress})"
- )
- }
-
- val fromScene = currentScene
-
- swipeTransition._currentScene = fromScene
- swipeTransition._fromScene = fromScene
-
- // We don't know where we are transitioning to yet given that the drag just started, so set
- // it to fromScene, which will effectively be treated the same as Idle(fromScene).
- swipeTransition._toScene = fromScene
-
- swipeTransition.stopOffsetAnimation()
- swipeTransition.dragOffset = 0f
-
- // Use the layout size in the swipe orientation for swipe distance.
- // TODO(b/290184746): Also handle custom distances for transitions. With smaller distances,
- // we will also have to make sure that we correctly handle overscroll.
- swipeTransition.absoluteDistance =
- when (orientation) {
- Orientation.Horizontal -> layoutImpl.size.width
- Orientation.Vertical -> layoutImpl.size.height
- }.toFloat()
-
- val fromEdge =
- startedPosition?.let { position ->
- layoutImpl.edgeDetector.edge(
- layoutImpl.size,
- position.round(),
- layoutImpl.density,
- orientation,
- )
- }
-
- swipeTransition.actionUpOrLeft =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = pointersDown,
- fromEdge = fromEdge,
- )
-
- swipeTransition.actionDownOrRight =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = pointersDown,
- fromEdge = fromEdge,
- )
-
- if (fromEdge == null) {
- swipeTransition.actionUpOrLeftNoEdge = null
- swipeTransition.actionDownOrRightNoEdge = null
- } else {
- swipeTransition.actionUpOrLeftNoEdge =
- (swipeTransition.actionUpOrLeft as Swipe).copy(fromEdge = null)
- swipeTransition.actionDownOrRightNoEdge =
- (swipeTransition.actionDownOrRight as Swipe).copy(fromEdge = null)
- }
-
- if (swipeTransition.absoluteDistance > 0f) {
- transitionState = swipeTransition
- }
- }
-
- internal fun onDrag(delta: Float) {
- if (delta == 0f) return
-
- swipeTransition.dragOffset += delta
-
- // First check transition.fromScene should be changed for the case where the user quickly
- // swiped twice in a row to accelerate the transition and go from A => B then B => C really
- // fast.
- maybeHandleAcceleratedSwipe()
-
- val offset = swipeTransition.dragOffset
- val fromScene = swipeTransition._fromScene
-
- // Compute the target scene depending on the current offset.
- val target = fromScene.findTargetSceneAndDistance(offset)
-
- if (swipeTransition._toScene.key != target.sceneKey) {
- swipeTransition._toScene = layoutImpl.scenes.getValue(target.sceneKey)
- }
-
- if (swipeTransition._distance != target.distance) {
- swipeTransition._distance = target.distance
- }
- }
-
- /**
- * Change fromScene in the case where the user quickly swiped multiple times in the same
- * direction to accelerate the transition from A => B then B => C.
- */
- private fun maybeHandleAcceleratedSwipe() {
- val toScene = swipeTransition._toScene
- val fromScene = swipeTransition._fromScene
-
- // If the swipe was not committed, don't do anything.
- if (fromScene == toScene || swipeTransition._currentScene != toScene) {
- return
- }
-
- // If the offset is past the distance then let's change fromScene so that the user can swipe
- // to the next screen or go back to the previous one.
- val offset = swipeTransition.dragOffset
- val absoluteDistance = swipeTransition.absoluteDistance
- if (offset <= -absoluteDistance && swipeTransition.upOrLeft(fromScene) == toScene.key) {
- swipeTransition.dragOffset += absoluteDistance
- swipeTransition._fromScene = toScene
- } else if (
- offset >= absoluteDistance && swipeTransition.downOrRight(fromScene) == toScene.key
- ) {
- swipeTransition.dragOffset -= absoluteDistance
- swipeTransition._fromScene = toScene
- }
-
- // Important note: toScene and distance will be updated right after this function is called,
- // using fromScene and dragOffset.
- }
-
- private class TargetScene(
- val sceneKey: SceneKey,
- val distance: Float,
- )
-
- private fun Scene.findTargetSceneAndDistance(directionOffset: Float): TargetScene {
- val upOrLeft = swipeTransition.upOrLeft(this)
- val downOrRight = swipeTransition.downOrRight(this)
-
- // Compute the target scene depending on the current offset.
- return when {
- directionOffset < 0f && upOrLeft != null -> {
- TargetScene(
- sceneKey = upOrLeft,
- distance = -swipeTransition.absoluteDistance,
- )
- }
- directionOffset > 0f && downOrRight != null -> {
- TargetScene(
- sceneKey = downOrRight,
- distance = swipeTransition.absoluteDistance,
- )
- }
- else -> {
- TargetScene(
- sceneKey = key,
- distance = 0f,
- )
- }
- }
- }
-
- internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
- // The state was changed since the drag started; don't do anything.
- if (!isDrivingTransition) {
- return
- }
-
- fun animateTo(targetScene: Scene, targetOffset: Float) {
- // If the effective current scene changed, it should be reflected right now in the
- // current scene state, even before the settle animation is ongoing. That way all the
- // swipeables and back handlers will be refreshed and the user can for instance quickly
- // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
- // immediately go back B => A.
- if (targetScene != swipeTransition._currentScene) {
- swipeTransition._currentScene = targetScene
- layoutImpl.onChangeScene(targetScene.key)
- }
-
- animateOffset(
- initialVelocity = velocity,
- targetOffset = targetOffset,
- targetScene = targetScene.key
- )
- }
-
- val fromScene = swipeTransition._fromScene
- if (canChangeScene) {
- // If we are halfway between two scenes, we check what the target will be based on the
- // velocity and offset of the transition, then we launch the animation.
-
- val toScene = swipeTransition._toScene
- if (fromScene == toScene) {
- // We were not animating.
- transitionState = TransitionState.Idle(fromScene.key)
- return
- }
-
- // Compute the destination scene (and therefore offset) to settle in.
- val offset = swipeTransition.dragOffset
- val distance = swipeTransition.distance
- if (
- shouldCommitSwipe(
- offset,
- distance,
- velocity,
- wasCommitted = swipeTransition._currentScene == toScene,
- )
- ) {
- // Animate to the next scene
- animateTo(targetScene = toScene, targetOffset = distance)
- } else {
- // Animate to the initial scene
- animateTo(targetScene = fromScene, targetOffset = 0f)
- }
- } else {
- // We are doing an overscroll animation between scenes. In this case, we can also start
- // from the idle position.
-
- val startFromIdlePosition = swipeTransition.dragOffset == 0f
-
- if (startFromIdlePosition) {
- // If there is a next scene, we start the overscroll animation.
- val target = fromScene.findTargetSceneAndDistance(velocity)
- val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
- if (isValidTarget) {
- swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
- swipeTransition._distance = target.distance
-
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
- }
- } else {
- // We were between two scenes: animate to the initial scene.
- animateTo(targetScene = fromScene, targetOffset = 0f)
- }
- }
- }
-
- /**
- * Whether the swipe to the target scene should be committed or not. This is inspired by
- * SwipeableV2.computeTarget().
- */
- private fun shouldCommitSwipe(
- offset: Float,
- distance: Float,
- velocity: Float,
- wasCommitted: Boolean,
- ): Boolean {
- fun isCloserToTarget(): Boolean {
- return (offset - distance).absoluteValue < offset.absoluteValue
- }
-
- // Swiping up or left.
- if (distance < 0f) {
- return if (offset > 0f || velocity >= velocityThreshold) {
- false
- } else {
- velocity <= -velocityThreshold ||
- (offset <= -positionalThreshold && !wasCommitted) ||
- isCloserToTarget()
- }
- }
-
- // Swiping down or right.
- return if (offset < 0f || velocity <= -velocityThreshold) {
- false
- } else {
- velocity >= velocityThreshold ||
- (offset >= positionalThreshold && !wasCommitted) ||
- isCloserToTarget()
- }
- }
-
- private fun animateOffset(
- initialVelocity: Float,
- targetOffset: Float,
- targetScene: SceneKey,
- ) {
- swipeTransition.startOffsetAnimation {
- coroutineScope.launch {
- if (!isAnimatingOffset) {
- swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
- }
- isAnimatingOffset = true
-
- swipeTransition.offsetAnimatable.animateTo(
- targetOffset,
- // TODO(b/290184746): Make this spring spec configurable.
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = OffsetVisibilityThreshold
- ),
- initialVelocity = initialVelocity,
- )
-
- isAnimatingOffset = false
-
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (isDrivingTransition) {
- transitionState = TransitionState.Idle(targetScene)
- }
- }
- }
- }
-
- private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
- var _currentScene by mutableStateOf(initialScene)
- override val currentScene: SceneKey
- get() = _currentScene.key
-
- var _fromScene by mutableStateOf(initialScene)
- override val fromScene: SceneKey
- get() = _fromScene.key
-
- var _toScene by mutableStateOf(initialScene)
- override val toScene: SceneKey
- get() = _toScene.key
-
- override val progress: Float
- get() {
- val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
- if (distance == 0f) {
- // This can happen only if fromScene == toScene.
- error(
- "Transition.progress should be called only when Transition.fromScene != " +
- "Transition.toScene"
- )
- }
- return offset / distance
- }
-
- override val isInitiatedByUserInput = true
-
- /** The current offset caused by the drag gesture. */
- var dragOffset by mutableFloatStateOf(0f)
-
- /**
- * Whether the offset is animated (the user lifted their finger) or if it is driven by
- * gesture.
- */
- var isAnimatingOffset by mutableStateOf(false)
-
- // If we are not animating offset, it means the offset is being driven by the user's finger.
- override val isUserInputOngoing: Boolean
- get() = !isAnimatingOffset
-
- /** The animatable used to animate the offset once the user lifted its finger. */
- val offsetAnimatable = Animatable(0f, OffsetVisibilityThreshold)
-
- /** Job to check that there is at most one offset animation in progress. */
- private var offsetAnimationJob: Job? = null
-
- /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
- fun startOffsetAnimation(job: () -> Job) {
- stopOffsetAnimation()
- offsetAnimationJob = job()
- }
-
- /** Stops any ongoing offset animation. */
- fun stopOffsetAnimation() {
- offsetAnimationJob?.cancel()
-
- if (isAnimatingOffset) {
- isAnimatingOffset = false
- dragOffset = offsetAnimatable.value
- }
- }
-
- /** The absolute distance between [fromScene] and [toScene]. */
- var absoluteDistance = 0f
-
- /**
- * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
- * above or to the left of [toScene].
- */
- var _distance by mutableFloatStateOf(0f)
- val distance: Float
- get() = _distance
-
- /** The [UserAction]s associated to this swipe. */
- var actionUpOrLeft: UserAction = Back
- var actionDownOrRight: UserAction = Back
- var actionUpOrLeftNoEdge: UserAction? = null
- var actionDownOrRightNoEdge: UserAction? = null
-
- fun upOrLeft(scene: Scene): SceneKey? {
- return scene.userActions[actionUpOrLeft]
- ?: actionUpOrLeftNoEdge?.let { scene.userActions[it] }
- }
-
- fun downOrRight(scene: Scene): SceneKey? {
- return scene.userActions[actionDownOrRight]
- ?: actionDownOrRightNoEdge?.let { scene.userActions[it] }
- }
- }
-
- companion object {
- private const val TAG = "SceneGestureHandler"
- }
-}
-
-private class SceneDraggableHandler(
- private val gestureHandler: SceneGestureHandler,
-) : DraggableHandler {
- override fun onDragStarted(startedPosition: Offset, pointersDown: Int) {
- gestureHandler.gestureWithPriority = this
- gestureHandler.onDragStarted(pointersDown, startedPosition)
- }
-
- override fun onDelta(pixels: Float) {
- if (gestureHandler.gestureWithPriority == this) {
- gestureHandler.onDrag(delta = pixels)
- }
- }
-
- override fun onDragStopped(velocity: Float) {
- if (gestureHandler.gestureWithPriority == this) {
- gestureHandler.gestureWithPriority = null
- gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
- }
- }
-}
-
-@VisibleForTesting
-class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
-) : NestedScrollHandler {
- override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
-
- private fun Offset.toAmount() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> x
- Orientation.Vertical -> y
- }
-
- private fun Velocity.toAmount() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> x
- Orientation.Vertical -> y
- }
-
- private fun Float.toOffset() =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> Offset(x = this, y = 0f)
- Orientation.Vertical -> Offset(x = 0f, y = this)
- }
-
- private fun nestedScrollConnection(): PriorityNestedScrollConnection {
- // The next potential scene is calculated during the canStart
- var nextScene: SceneKey? = null
-
- // This is the scene on which we will have priority during the scroll gesture.
- var priorityScene: SceneKey? = null
-
- // If we performed a long gesture before entering priority mode, we would have to avoid
- // moving on to the next scene.
- var gestureStartedOnNestedChild = false
-
- val actionUpOrLeft =
- Swipe(
- direction =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = 1,
- )
-
- val actionDownOrRight =
- Swipe(
- direction =
- when (gestureHandler.orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = 1,
- )
-
- fun findNextScene(amount: Float): SceneKey? {
- val fromScene = gestureHandler.currentScene
- return when {
- amount < 0f -> fromScene.userActions[actionUpOrLeft]
- amount > 0f -> fromScene.userActions[actionDownOrRight]
- else -> null
- }
- }
-
- return PriorityNestedScrollConnection(
- canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
- gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
-
- val canInterceptPreScroll =
- gestureHandler.isDrivingTransition &&
- !gestureStartedOnNestedChild &&
- offsetAvailable.toAmount() != 0f
-
- if (!canInterceptPreScroll) return@PriorityNestedScrollConnection false
-
- nextScene = gestureHandler.swipeTransitionToScene.key
-
- true
- },
- canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
- val amount = offsetAvailable.toAmount()
- if (amount == 0f) return@PriorityNestedScrollConnection false
-
- gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
- nextScene = findNextScene(amount)
- nextScene != null
- },
- canStartPostFling = { velocityAvailable ->
- val amount = velocityAvailable.toAmount()
- if (amount == 0f) return@PriorityNestedScrollConnection false
-
- // We could start an overscroll animation
- gestureStartedOnNestedChild = true
- nextScene = findNextScene(amount)
- nextScene != null
- },
- canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
- onStart = {
- gestureHandler.gestureWithPriority = this
- priorityScene = nextScene
- gestureHandler.onDragStarted(pointersDown = 1, startedPosition = null)
- },
- onScroll = { offsetAvailable ->
- if (gestureHandler.gestureWithPriority != this) {
- return@PriorityNestedScrollConnection Offset.Zero
- }
-
- val amount = offsetAvailable.toAmount()
-
- // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
- // initiated in a nested child.
- gestureHandler.onDrag(amount)
-
- amount.toOffset()
- },
- onStop = { velocityAvailable ->
- if (gestureHandler.gestureWithPriority != this) {
- return@PriorityNestedScrollConnection Velocity.Zero
- }
-
- priorityScene = null
-
- gestureHandler.onDragStopped(
- velocity = velocityAvailable.toAmount(),
- canChangeScene = !gestureStartedOnNestedChild
- )
-
- // The onDragStopped animation consumes any remaining velocity.
- velocityAvailable
- },
- )
- }
-}
-
-/**
- * The number of pixels below which there won't be a visible difference in the transition and from
- * which the animation can stop.
- */
-private const val OffsetVisibilityThreshold = 0.5f
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
index 7b7695e..5473186 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
@@ -66,7 +66,8 @@
val int by animateSharedIntAsState(targetValues.int, TestValues.Value1, key)
val float by animateSharedFloatAsState(targetValues.float, TestValues.Value2, key)
val dp by animateSharedDpAsState(targetValues.dp, TestValues.Value3, key)
- val color by animateSharedColorAsState(targetValues.color, TestValues.Value4, key)
+ val color by
+ animateSharedColorAsState(targetValues.color, TestValues.Value4, element = null)
// Make sure we read the values during composition, so that we recompose and call
// onCurrentValueChanged() with the latest values.
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
new file mode 100644
index 0000000..de46f72
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestSceneScope.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+
+/** `SceneScope` for tests, which allows a single scene to be drawn in a [SceneTransitionLayout]. */
+@Composable
+fun TestSceneScope(
+ modifier: Modifier = Modifier,
+ content: @Composable SceneScope.() -> Unit,
+) {
+ val currentScene = remember { SceneKey("current") }
+ SceneTransitionLayout(
+ currentScene,
+ onChangeScene = { /* do nothing */},
+ transitions = remember { transitions {} },
+ modifier,
+ ) {
+ scene(currentScene, content = content)
+ }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index b076b2c..42ba643 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -33,6 +33,7 @@
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockSettings
+import com.android.systemui.plugins.DefaultClockFaceLayout
import com.android.systemui.plugins.WeatherData
import java.io.PrintWriter
import java.util.Locale
@@ -114,6 +115,7 @@
protected var targetRegion: Rect? = null
override val config = ClockFaceConfig()
+ override val layout = DefaultClockFaceLayout(view)
override var messageBuffer: MessageBuffer?
get() = view.messageBuffer
@@ -184,6 +186,7 @@
view: AnimatableClockView,
seedColor: Int?,
) : DefaultClockFaceController(view, seedColor) {
+ override val layout = DefaultClockFaceLayout(view)
override val config =
ClockFaceConfig(hasCustomPositionUpdatedAnimation = hasStepClockAnimation)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegateTest.kt
new file mode 100644
index 0000000..5389fc2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegateTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import android.app.AlertDialog
+import android.content.res.Configuration
+import android.testing.TestableLooper.RunWithLooper
+import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.util.mockito.mock
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+@SmallTest
+class AlertDialogWithDelegateTest : SysuiTestCase() {
+
+ private val delegate = mock<DialogDelegate<AlertDialog>>()
+
+ @Test
+ fun delegateIsCalled_inCorrectOrder() {
+ val configuration = Configuration()
+ val inOrder = Mockito.inOrder(delegate)
+ val dialog = createDialog()
+
+ dialog.show()
+ dialog.onWindowFocusChanged(/* hasFocus= */ true)
+ dialog.onConfigurationChanged(configuration)
+ dialog.dismiss()
+
+ inOrder.verify(delegate).beforeCreate(dialog, /* savedInstanceState= */ null)
+ inOrder.verify(delegate).onCreate(dialog, /* savedInstanceState= */ null)
+ inOrder.verify(delegate).onStart(dialog)
+ inOrder.verify(delegate).onWindowFocusChanged(dialog, /* hasFocus= */ true)
+ inOrder.verify(delegate).onConfigurationChanged(dialog, configuration)
+ inOrder.verify(delegate).onStop(dialog)
+ }
+
+ private fun createDialog(): AlertDialogWithDelegate =
+ AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate).apply {
+ window?.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 1620088..0b922a8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -29,22 +29,28 @@
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.model.SysUiState;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -58,6 +64,8 @@
private FeatureFlags mFeatureFlags;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private DialogDelegate<SystemUIDialog> mDelegate;
@Before
public void setup() {
@@ -143,4 +151,35 @@
assertThat(calledStart.get()).isTrue();
assertThat(calledStop.get()).isTrue();
}
+
+ @Test
+ public void delegateIsCalled_inCorrectOrder() {
+ Configuration configuration = new Configuration();
+ InOrder inOrder = Mockito.inOrder(mDelegate);
+ SystemUIDialog dialog = createDialogWithDelegate();
+
+ dialog.show();
+ dialog.onWindowFocusChanged(/* hasFocus= */ true);
+ dialog.onConfigurationChanged(configuration);
+ dialog.dismiss();
+
+ inOrder.verify(mDelegate).beforeCreate(dialog, /* savedInstanceState= */ null);
+ inOrder.verify(mDelegate).onCreate(dialog, /* savedInstanceState= */ null);
+ inOrder.verify(mDelegate).onStart(dialog);
+ inOrder.verify(mDelegate).onWindowFocusChanged(dialog, /* hasFocus= */ true);
+ inOrder.verify(mDelegate).onConfigurationChanged(dialog, configuration);
+ inOrder.verify(mDelegate).onStop(dialog);
+ }
+
+ private SystemUIDialog createDialogWithDelegate() {
+ SystemUIDialog.Factory factory = new SystemUIDialog.Factory(
+ getContext(),
+ mFeatureFlags,
+ Dependency.get(SystemUIDialogManager.class),
+ Dependency.get(SysUiState.class),
+ Dependency.get(BroadcastDispatcher.class),
+ Dependency.get(DialogLaunchAnimator.class)
+ );
+ return factory.create(mDelegate);
+ }
}
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index c428952..0537f17 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -26,22 +26,31 @@
name: "SystemUIPluginLib",
srcs: [
- "src/**/*.java",
- "src/**/*.kt",
"bcsmartspace/src/**/*.java",
"bcsmartspace/src/**/*.kt",
+ "src/**/*.java",
+ "src/**/*.kt",
],
+ optimize: {
+ proguard_flags_files: [
+ "proguard_plugins.flags",
+ ],
+ export_proguard_flags_files: true,
+ },
+
// If you add a static lib here, you may need to also add the package to the ClassLoaderFilter
// in PluginInstance. That will ensure that loaded plugins have access to the related classes.
// You should also add it to proguard_common.flags so that proguard does not remove the portions
// of the library which are used by the plugins but not by systemui itself.
static_libs: [
"androidx.annotation_annotation",
+ "androidx-constraintlayout_constraintlayout",
"PluginCoreLib",
"SystemUIAnimationLib",
"SystemUICommon",
"SystemUILogLib",
+ "androidx.annotation_annotation",
],
}
diff --git a/packages/SystemUI/plugin/proguard_plugins.flags b/packages/SystemUI/plugin/proguard_plugins.flags
new file mode 100644
index 0000000..abac27f
--- /dev/null
+++ b/packages/SystemUI/plugin/proguard_plugins.flags
@@ -0,0 +1,9 @@
+# The plugins and core log subpackages act as shared libraries that might be referenced in
+# dynamically-loaded plugin APKs.
+-keep class com.android.systemui.plugins.** {
+ *;
+}
+
+-keep class com.android.systemui.log.core.** {
+ *;
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 485c27e..63ded2e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -17,6 +17,7 @@
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
+import androidx.constraintlayout.widget.ConstraintSet
import com.android.internal.annotations.Keep
import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.annotations.ProvidesInterface
@@ -85,6 +86,9 @@
/** View that renders the clock face */
val view: View
+ /** Layout specification for this clock */
+ val layout: ClockFaceLayout
+
/** Determines the way the hosting app should behave when rendering this clock face */
val config: ClockFaceConfig
@@ -98,6 +102,30 @@
var messageBuffer: MessageBuffer?
}
+/** Specifies layout information for the */
+interface ClockFaceLayout {
+ /** All clock views to add to the root constraint layout before applying constraints. */
+ val views: List<View>
+
+ /** Custom constraints to apply to Lockscreen ConstraintLayout. */
+ fun applyConstraints(constraints: ConstraintSet): ConstraintSet
+}
+
+/** A ClockFaceLayout that applies the default lockscreen layout to a single view */
+class DefaultClockFaceLayout(val view: View) : ClockFaceLayout {
+ // both small and large clock should have a container (RelativeLayout in
+ // SimpleClockFaceController)
+ override val views = listOf(view)
+ override fun applyConstraints(constraints: ConstraintSet): ConstraintSet {
+ if (views.size != 1) {
+ throw IllegalArgumentException(
+ "Should have only one container view when using DefaultClockFaceLayout"
+ )
+ }
+ return constraints
+ }
+}
+
/** Events that should call when various rendering parameters change */
interface ClockEvents {
/** Call whenever timezone changes */
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 4e39f1a..b7e1545 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/Android.bp
@@ -27,6 +27,9 @@
srcs: ["src/**/*.java"],
optimize: {
proguard_flags_files: ["proguard.flags"],
+ // Ensure downstream clients that reference this as a shared lib
+ // inherit the appropriate flags to preserve annotations.
+ export_proguard_flags_files: true,
},
// Enforce that the library is built against java 8 so that there are
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index b534fcec..42b5923 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -4,4 +4,4 @@
*;
}
--keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; }
\ No newline at end of file
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; }
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index 445bdc2..21b019e 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -1,3 +1,4 @@
+-include proguard_kotlin.flags
-keep class com.android.systemui.VendorServices
# Needed to ensure callback field references are kept in their respective
@@ -20,16 +21,6 @@
public <init>(android.content.Context, android.util.AttributeSet);
}
--keep class com.android.systemui.tuner.*
-
-# The plugins and core log subpackages act as shared libraries that might be referenced in
-# dynamically-loaded plugin APKs.
--keep class com.android.systemui.plugins.** {
- *;
-}
--keep class com.android.systemui.log.core.** {
- *;
-}
-keep class androidx.core.app.CoreComponentFactory
# Keep the wm shell lib
@@ -51,45 +42,6 @@
# part of optimization. This lets proguard inline trivial getter/setter methods.
-allowaccessmodification
-# Removes runtime checks added through Kotlin to JVM code genereration to
-# avoid linear growth as more Kotlin code is converted / added to the codebase.
-# These checks are generally applied to Java platform types (values returned
-# from Java code that don't have nullness annotations), but we remove them to
-# avoid code size increases.
-#
-# See also https://kotlinlang.org/docs/reference/java-interop.html
-#
-# TODO(b/199941987): Consider standardizing these rules in a central place as
-# Kotlin gains adoption with other platform targets.
--assumenosideeffects class kotlin.jvm.internal.Intrinsics {
- # Remove check for method parameters being null
- static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
-
- # When a Java platform type is returned and passed to Kotlin NonNull method,
- # remove the null check
- static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
- static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
-
- # Remove check that final value returned from method is null, if passing
- # back Java platform type.
- static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
- static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
-
- # Null check for accessing a field from a parent class written in Java.
- static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
- static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
-
- # Removes code generated from !! operator which converts Nullable type to
- # NonNull type. These would throw an NPE immediate after on access.
- static void checkNotNull(java.lang.Object, java.lang.String);
- static void checkNotNullParameter(java.lang.Object, java.lang.String);
-
- # Removes lateinit var check being used before being set. Check is applied
- # on every field access without this.
- static void throwUninitializedPropertyAccessException(java.lang.String);
-}
-
-
# Strip verbose logs.
-assumenosideeffects class android.util.Log {
static *** v(...);
diff --git a/packages/SystemUI/proguard_kotlin.flags b/packages/SystemUI/proguard_kotlin.flags
new file mode 100644
index 0000000..ceea3c8
--- /dev/null
+++ b/packages/SystemUI/proguard_kotlin.flags
@@ -0,0 +1,37 @@
+# Removes runtime checks added through Kotlin to JVM code genereration to
+# avoid linear growth as more Kotlin code is converted / added to the codebase.
+# These checks are generally applied to Java platform types (values returned
+# from Java code that don't have nullness annotations), but we remove them to
+# avoid code size increases.
+#
+# See also https://kotlinlang.org/docs/reference/java-interop.html
+#
+# TODO(b/199941987): Consider standardizing these rules in a central place as
+# Kotlin gains adoption with other platform targets.
+-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
+ # Remove check for method parameters being null
+ static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
+
+ # When a Java platform type is returned and passed to Kotlin NonNull method,
+ # remove the null check
+ static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
+ static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
+
+ # Remove check that final value returned from method is null, if passing
+ # back Java platform type.
+ static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
+ static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
+
+ # Null check for accessing a field from a parent class written in Java.
+ static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
+ static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
+
+ # Removes code generated from !! operator which converts Nullable type to
+ # NonNull type. These would throw an NPE immediate after on access.
+ static void checkNotNull(java.lang.Object, java.lang.String);
+ static void checkNotNullParameter(java.lang.Object, java.lang.String);
+
+ # Removes lateinit var check being used before being set. Check is applied
+ # on every field access without this.
+ static void throwUninitializedPropertyAccessException(java.lang.String);
+}
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 36757f8..cb061ed 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Gesigslot is onbeskikbaar"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth gekoppel."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth-toestelikoon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klik om toestelbesonderhede op te stel."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Gekoppel aan <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Moenie Steur Nie"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen saamgebinde toestelle beskikbaar nie"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tik om ’n toestel te koppel of ontkoppel"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Bind nuwe toestel saam"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Sien alles"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gebruik Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera en mikrofoon is geblokkeer"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoon is geblokkeer"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteitmodus is aan"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikerteenwoordigheid is bespeur"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
<string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ebdfd95..73f446c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"በመልክ መክፈት አይገኝም"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ብሉቱዝ ተያይዟል።"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"የብሉቱዝ መሣሪያ አዶ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"የመሣሪያ ዝርዝርን ለማዋቀር ጠቅ ያድርጉ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"ከ<xliff:g id="CAST">%s</xliff:g> ጋር ተገናኝቷል።"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"አትረብሽ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ብሉቱዝ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ምንም የተጣመሩ መሣሪያዎች አይገኝም"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"መሣሪያን ለማገናኘት ወይም ግንኙነቱን ለማቋረጥ መታ ያድርጉ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ሁሉንም ይመልከቱ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ብሉቱዝን ይጠቀሙ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ካሜራ እና ማይክሮፎን ታግደዋል"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ማይክሮፎን ታግዷል"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"የቅድሚያ ሁነታ በርቷል"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"የተጠቃሚ ተገኝነት ታውቋል"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
<string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 84a3004..cc2f488 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ميزة \"فتح الجهاز بالتعرف على الوجه\" غير متاحة."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"رمز الجهاز الذي يتضمّن بلوتوث"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"انقر هنا لضبط إعدادات الجهاز."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"تم الاتصال بـ <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"عدم الإزعاج"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"لا يتوفر أي أجهزة مقترنة"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"انقر لربط جهاز أو إلغاء ربطه."</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"إقران جهاز جديد"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"عرض الكل"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"استخدام البلوتوث"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخدام الميكروفون محظور."</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"وضع الأولوية مفعّل."</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"تم رصد تواجد المستخدم."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
<string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d04b33a..4e75995 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ফেচ আনলক সুবিধা উপলব্ধ নহয়"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ব্লুটুথ ডিভাইচৰ চিহ্ন"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ডিভাইচৰ সবিশেষ কনফিগাৰ কৰিবলৈ ক্লিক কৰক"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>ত সংযোগ হ’ল।"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"অসুবিধা নিদিব"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"কোনো যোৰা লগোৱা ডিভাইচ উপলব্ধ নহয়।"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"এটা ডিভাইচৰ সংযোগ কৰিবলৈ অথবা ডিভাইচটোৰ সৈতে সংযোগ বিচ্ছিন্ন কৰিবলৈ টিপক"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"আটাইবোৰ চাওক"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ব্লুটুথ ব্যৱহাৰ কৰক"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"কেমেৰা আৰু মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"অগ্ৰাধিকাৰ দিয়া ম’ড অন আছে"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যৱহাৰকাৰীৰ উপস্থিতি চিনাক্ত কৰা হৈছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
<string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1ef94326..3e6765d 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Üz ilə kiliddən çıxarma əlçatan deyil"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth qoşulub."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth cihazı ikonası"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Cihaz təfərrüatlarını konfiqurasiya etmək üçün klikləyin"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> cihazına qoşulub."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Narahat etməyin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Heç bir cütlənmiş cihaz əlçatan deyil"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toxunaraq cihaza qoşulun, yaxud əlaqəni ayırın"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Yeni cihaz birləşdirin"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Hamısına baxın"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth aç"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera və mikrofon bloklanıb"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklanıb"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritet rejimi aktivdir"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"İstifadəçi mövcudluğu aşkarlandı"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
<string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index de638b7..17e9f9b 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem nije dostupno"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je priključen."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona Bluetooth uređaja"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknite da biste konfigurisali detalje o uređaju"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procenat napunjenosti baterije nije poznat."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Povezani smo sa uređajem <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nije dostupan nijedan upareni uređaj"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da biste povezali uređaj ili prekinuli vezu"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Upari novi uređaj"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Prikaži sve"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetni režim je uključen"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Prisustvo korisnika može da se otkrije"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
<string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 30c8053..252b2bd 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Распазнаванне твару не працуе"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-сувязь."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Значок прылады з Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Націсніце, каб задаць падрабязныя налады прылады"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Працэнт зараду акумулятара невядомы."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ёсць падключэнне да <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбаваць"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма даступных спалучаных прылад"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Націсніце, каб падключыць або адключыць прыладу"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Спалучыць новую прыладу"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Паглядзець усе"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Выкарыстоўваць Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрафон заблакіраваны"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Прыярытэтны рэжым уключаны"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Выяўлена прысутнасць карыстальніка"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
<string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплеі?"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f5a8214..4beb901 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"„Отключване с лице“ не е налице"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е включен."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Икона за устройство с Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Кликнете, за да конфигурирате подробностите за устройството"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Установена е връзка с/ъс <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не безпокойте"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма налични сдвоени устройства"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Докоснете, за да свържете устройство или да прекъснете връзката му"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Сдвояване на ново устройство"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Преглед на всички"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Използване на Bluetooth"</string>
@@ -509,7 +507,7 @@
<string name="csd_system_lowered_text" product="default" msgid="1250251883692996888">"Нивото на силата на звука на слушалките е било високо по-дълго, отколкото е препоръчително"</string>
<string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Нивото на силата на звука на слушалките е надвишило безопасния лимит за тази седмица"</string>
<string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Продължете да слушате"</string>
- <string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Намаляване на силата на звука"</string>
+ <string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Намаляване на звука"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Достъпът до камерата и микрофона е блокиран"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Достъпът до микрофона е блокиран"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетният режим е включен"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Установено е присъствие на потребител"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 43cf9e3..cd15261 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\'ফেস আনলক\' উপলভ্য নেই"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ব্লুটুথ ডিভাইসের আইকন"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ডিভাইসের বিবরণ কনফিগার করতে ক্লিক করুন"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> এর সাথে সংযুক্ত৷"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"বিরক্ত করবে না"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"চেনা কোনও ডিভাইস নেই"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"কোনও ডিভাইস কানেক্ট বা ডিসকানেক্ট করতে ট্যাপ করুন"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"সব দেখুন"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ব্লুটুথ ব্যবহার করুন"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\'প্রায়োরিটি\' মোড চালু করা আছে"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যবহারকারীর উপস্থিতি শনাক্ত করা হয়েছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
<string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লে আয়না?"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c443542..a6d1f2b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem je nedostupno"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je povezan."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona Bluetooth uređaja"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknite da konfigurirate detalje uređaja"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Povezan na <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne ometaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nema dostupnih uparenih uređaja"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da povežete uređaj ili prekinete njegovu povezanost"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Upari novi uređaj"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Prikaži sve"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Način rada Prioriteti je uključen"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkriveno je prisustvo korisnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
<string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 5995503..143bd43 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueig facial no està disponible"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connectat."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icona de dispositiu Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Fes clic per configurar els detalls del dispositiu"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Està connectat amb <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestis"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hi ha dispositius vinculats disponibles"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca per connectar o desconnectar un dispositiu"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Vincula un dispositiu nou"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Mostra-ho tot"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utilitza\'l"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El mode Prioritat està activat"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"S\'ha detectat la presència d\'usuaris"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
<string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vols replicar-ho a la pantalla externa?"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ea85db9..9ffc4b2 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odemknutí obličejem není k dispozici"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Rozhraní Bluetooth je připojeno."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona zařízení Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknutím nakonfigurujete podrobnosti o zařízení"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Jste připojeni k zařízení <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nerušit"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nejsou dostupná žádná spárovaná zařízení"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím připojíte nebo odpojíte zařízení"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Spárovat nové zařízení"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Zobrazit vše"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Použít Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokován"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Režim priority je zapnutý"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Je zjištěna přítomnost uživatele"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
<string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ae54f3a..0eb5084 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansigtsoplåsning er utilgængelig"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikon for Bluetooth-enhed"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klik for at konfigurere enhedsoplysninger"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Forbundet til <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Forstyr ikke"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Der er ingen tilgængelige parrede enheder"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tryk for at oprette eller afbryde forbindelse til en enhed"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Par ny enhed"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Se alt"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Brug Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetstilstand er aktiveret"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Brugertilstedeværelse er registreret"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
<string name="install_app" msgid="5066668100199613936">"Installer app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2fdb477..c9050f5 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Entsperrung per Gesichtserkennung nicht verfügbar"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Mit Bluetooth verbunden"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Symbol des Bluetooth-Geräts"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klicke, um das Gerätedetail zu konfigurieren"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Verbunden mit <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1182,8 +1181,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera und Mikrofon blockiert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon blockiert"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritätsmodus an"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Anwesenheit des Nutzers wurde erkannt"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
<string name="install_app" msgid="5066668100199613936">"App installieren"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 194e04c..80eef9f 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ξεκλ. με πρόσωπο μη διαθ."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Το Bluetooth είναι συνδεδεμένο."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Εικονίδιο συσκευής Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Κάντε κλικ για να διαμορφώσετε τις λεπτομέρειες συσκευής"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Συνδέθηκε σε <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Μην ενοχλείτε"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Δεν υπάρχουν διαθέσιμες συσκευές σε σύζευξη"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Πατήστε για σύνδεση ή αποσύνδεση μιας συσκευής"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Σύζευξη νέας συσκευής"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Εμφάνιση όλων"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Χρήση Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Η κάμερα και το μικρόφωνο έχουν αποκλειστεί"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Το μικρόφωνο έχει αποκλειστεί"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Η λειτουργία προτεραιότητας είναι ενεργοποιημένη"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Εντοπίστηκε παρουσία χρήστη"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
<string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 87ca42b..c6fe169 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth device icon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Click to configure device detail"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Pair new device"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"See all"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index c69533d..f9aa1cb 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth device icon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Click to configure device detail"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone blocked"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 87ca42b..c6fe169 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth device icon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Click to configure device detail"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Pair new device"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"See all"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 87ca42b..c6fe169 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth device icon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Click to configure device detail"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Pair new device"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"See all"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 264084f..23f7483 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth device icon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Click to configure device detail"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone blocked"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Priority mode on"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 66dd037..7c3960e 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueo facial no disponible"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ícono de dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Haz clic para configurar los detalles del dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Se desconoce el porcentaje de la batería."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No interrumpir"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos sincronizados disponibles"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Presiona para conectar o desconectar un dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Vincular dispositivo nuevo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Ver todos"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El modo de prioridad está activado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se detectó la presencia del usuario"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar a la pantalla externa?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index de40f3b..f65b2e5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueo facial no disponible"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icono de dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Haz clic para configurar la información del dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestar"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos vinculados disponibles"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca para conectar o desconectar un dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Empareja un nuevo dispositivo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Ver todos"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridad activado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se ha detectado la presencia de usuarios"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Replicar en pantalla externa?"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 7606254..d648f87 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Näoga avamine pole saadaval"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth on ühendatud."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth-seadme ikoon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klõpsake seadme üksikasjade konfigureerimiseks"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Aku laetuse protsent on teadmata."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ühendatud ülekandega <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mitte segada"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ühtegi seotud seadet pole saadaval"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Puudutage seadme ühendamiseks või ühenduse katkestamiseks"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Uue seadme sidumine"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Kuva kõik"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Kasuta Bluetoothi"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteetne režiim on sisse lülitatud"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Tuvastati kasutaja kohalolu"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
<string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 7845339..e3c32e9 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Aurpegi bidez desblokeatzeko eginbidea ez dago erabilgarri"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetootha konektatuta."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth bidezko gailuaren ikonoa"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Gailuaren xehetasuna konfiguratzeko, sakatu hau"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Hona konektatuta: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ez molestatzeko modua"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetootha"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ez dago parekatutako gailurik erabilgarri"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Sakatu hau gailu bat konektatu edo deskonektatzeko"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Parekatu beste gailu bat"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Ikusi guztiak"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Erabili Bluetootha"</string>
@@ -506,7 +504,7 @@
<string name="sound_settings" msgid="8874581353127418308">"Audioa eta dardara"</string>
<string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ezarpenak"</string>
<string name="csd_lowered_title" product="default" msgid="2464112924151691129">"Bolumena maila seguruago batera jaitsi da"</string>
- <string name="csd_system_lowered_text" product="default" msgid="1250251883692996888">"Entzungailuen bolumena gomendatutako denboran baino gehiagoan eduki da ozen"</string>
+ <string name="csd_system_lowered_text" product="default" msgid="1250251883692996888">"Entzungailuen bolumena gomendatutako denbora baino luzaroago egon da ozen"</string>
<string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Entzungailuen bolumenak aste honetarako muga segurua gainditu du"</string>
<string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Jarraitu entzuten"</string>
<string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Jaitsi bolumena"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera eta mikrofonoa blokeatuta daude"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonoa blokeatuta dago"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Lehentasun modua aktibatuta dago"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Erabiltzailearen presentzia hauteman da"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
<string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 3fc784b..805feff 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"«قفلگشایی با چهره» دردسترس نیست"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوتوث متصل است."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"نماد دستگاه بلوتوث"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"برای پیکربندی جزئیات دستگاه کلیک کنید"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"درصد شارژ باتری مشخص نیست."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"به <xliff:g id="CAST">%s</xliff:g> متصل شد."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"مزاحم نشوید"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"هیچ دستگاه مرتبط شدهای موجود نیست"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"برای اتصال یا قطع اتصال دستگاه، ضربه بزنید"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"جفت کردن دستگاه جدید"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"دیدن همه"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"استفاده از بلوتوث"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"دوربین و میکروفون مسدود شدهاند"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"میکروفون مسدود شده است"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"حالت اولویت روشن است"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"حضور کاربر شناسایی میشود"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
<string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"در نمایشگر خارجی پخش شود؟"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 73532d6..9a8ceca 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Kasvojentunnistusavaus ei ole saatavilla"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth yhdistetty."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth-laitekuvake"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Määritä laitteen asetukset klikkaamalla"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Yhdistetty kohteeseen <xliff:g id="CAST">%s</xliff:g>"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Älä häiritse"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Laitepareja ei ole käytettävissä"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Muodosta yhteys laitteeseen tai katkaise yhteys napauttamalla"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Muodosta uusi laitepari"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Näytä kaikki"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Käytä Bluetoothia"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni estetty"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tärkeät-tila on päällä"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Käyttäjän läsnäolo havaittu"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
<string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ec9e65a..79f0c44 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Déverrouillage par reconnaissance faciale inaccessible."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icône de l\'appareil Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Cliquez pour configurer les détails de l\'appareil"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun des appareils associés n\'est disponible"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Touchez pour connecter ou déconnecter un appareil"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Associer un nouvel appareil"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Tout afficher"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utiliser le Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Priorité activé"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
<string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8accd74..4988cf5 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Déverrouillage par reconnaissance faciale indisponible"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icône de l\'appareil Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Cliquer pour configurer les détails de l\'appareil"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun appareil associé disponible."</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Appuyer pour connecter ou déconnecter un appareil"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Associer un nouvel appareil"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Tout afficher"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utiliser le Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Prioritaire activé"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence de l\'utilisateur est détectée"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
<string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirroring sur écran externe ?"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 95bb93f..90f1535 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O desbloqueo facial non está dispoñible"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icona do dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Facer clic para configurar os detalles do dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Descoñécese a porcentaxe da batería."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Dispositivo conectado: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non molestar"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Non hai dispositivos vinculados dispoñibles"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca para conectar ou desconectar un dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Vincular dispositivo novo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Ver todo"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"O modo de prioridade está activado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Detectouse a presenza de usuarios"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e650671..302dab1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ફેસ અનલૉક સુવિધા ઉપલબ્ધ નથી"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"બ્લૂટૂથ કનેક્ટ થયું."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"બ્લૂટૂથ ડિવાઇસનું આઇકન"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ડિવાઇસની વિગત ગોઠવવા માટે ક્લિક કરો"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> થી કનેક્ટ થયાં."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> થી કનેક્ટ કરેલ."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ખલેલ પાડશો નહીં"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"બ્લૂટૂથ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"કોઈ જોડી કરેલ ઉપકરણો ઉપલબ્ધ નથી"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"કોઈ ડિવાઇસ કનેક્ટ કરવા કે ડિસ્કનેક્ટ કરવા માટે ટૅપ કરો"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"તમામ જુઓ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"બ્લૂટૂથનો ઉપયોગ કરો"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"પ્રાધાન્યતા મોડ ચાલુ છે"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"વપરાશકર્તાની હાજરીની ભાળ મળી છે"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
<string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index cdb3658..5df950c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फ़ेस अनलॉक की सुविधा उपलब्ध नहीं है"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट किया गया."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ब्लूटूथ डिवाइस का आइकॉन"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"डिवाइस की जानकारी कॉन्फ़िगर करने के लिए क्लिक करें"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> से कनेक्ट है."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"परेशान न करें"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोई भी युग्मित डिवाइस उपलब्ध नहीं"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"किसी डिवाइस को कनेक्ट या डिसकनेक्ट करने के लिए टैप करें"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"नया डिवाइस जोड़ें"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"सभी देखें"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लूटूथ इस्तेमाल करें"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कैमरे और माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राथमिकता मोड चालू है"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"उपयोगकर्ता की मौजूदगी का पता लगाया गया"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
<string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाहरी डिसप्ले को अन्य डिवाइस पर दिखाना है?"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b4ea7dc..de60e8e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem nije dostupno"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth povezan."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona Bluetooth uređaja"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknite da biste konfigurirali pojedinosti o uređaju"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak baterije nije poznat."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Povezani ste sa sljedećim uređajem: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Upareni uređaji nisu dostupni"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da biste povezali uređaj ili prekinuli vezu uređaja"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Upari novi uređaj"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Pogledajte sve"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Uključi"</string>
@@ -508,7 +506,7 @@
<string name="csd_lowered_title" product="default" msgid="2464112924151691129">"Glasnoća je stišana na sigurniju razinu"</string>
<string name="csd_system_lowered_text" product="default" msgid="1250251883692996888">"Pojačana je glasnoća u slušalicama dulje nego što se preporučuje"</string>
<string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Glasnoća slušalica premašila je sigurno ograničenje za ovaj tjedan"</string>
- <string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Nastavite slušati"</string>
+ <string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Nastavi slušati"</string>
<string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Stišaj"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je prikvačena"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Blokirani su kamera i mikrofon"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Uključen je prioritetni način rada"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkrivena je prisutnost korisnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
<string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 21194c4..1380985 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Nem áll rendelkezésre az Arcalapú feloldás"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth csatlakoztatva."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth-eszköz ikon"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kattintson az eszköz beállításainak megadásához"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Csatlakozva a következőhöz: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritás mód bekapcsolva"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Felhasználói jelenlét észlelve"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
<string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index eafd14f..c31a162 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Դեմքով ապակողպումն անհասանելի է"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-ը միացված է:"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth սարքի պատկերակ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Սեղմեք՝ սարքի մանրամասները կազմաձևելու համար"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Միացված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Չանհանգստացնել"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Զուգակցված սարքեր չկան"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Հպեք՝ սարք միացնելու կամ անջատելու համար"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Նոր սարքի զուգակցում"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Տեսնել բոլորը"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Միացնել Bluetooth-ը"</string>
@@ -1124,7 +1122,7 @@
<string name="clipboard_image_preview" msgid="2156475174343538128">"Պատկերի նախադիտում"</string>
<string name="clipboard_edit" msgid="4500155216174011640">"փոփոխել"</string>
<string name="add" msgid="81036585205287996">"Ավելացնել"</string>
- <string name="manage_users" msgid="1823875311934643849">"Օգտատերերի կառավարում"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Կառավարել"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Այս ծանուցումը հնարավոր չէ քաշել տրոհված էկրանի մեկ հատվածից մյուսը"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi-ը հասանելի չէ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Առաջնահերթության ռեժիմ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Խոսափողն արգելափակված է"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Առաջնահերթության ռեժիմը միացված է"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Հայտնաբերվել է օգտատեր"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
<string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c78b42b..56d0381 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Buka dengan Wajah tidak tersedia"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikon perangkat Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klik untuk mengonfigurasi detail perangkat"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Terhubung ke <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Perangkat yang disandingkan tak tersedia"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ketuk untuk menghubungkan atau memutuskan koneksi perangkat"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Sambungkan perangkat baru"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Lihat semua"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gunakan Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode prioritas diaktifkan"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna terdeteksi"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
<string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 5c68e70..1e517b1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Andlitskenni ekki í boði"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tengt."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Tákn Bluetooth-tækis"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Smelltu til að stilla tækjaupplýsingar"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Staða rafhlöðu óþekkt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Tengt við <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ónáðið ekki"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Engin pöruð tæki til staðar"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ýttu til að tengja eða aftengja tæki"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Para nýtt tæki"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Sjá allt"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Nota Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Kveikt er á forgangsstillingu"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viðvera notanda greindist"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
<string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index dfb0054..03faea6 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Sblocco con il Volto non disponibile"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth collegato."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icona del dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Fai clic per configurare i dettagli del dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentuale della batteria sconosciuta."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connesso a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connesso a: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non disturbare"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nessun dispositivo accoppiato disponibile"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tocca per connettere o disconnettere un dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Accoppia nuovo dispositivo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Visualizza tutti"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usa Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modalità priorità attivata"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viene rilevata la presenza dell\'utente"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
<string name="install_app" msgid="5066668100199613936">"Installa app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8eb9a55..f007658 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"顔認証を利用できません"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth デバイスのアイコン"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"クリックしてデバイスの詳細を設定します"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"バッテリー残量は不明です。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>に接続されています。"</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"カメラとマイクはブロックされています"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"マイクはブロックされています"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先モードは ON です"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"会話を始められます"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
<string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 3e508b7..562962a 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"სახით განბლოკვა მიუწვდომელია."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth დაკავშირებულია."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth მოწყობილობის ხატულა"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"დააწკაპუნეთ მოწყობილობის დეტალების კონფიგურირებისთვის"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"დაკავშირებულია მოწყობილობასთან: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"არ შემაწუხოთ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"დაწყვილებული მოწყობილობები მიუწვდომელია"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"შეეხეთ მოწყობილობის დასაკავშირებლად ან გასათიშად"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ყველას ნახვა"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-ის გამოყენება"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"კამერა და მიკროფონი დაბლოკილია"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"მიკროფონი დაბლოკილია"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"პრიორიტეტული რეჟიმი ჩართულია"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"აღმოჩენილია მომხმარებლის ყოფნა"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
<string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a2231ce..7532a64 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Бет тану функциясы қолжетімсіз."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth қосылған."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth құрылғысы белгішесі"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Құрылғы деректерін конфигурациялау үшін басыңыз."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> трансляциясына қосылды."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жұптасқан құрылғылар жоқ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Құрылғыны жалғау не ажырату үшін түртіңіз."</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Жаңа құрылғыны жұптау"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Барлығын көру"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-ты пайдалану"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон блокталған."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон блокталған."</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\"Маңызды\" режимі қосулы."</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Пайдаланушы анықталды."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
<string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 95c4360..c823635 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខបានទេ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"បានតភ្ជាប់ប៊្លូធូស។"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"រូបឧបករណ៍ប៊្លូធូស"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ចុចដើម្បីកំណត់រចនាសម្ព័ន្ធព័ត៌មានលម្អិតអំពីឧបករណ៍"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"មិនដឹងអំពីភាគរយថ្មទេ។"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បានភ្ជាប់ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"បានភ្ជាប់ទៅ <xliff:g id="CAST">%s</xliff:g>"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"កុំរំខាន"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ប៊្លូធូស"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"មិនមានឧបករណ៍ផ្គូផ្គងដែលអាចប្រើបាន"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ចុចដើម្បីភ្ជាប់ ឬផ្ដាច់ឧបករណ៍"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"មើលទាំងអស់"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ប្រើប៊្លូធូស"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"បានទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូន"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"បានទប់ស្កាត់មីក្រូហ្វូន"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"មុខងារអាទិភាពត្រូវបានបើក"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"វត្តមានអ្នកប្រើប្រាស់ត្រូវបានចាប់ដឹង"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
<string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅឧបករណ៍បញ្ចាំងខាងក្រៅឬ?"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 743ee00..7447d5b 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ಬ್ಲೂಟೂತ್ ಸಾಧನ ಐಕಾನ್"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ಸಾಧನದ ವಿವರಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ಬ್ಯಾಟರಿ ಶೇಕಡಾವಾರು ತಿಳಿದಿಲ್ಲ."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ಬ್ಲೂಟೂತ್"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ಯಾವುದೇ ಜೋಡಿಸಲಾದ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ಸಾಧನವನ್ನು ಕನೆಕ್ಟ್ ಅಥವಾ ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ಬ್ಲೂಟೂತ್ ಬಳಸಿ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ಆದ್ಯತೆಯ ಮೋಡ್ ಆನ್ ಆಗಿದೆ"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ಬಳಕೆದಾರರ ಉಪಸ್ಥಿತಿಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
<string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2911173..8859660 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"얼굴 인식 잠금 해제를 사용할 수 없습니다."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"블루투스가 연결되었습니다."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"블루투스 기기 아이콘"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"기기 세부정보를 구성하려면 클릭하세요."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>에 연결됨"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"방해 금지 모드"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"블루투스"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"페어링된 기기가 없습니다"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"기기를 연결 또는 연결 해제하려면 탭하세요"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"새 기기와 페어링"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"모두 보기"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"블루투스 사용"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"마이크 차단됨"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"우선순위 모드 설정됨"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"사용자 정보가 감지되었습니다."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
<string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index a0004e7..ae4f431 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\"Жүзүнөн таанып ачуу\" жеткиликсиз"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth байланышта"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth түзмөгүнүн сүрөтчөсү"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Түзмөктүн чоо-жайын конфигурациялоо үчүн чыкылдатыңыз"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера менен микрофон бөгөттөлдү"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон бөгөттөлдү"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Маанилүү сүйлөшүүлөр режими күйүк"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Колдонуучу аныкталды"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
<string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 443bd70..a4c9417 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ໃຊ້ການປົດລັອກດ້ວຍໜ້າບໍ່ໄດ້"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ໄອຄອນອຸປະກອນ Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ຄລິກເພື່ອຕັ້ງຄ່າລາຍລະອຽດອຸປະກອນ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="CAST">%s</xliff:g> ແລ້ວ."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ຫ້າມລົບກວນ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ບໍ່ມີອຸປະກອນທີ່ສາມາດຈັບຄູ່ໄດ້"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ແຕະເພື່ອເຊື່ອມຕໍ່ ຫຼື ຕັດການເຊື່ອມຕໍ່ອຸປະກອນ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ເບິ່ງທັງໝົດ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ໃຊ້ Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ໂໝດຄວາມສຳຄັນເປີດຢູ່"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ກວດພົບຕົວຕົນຜູ້ໃຊ້"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
<string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b6758b7e..772ff0e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Atrakinimo pagal veidą funkcija nepasiekiama"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"„Bluetooth“ prijungtas."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"„Bluetooth“ įrenginio piktograma"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Spustelėkite, jei norite konfigūruoti išsamią įrenginio informaciją"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumuliatoriaus energija procentais nežinoma."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Prisijungta prie <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Netrukdymo režimas"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nėra pasiekiamų susietų įrenginių"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Palieskite, kad prijungtumėte ar atjungtumėte įrenginį"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Susieti naują įrenginį"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Žiūrėti viską"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"„Bluetooth“ naudojimas"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparatas ir mikrofonas užblokuoti"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonas užblokuotas"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteto režimas įjungtas"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Aptikta naudotojo veikla"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
<string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a1de3cf..9987f48 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Autorizācija pēc sejas nav pieejama"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth savienojums ir izveidots."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth ierīces ikona"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Lai konfigurētu ierīces informāciju, noklikšķiniet"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Savienots ar ierīci <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režīms “Netraucēt”"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nav pieejama neviena pārī savienota ierīce."</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Lai pievienotu vai atvienotu kādu ierīci, pieskarieties."</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Savienošana pārī ar jaunu ierīci"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Skatīt visas"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Izmantot Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritātes režīms ir ieslēgts"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Konstatēta lietotāja klātbūtne"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
<string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 93c973f..273443f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"„Отклучувањето со лик“ е недостапно"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е поврзан."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Икона за уред со Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Кликнете за да ги конфигурирате деталите за уредот"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Поврзано со <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не вознемирувај"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нема достапни спарени уреди"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Допрете за да поврзете уред или да ја прекинете врската со уред"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Спарете нов уред"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Прикажи ги сите"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Користи Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетниот режим е вклучен"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Откриено е присуство на корисник"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се синхронизира на надворешниот екран?"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index f7aa8cb..a521eee 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ഫെയ്സ് അൺലോക്ക് ലഭ്യമല്ല"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ബ്ലൂടൂത്ത് കണക്റ്റുചെയ്തു."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth ഉപകരണ ഐക്കൺ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ഉപകരണത്തിന്റെ വിശദാംശങ്ങൾ കോൺഫിഗർ ചെയ്യാൻ ക്ലിക്ക് ചെയ്യുക"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ബാറ്ററി ശതമാനം അജ്ഞാതമാണ്."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ജോടിയാക്കിയ ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ഒരു ഉപകരണം കണക്റ്റ് ചെയ്യാനോ വിച്ഛേദിക്കാനോ ടാപ്പ് ചെയ്യുക"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"എല്ലാം കാണുക"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth ഉപയോഗിക്കുക"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ക്യാമറയും മൈക്രോഫോണും ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"മൈക്രോഫോൺ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"മുൻഗണനാ മോഡ് ഓണാണ്"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ഉപയോക്താവിന്റെ സാന്നിധ്യം കണ്ടെത്തി"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
<string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5ad6d7e..7e58aff 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Царайгаар түгжээ тайлах боломжгүй"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth холбогдсон."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth төхөөрөмжийн дүрс тэмдэг"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Төхөөрөмжийн дэлгэрэнгүйг тохируулахын тулд товшино уу"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>-д холбогдсон."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Бүү саад бол"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Хослуулсан төхөөрөмж байхгүй"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Төхөөрөмжийг холбох эсвэл салгахын тулд товшино уу"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Шинэ төхөөрөмж хослуулах"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Бүгдийг харах"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-г ашиглах"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камер болон микрофоныг блоклосон"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофоныг блоклосон"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Чухал горим асаалттай байна"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Хэрэглэгч байгааг илрүүлсэн"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
<string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 54bfb66..4f0b947 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फेस अनलॉक उपलब्ध नाही"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट केले."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ब्लूटूथ डिव्हाइस आयकन"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"डिव्हाइसचे तपशील कॉंफिगर करण्यासाठी क्लिक करा"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्ट केले."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> शी कनेक्ट केले."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"व्यत्यय आणू नका"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोणतेही जोडलेले डिव्हाइसेस उपलब्ध नाहीत"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"डिव्हाइस कनेक्ट किंवा डिस्कनेक्ट करण्यासाठी टॅप करा"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"नवीन डिव्हाइस पेअर करा"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"सर्व पहा"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लूटूथ वापरा"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राधान्य मोड सुरू आहे"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"वापरकर्त्याची उपस्थिती डिटेक्ट केली"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string>
<string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index c486e1d..514e5ac 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Buka Kunci Wajah tidak tersedia"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth disambungkan."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikon peranti Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klik untuk mengkonfigurasi butiran peranti"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Peratusan kuasa bateri tidak diketahui."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Disambungkan kepada <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Disambungkan ke <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Tiada peranti berpasangan tersedia"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ketik untuk menyambungkan atau memutuskan sambungan peranti"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Gandingkan peranti baharu"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Lihat semua"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gunakan Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon disekat"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon disekat"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mod keutamaan dihidupkan"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna dikesan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
<string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index c38d493..0a38701 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း မရနိုင်ပါ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ဘလူးတုသ်သုံးစက် သင်္ကေတ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"စက်အသေးစိတ်ကို စီစဉ်သတ်မှတ်ရန် နှိပ်ပါ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> သို့ချိတ်ဆက်ထားပါသည်။"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"မနှောင့်ယှက်ရ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ဘလူးတုသ်"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ချိတ်တွဲထားသည့် ကိရိယာများ မရှိ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"စက်ကို ချိတ်ဆက်ရန် (သို့) ချိတ်ဆက်မှုဖြုတ်ရန် တို့ပါ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"စက်အသစ်တွဲချိတ်ရန်"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"အားလုံးကြည့်ရန်"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ဘလူးတုသ်သုံးရန်"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပိတ်ထားသည်"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"မိုက်ခရိုဖုန်းကို ပိတ်ထားသည်"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ဦးစားပေးမုဒ် ဖွင့်ထားသည်"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"အသုံးပြုသူရှိကြောင်း တွေ့ရသည်"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
<string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0accbec..db181ad 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansiktslås er utilgjengelig"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth er tilkoblet."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikon for Bluetooth-enheter"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klikk for å konfigurere enhetsdetaljer"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Koblet til <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ikke forstyrr"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ingen sammenkoblede enheter er tilgjengelige"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Trykk for å koble en enhet til eller fra"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Koble til en ny enhet"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Se alle"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bruk Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameraet og mikrofonen er blokkert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokkert"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteringsmodus er på"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Det er registrert at brukeren er til stede"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
<string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 4ca9af9..30c9722 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फेस अनलक उपलब्ध छैन"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ब्लुटुथ डिभाइस जनाउने आइकन"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"डिभाइसको विवरण कन्फिगर गर्न क्लिक गर्नुहोस्"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा कनेक्ट गरियो।"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"बाधा नपुऱ्याउनुहोस्"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लुटुथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"जोडी उपकरणहरू उपलब्ध छैन"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"कुनै डिभाइस कनेक्ट गर्न वा डिस्कनेक्ट गर्न ट्याप गर्नुहोस्"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"सबै डिभाइसहरू हेर्नुहोस्"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लुटुथ प्रयोग गर्नुहोस्"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"क्यामेरा र माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राथमिकता मोड अन छ"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"प्रयोगकर्ता उपस्थित भएको कुरा पत्ता लागेको छ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
<string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index f36c3c7..dc654a5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ontgrendelen via gezichtsherkenning niet beschikbaar"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-verbinding ingesteld."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icoon voor bluetooth-apparaat"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klik om de apparaatgegevens in te stellen"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterijpercentage onbekend."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Verbonden met <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Niet storen"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen gekoppelde apparaten beschikbaar"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tik om een apparaat te verbinden of de verbinding te verbreken"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Nieuw apparaat koppelen"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Alles bekijken"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth gebruiken"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera en microfoon geblokkeerd"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfoon geblokkeerd"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteitsmodus aan"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikersaanwezigheid is waargenomen"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
<string name="install_app" msgid="5066668100199613936">"App installeren"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 2552600..bc2cef0 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ଫେସ ଅନଲକ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ବ୍ଲୁଟୂଥ୍ ସଂଯୋଗ କରାଯାଇଛି।"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଆଇକନ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ଡିଭାଇସ ବିବରଣୀକୁ କନଫିଗର କରିବା ପାଇଁ କ୍ଲିକ କରନ୍ତୁ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ସହିତ ସଂଯୁକ୍ତ।"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୁଥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ପେୟାର୍ ହୋଇଥିବା କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ଏକ ଡିଭାଇସ କନେକ୍ଟ କିମ୍ବା ଡିସକନେକ୍ଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର କରନ୍ତୁ"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ବ୍ଲୁଟୁଥ ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"କେମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ପ୍ରାୟୋରିଟି ମୋଡ ଚାଲୁ ଅଛି"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ୟୁଜରଙ୍କ ଉପସ୍ଥିତି ଚିହ୍ନଟ କରାଯାଇଛି"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
<string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 5551bc9..66c3e46 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ਫ਼ੇਸ ਅਣਲਾਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ਬਲੂਟੁੱਥ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਤੀਕ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"ਡੀਵਾਈਸ ਦੇ ਵੇਰਵੇ ਦਾ ਸੰਰੂਪਣ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ਬੈਟਰੀ ਪ੍ਰਤੀਸ਼ਤ ਅਗਿਆਤ ਹੈ।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ।"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ਬਲੂਟੁੱਥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ਕੋਈ ਜੋੜਾਬੱਧ ਕੀਤੀਆਂ ਡੀਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ਡੀਵਾਈਸ ਨੂੰ ਕਨੈਕਟ ਜਾਂ ਡਿਸਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ਸਭ ਦੇਖੋ"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ਬਲੂਟੁੱਥ ਵਰਤੋ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ ਦਾ ਪਤਾ ਲਗਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
<string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 546bf41..589c2a3 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Rozpoznawanie twarzy niedostępne"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth połączony."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona urządzenia Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknij, aby skonfigurować szczegóły urządzenia"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Połączono z urządzeniem <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nie przeszkadzać"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Brak dostępnych sparowanych urządzeń"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Kliknij, aby podłączyć lub odłączyć urządzenie"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Sparuj nowe urządzenie"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Pokaż wszystkie"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Użyj Bluetootha"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tryb priorytetowy jest włączony"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Wykryto obecność użytkownika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
<string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index d3ac7fd..f9f247a 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O Desbloqueio facial não está disponível"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ícone de dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Clique para configurar os detalhes do dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toque para conectar ou desconectar um dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Parear novo dispositivo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Mostrar tudo"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo de prioridade ativado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c81b8b0..b445d08 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueio facial indisponível"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ligado."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ícone de dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Clique para configurar o detalhe do dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ligado a <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmara e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridade ativado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Quando deteta a presença do utilizador"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d3ac7fd..f9f247a 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O Desbloqueio facial não está disponível"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ícone de dispositivo Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Clique para configurar os detalhes do dispositivo"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toque para conectar ou desconectar um dispositivo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Parear novo dispositivo"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Mostrar tudo"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo de prioridade ativado"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1ca164f..563d8e1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Deblocarea facială nu este disponibilă"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Conectat prin Bluetooth."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Pictograma de dispozitiv Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Dă clic pentru a configura detaliile dispozitivului"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"S-a stabilit conexiunea la <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nu deranja"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Niciun dispozitiv conectat disponibil"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Atinge pentru a conecta sau deconecta un dispozitiv"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Asociază un nou dispozitiv"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Afișează tot"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Folosește Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera foto și microfonul sunt blocate"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfonul a fost blocat"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modul Cu prioritate este activat"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"S-a detectat prezența utilizatorului"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
<string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 476c1fa..e1ac364 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейсконтроль недоступен"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-соединение установлено."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Значок устройства Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Нажмите, чтобы изменить информацию об устройстве"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Уровень заряда батареи в процентах неизвестен."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Подключено к: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не беспокоить"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нет доступных сопряженных устройств"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Нажмите, чтобы подключить или отключить устройство"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Подключить устройство"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Все"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Использовать"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон заблокированы"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон заблокирован"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим \"Только важные\" включен"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Обнаружен пользователь"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
<string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index d130ebf..edcf415 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"මුහුණෙන් අගුළු ඇරීම නැත"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"බ්ලූටූත් සම්බන්ධිතයි."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"බ්ලූටූත් උපාංග නිරූපකය"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"උපාංග විස්තර වින්යාස කිරීමට ක්ලික් කරන්න"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"බැටරි ප්රතිශතය නොදනී."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> වෙත සම්බන්ධ විය."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"බාධා නොකරන්න"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"බ්ලූටූත්"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"යුගල කළ උපාංග නොතිබේ"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"උපාංගයක් සම්බන්ධ කිරීමට හෝ විසන්ධි කිරීමට තට්ටු කරන්න"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"නව උපාංගය යුගල කරන්න"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"සියල්ල බලන්න"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"බ්ලූටූත් භාවිතා කරන්න"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"කැමරාව සහ මයික්රොෆෝනය අවහිරයි"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"මයික්රොෆෝනය අවහිරයි"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ප්රමුඛතා මාදිලිය සක්රීයයි"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"පරිශීලක රූපාකාරය අනාවරණය වේ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
<string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index a00053a..d95bde1 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odomknutie tvárou nie je k dispozícii"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth pripojené."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona zariadenia s rozhraním Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknutím nakonfigurujte podrobnosti o zariadení"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percento batérie nie je známe."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Pripojené k zariadeniu <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režim bez vyrušení"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nie sú k dispozícii žiadne spárované zariadenia"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím pripojíte alebo odpojíte zariadenie"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Spárovať nové zariadenie"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Zobraziť všetko"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Použiť Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofón je blokovaný"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Režim priority je zapnutý"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Bola rozpoznaná prítomnosť používateľa"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
<string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 504eec7..cc6040f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odklepanje z obrazom ni na voljo."</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Povezava Bluetooth vzpostavljena."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona naprave Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliknite za konfiguriranje podrobnosti o napravi"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Neznan odstotek napolnjenosti baterije."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Vzpostavljena povezava: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne moti"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Na voljo ni nobene seznanjene naprave"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dotaknite se za vzpostavitev ali prekinitev povezave z napravo"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Seznanitev nove naprave"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Pokaži vse"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Uporabi Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparat in mikrofon sta blokirana."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran."</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prednostni način je vklopljen."</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Zaznana je prisotnost uporabnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
<string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti v zunanji zaslon?"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index d9c0c6f..e214f4a 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\"Shkyçja me fytyrë\" nuk ofrohet"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Pajisja është lidhur me \"bluetooth\"."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Ikona e pajisjes me Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Kliko për të konfiguruar detajet e pajisjes"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Është lidhur me <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mos shqetëso"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth-i"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nuk ofrohet për përdorim asnjë pajisje e çiftuar"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Trokit për të lidhur ose shkëputur një pajisje"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Çifto pajisje të re"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Shiko të gjitha"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Përdor Bluetooth-in"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dhe mikrofoni u bllokuan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni u bllokua"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modaliteti i përparësisë aktiv"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Është zbuluar prania e përdoruesit"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
<string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 16a1853..d251232 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Откључавање лицем није доступно"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth је прикључен."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Икона Bluetooth уређаја"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Кликните да бисте конфигурисали детаље о уређају"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Проценат напуњености батерије није познат."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Повезани сте са <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Повезани смо са уређајем <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не узнемиравај"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Није доступан ниједан упарени уређај"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Додирните да бисте повезали уређај или прекинули везу"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Упари нови уређај"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Прикажи све"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Користи Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон су блокирани"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон је блокиран"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетни режим је укључен"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Присуство корисника може да се открије"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 30c8a4a..b870a1d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansiktslås är otillgängligt"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ansluten."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Enhetsikon för Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Klicka för att konfigurera enhetsinformation"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ansluten till <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Stör ej"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Det finns inga kopplade enheter tillgängliga"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tryck för att ansluta eller koppla från en enhet"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Parkoppla en ny enhet"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Se alla"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Använd Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameran och mikrofonen är blockerade"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen är blockerad"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetsläge är aktiverat"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Användarnärvaro har upptäckts"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
<string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 77d1717..57bedbf 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Kipengele cha Kufungua kwa Uso hakipatikani"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth imeunganishwa."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Aikoni ya Kifaa chenye Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Bofya ili uweke mipangilio ya maelezo ya kifaa"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Imeunganishwa kwenye <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Usinisumbue"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Hakuna vifaa vilivyooanishwa vinavyopatikana"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Gusa ili uunganishe au utenganishe kifaa"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Oanisha kifaa kipya"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Angalia vyote"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Tumia Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Hali ya kipaumbele imewashwa"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Imetambua uwepo wa mtumiaji"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
<string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a505c3a..9342ce9 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"முகம் காட்டித் திறத்தல் அம்சம் கிடைக்கவில்லை"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"புளூடூத் இணைக்கப்பட்டது."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"புளூடூத் சாதன ஐகான்"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"சாதன விவரத்தை உள்ளமைக்க கிளிக் செய்யலாம்"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> உடன் இணைக்கப்பட்டுள்ளது."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"தொந்தரவு செய்ய வேண்டாம்"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"புளூடூத்"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"இணைக்கப்பட்ட சாதனங்கள் இல்லை"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"சாதனத்தை இணைக்க/துண்டிக்க தட்டவும்"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"அனைத்தையும் காட்டு"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"புளூடூத்தைப் பயன்படுத்துதல்"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"கேமராவும் மைக்ரோஃபோனும் தடுக்கப்பட்டுள்ளன"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"மைக்ரோஃபோன் தடுக்கப்பட்டுள்ளது"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"முன்னுரிமைப் பயன்முறை இயக்கத்தில் உள்ளது"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"பயனர் கண்டறியப்பட்டுள்ளார்"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
<string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 06296d2..e9f07af 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ఫేస్ అన్లాక్ అందుబాటులో లేదు"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"బ్లూటూత్ పరికర చిహ్నం"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"పరికర వివరాలను కాన్ఫిగర్ చేయడానికి క్లిక్ చేయండి"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"బ్యాటరీ శాతం తెలియదు."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"కెమెరా, మైక్రోఫోన్ బ్లాక్ చేయబడ్డాయి"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"మైక్రోఫోన్ బ్లాక్ చేయబడింది"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ప్రయారిటీ మోడ్ ఆన్లో ఉంది"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"యూజర్ ఉనికి గుర్తించబడింది"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string>
<string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"బాహ్య డిస్ప్లేను మిర్రర్ చేయాలా?"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ef597db..82d8118 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"การปลดล็อกด้วยใบหน้าไม่พร้อมใช้งาน"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"เชื่อมต่อบลูทูธแล้ว"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"ไอคอนอุปกรณ์บลูทูธ"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"คลิกเพื่อกำหนดค่ารายละเอียดอุปกรณ์"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ไม่ทราบเปอร์เซ็นต์แบตเตอรี่"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"เชื่อมต่อกับ <xliff:g id="BLUETOOTH">%s</xliff:g> แล้ว"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"เชื่อมต่อกับ <xliff:g id="CAST">%s</xliff:g>"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ห้ามรบกวน"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"บลูทูธ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ไม่มีอุปกรณ์ที่จับคู่ที่สามารถใช้ได้"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"แตะเพื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่ออุปกรณ์"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"จับคู่อุปกรณ์ใหม่"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"ดูทั้งหมด"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ใช้บลูทูธ"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ไมโครโฟนถูกบล็อกอยู่"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"โหมดลำดับความสำคัญเปิดอยู่"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ตรวจพบการแสดงข้อมูลของผู้ใช้"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
<string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c476cff..211a747 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Hindi available ang Pag-unlock Gamit ang Mukha"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Nakakonekta ang Bluetooth."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Icon ng Bluetooth device"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"I-click para i-configure ang detalye ng device"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Hindi alam ang porsyento ng baterya."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Nakakonekta sa <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -1181,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Naka-block ang camera at mikropono"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Naka-block ang mikropono"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Naka-on ang Priority mode"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Na-detect ang presensya ng user"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
<string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e347d4a..e0fac50 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Yüz Tanıma Kilidi kullanılamıyor"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth bağlandı."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth cihaz simgesi"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Cihaz ayrıntılarını yapılandırmak için tıklayın"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> bağlantısı kuruldu."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Rahatsız Etmeyin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Kullanılabilir eşlenmiş cihaz yok"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Cihaz bağlamak veya cihazın bağlantısını kesmek için dokunun"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Yeni cihaz eşleme"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Tümünü göster"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth\'u kullan"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ve mikrofon engellendi"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon engellendi"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Öncelik modu etkin"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kullanıcı varlığı algılandı"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
<string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f0d1e57..a2c4ef5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейс-контроль недоступний"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Значок пристрою з Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Натисніть, щоб змінити налаштування пристрою"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Під’єднано до пристрою <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбувати"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Немає спарених пристроїв"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Натисніть, щоб під’єднати або від’єднати пристрій"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Підключити новий пристрій"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Показати всі"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Увімкнути Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрофон заблоковано"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим пріоритету ввімкнено"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Виявлено присутність користувача"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
<string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index de1d827..364a84c 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"فیس اَنلاک غیر دستیاب ہے"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوٹوتھ مربوط ہے۔"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"بلوٹوتھ آلے کا آئیکن"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"آلہ کی تفصیل کو کنفیگر کرنے کے لیے کلک کریں"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> سے منسلک ہے۔"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ڈسٹرب نہ کریں"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوٹوتھ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"کوئی جوڑا بنائے ہوئے آلات دستیاب نہیں ہیں"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"کسی آلے کو منسلک یا غیر منسلک کرنے کے لیے تھپتھپائیں"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"نئے آلے کا جوڑا بنائیں"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"سبھی دیکھیں"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"استعمال کریں"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"کیمرا اور مائیکروفون مسدود ہے"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"مائیکروفون مسدود ہے"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ترجیحی موڈ آن ہے"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"صارف کی موجودگی کا پتہ چلا ہے"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
<string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index ec1cf32..3ff1808 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -250,8 +250,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Bezovta qilinmasin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ulangan qurilmalar topilmadi"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Qurilma ulash yoki uzish uchun tegining"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Yangi qurilmani ulash"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Hammasi"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth ishlatish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a457c35..92fefc6 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Không dùng được tính năng Mở khoá bằng khuôn mặt"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Đã kết nối bluetooth."</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Biểu tượng thiết bị Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Nhấp để định cấu hình thông tin thiết bị"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Đã kết nối với <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Không làm phiền"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Không có thiết bị nào được ghép nối"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Nhấn để kết nối/ngắt kết nối với một thiết bị"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Ghép nối thiết bị mới"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Xem tất cả"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bật Bluetooth"</string>
@@ -288,7 +286,7 @@
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Chỉnh màu"</string>
<string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Cỡ chữ"</string>
- <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Quản lý người dùng"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Quản lý ng.dùng"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Đóng"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Đã kết nối"</string>
@@ -1124,7 +1122,7 @@
<string name="clipboard_image_preview" msgid="2156475174343538128">"Bản xem trước hình ảnh"</string>
<string name="clipboard_edit" msgid="4500155216174011640">"sửa"</string>
<string name="add" msgid="81036585205287996">"Thêm"</string>
- <string name="manage_users" msgid="1823875311934643849">"Quản lý người dùng"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Quản lý ng.dùng"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Thông báo này không hỗ trợ thao tác kéo để chia đôi màn hình"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Không có Wi‑Fi"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Chế độ ưu tiên"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Chế độ ưu tiên đang bật"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Phát hiện thấy người dùng đang hiện diện"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
<string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Đồng bộ hoá hai chiều sang màn hình ngoài?"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9b385e0..712f1a9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"无法使用人脸解锁功能"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"蓝牙已连接。"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"蓝牙设备图标"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"点击以配置设备详情"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已连接到 <xliff:g id="CAST">%s</xliff:g>。"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"勿扰"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"蓝牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"没有可用的配对设备"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"点按即可连接设备或断开设备连接"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"与新设备配对"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"查看全部"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"使用蓝牙"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已禁用摄像头和麦克风"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已禁用麦克风"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"已开启优先模式"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"检测到用户存在"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
<string name="install_app" msgid="5066668100199613936">"安装应用"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index cd80e64..31abf82 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"無法使用面孔解鎖"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"藍牙裝置圖示"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"按一下即可設定裝置詳情"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已連接至 <xliff:g id="CAST">%s</xliff:g>。"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"請勿騷擾"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"輕按即可連結或解除連結裝置"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"配對新裝置"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"查看全部"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"使用藍牙"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖相機和麥克風"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已封鎖麥克風"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先模式已開啟"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者動態"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
<string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index db557ca..d112ad2 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"無法使用人臉解鎖功能"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"「藍牙裝置」圖示"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"按一下即可設定裝置詳細資料"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已連線至 <xliff:g id="CAST">%s</xliff:g>。"</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"零打擾"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"輕觸即可連結/取消連結裝置"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"配對新裝置"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"查看全部"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"使用藍牙"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖攝影機和麥克風"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已封鎖麥克風"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"優先模式已開啟"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
<string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 21a694f..d1bdc15 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -196,8 +196,7 @@
<string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ukuvula ngobuso akutholakali"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ixhunyiwe"</string>
<string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Isithonjana sedivayisi ye-Bluetooth"</string>
- <!-- no translation found for accessibility_bluetooth_device_settings_gear (3314916468105272540) -->
- <skip />
+ <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Chofoza ukuze ulungiselele imininingwane yedivayisi"</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ixhumeke ku-<xliff:g id="CAST">%s</xliff:g>."</string>
@@ -250,8 +249,7 @@
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ungaphazamisi"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"I-Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Awekho amadivayisi abhanqiwe atholakalayo"</string>
- <!-- no translation found for quick_settings_bluetooth_tile_subtitle (212752719010829550) -->
- <skip />
+ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Thepha ukuze uxhumae noma ungaxhumi idivaysi"</string>
<string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Bhangqa idivayisi entsha"</string>
<string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Buka konke"</string>
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Sebenzisa i-Bluetooth"</string>
@@ -1182,8 +1180,7 @@
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string>
<string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imodi ebalulekile ivuliwe"</string>
- <!-- no translation found for assistant_attention_content_description (4166330881435263596) -->
- <skip />
+ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Ubukhona bomsebenzisi butholakele"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
<string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1a37e2d..73ee50d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -736,6 +736,8 @@
<!-- Whether the communal service should be enabled -->
<bool name="config_communalServiceEnabled">false</bool>
+ <!-- Name of the database that stores info of widgets shown on glanceable hub -->
+ <string name="config_communalDatabase" translatable="false">communal_db</string>
<!-- Component names of allowed communal widgets -->
<string-array name="config_communalWidgetAllowlist" translatable="false" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 12bff4a..9a3c6d5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1048,6 +1048,11 @@
<!-- Indicator on keyguard to start the communal tutorial. [CHAR LIMIT=100] -->
<string name="communal_tutorial_indicator_text">Swipe left to start the communal tutorial</string>
+ <!-- Description for the button that opens the widget picker on click. [CHAR LIMIT=50] -->
+ <string name="button_to_open_widget_picker">Open the widget picker</string>
+ <!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] -->
+ <string name="button_to_remove_widget">Remove a widget</string>
+
<!-- Related to user switcher --><skip/>
<!-- Accessibility label for the button that opens the user switcher. -->
@@ -3261,4 +3266,9 @@
<string name="privacy_dialog_active_app_usage_2">In use by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
<!-- Label for recent app usage of a phone sensor with sub-attribution and proxy label in the privacy dialog [CHAR LIMIT=NONE] -->
<string name="privacy_dialog_recent_app_usage_2">Recently used by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
+
+ <!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] -->
+ <string name="keyboard_backlight_dialog_title">Keyboard backlight</string>
+ <!-- Content description for keyboard backlight brightness value [CHAR LIMIT=NONE] -->
+ <string name="keyboard_backlight_value">Level %1$d of %2$d</string>
</resources>
diff --git a/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/1.json b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/1.json
new file mode 100644
index 0000000..ffc4d91
--- /dev/null
+++ b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/1.json
@@ -0,0 +1,79 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "38f223811a414587ee1b6445ae19385d",
+ "entities": [
+ {
+ "tableName": "communal_widget_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `widget_id` INTEGER NOT NULL, `component_name` TEXT NOT NULL, `item_id` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "uid",
+ "columnName": "uid",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "widgetId",
+ "columnName": "widget_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "componentName",
+ "columnName": "component_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "itemId",
+ "columnName": "item_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "uid"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "communal_item_rank_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `rank` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "uid",
+ "columnName": "uid",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "rank",
+ "columnName": "rank",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "uid"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '38f223811a414587ee1b6445ae19385d')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index f9f2c63..92f66902 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -269,6 +269,7 @@
private ClassLoader getParentClassLoader(ClassLoader baseClassLoader) {
return new PluginManagerImpl.ClassLoaderFilter(
baseClassLoader,
+ "androidx.constraintlayout.widget",
"com.android.systemui.common",
"com.android.systemui.log",
"com.android.systemui.plugin");
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index b44bf39..fec96c6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -16,6 +16,8 @@
package com.android.systemui.shared.rotation;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+
import android.annotation.DimenRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -87,15 +89,15 @@
@DimenRes int roundedContentPadding, @DimenRes int taskbarLeftMargin,
@DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
@DimenRes int rippleMaxWidth, @BoolRes int floatingRotationBtnPositionLeftResource) {
- mWindowManager = context.getSystemService(WindowManager.class);
- mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(layout, null);
+ mContext = context.createWindowContext(context.getDisplay(), TYPE_NAVIGATION_BAR_PANEL,
+ null);
+ mWindowManager = mContext.getSystemService(WindowManager.class);
+ mKeyButtonContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(layout, null);
mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
mKeyButtonView.setVisibility(View.VISIBLE);
- mKeyButtonView.setContentDescription(context.getString(contentDescriptionResource));
+ mKeyButtonView.setContentDescription(mContext.getString(contentDescriptionResource));
mKeyButtonView.setRipple(rippleMaxWidth);
- mContext = context;
-
mContentDescriptionResource = contentDescriptionResource;
mMinMarginResource = minMargin;
mRoundedContentPaddingResource = roundedContentPadding;
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index e47d36f..6b390b1 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -27,9 +27,9 @@
import android.util.TypedValue
import android.view.View
import android.view.View.OnAttachStateChangeListener
+import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnGlobalLayoutListener
-import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -63,7 +63,6 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
import java.util.Locale
import java.util.TimeZone
@@ -150,25 +149,24 @@
var pastVisibility: Int? = null
override fun onViewAttachedToWindow(view: View) {
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
- if (view != null) {
- smallClockFrame = view.parent as FrameLayout
- smallClockFrame?.let {frame ->
- pastVisibility = frame.visibility
- onGlobalLayoutListener = OnGlobalLayoutListener {
- val currentVisibility = frame.visibility
- if (pastVisibility != currentVisibility) {
- pastVisibility = currentVisibility
- // when small clock visible,
- // recalculate bounds and sample
- if (currentVisibility == View.VISIBLE) {
- smallRegionSampler?.stopRegionSampler()
- smallRegionSampler?.startRegionSampler()
- }
+ // Match the asing for view.parent's layout classes.
+ smallClockFrame = view.parent as ViewGroup
+ smallClockFrame?.let { frame ->
+ pastVisibility = frame.visibility
+ onGlobalLayoutListener = OnGlobalLayoutListener {
+ val currentVisibility = frame.visibility
+ if (pastVisibility != currentVisibility) {
+ pastVisibility = currentVisibility
+ // when small clock is visible,
+ // recalculate bounds and sample
+ if (currentVisibility == View.VISIBLE) {
+ smallRegionSampler?.stopRegionSampler()
+ smallRegionSampler?.startRegionSampler()
}
}
- frame.viewTreeObserver
- .addOnGlobalLayoutListener(onGlobalLayoutListener)
}
+ frame.viewTreeObserver
+ .addOnGlobalLayoutListener(onGlobalLayoutListener)
}
}
@@ -197,7 +195,7 @@
var smallClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
@VisibleForTesting
var largeClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
- private var smallClockFrame: FrameLayout? = null
+ private var smallClockFrame: ViewGroup? = null
private var onGlobalLayoutListener: OnGlobalLayoutListener? = null
private var isDozing = false
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 9bddcd7..39a59c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -453,7 +453,7 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// TODO: b/305022530
- if (mClock.getConfig().getId().equals("DIGITAL_CLOCK_METRO")) {
+ if (mClock != null && mClock.getConfig().getId().equals("DIGITAL_CLOCK_METRO")) {
mClock.getEvents().onColorPaletteChanged(mContext.getResources());
}
@@ -461,7 +461,8 @@
post(() -> updateClockTargetRegions());
}
- if (mSmartspace != null && mSmartspaceTop != mSmartspace.getTop()) {
+ if (mSmartspace != null && mSmartspaceTop != mSmartspace.getTop()
+ && mDisplayedClockSize != null) {
mSmartspaceTop = mSmartspace.getTop();
post(() -> updateClockViews(mDisplayedClockSize == LARGE, mAnimateOnLayout));
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 54f1457..6b8009d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -44,8 +44,10 @@
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
@@ -122,12 +124,14 @@
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final InWindowLauncherUnlockAnimationManager mInWindowLauncherUnlockAnimationManager;
private boolean mShownOnSecondaryDisplay = false;
private boolean mOnlyClock = false;
private boolean mIsActiveDreamLockscreenHosted = false;
private final FeatureFlagsClassic mFeatureFlags;
private KeyguardInteractor mKeyguardInteractor;
+ private KeyguardClockInteractor mKeyguardClockInteractor;
private final DelayableExecutor mUiExecutor;
private boolean mCanShowDoubleLineClock = true;
private DisposableHandle mAodIconsBindHandle;
@@ -187,7 +191,9 @@
DozeParameters dozeParameters,
AlwaysOnDisplayNotificationIconViewStore aodIconViewStore,
KeyguardInteractor keyguardInteractor,
- FeatureFlagsClassic featureFlags) {
+ KeyguardClockInteractor keyguardClockInteractor,
+ FeatureFlagsClassic featureFlags,
+ InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -210,11 +216,15 @@
mView.setLogBuffer(mLogBuffer);
mFeatureFlags = featureFlags;
mKeyguardInteractor = keyguardInteractor;
+ mKeyguardClockInteractor = keyguardClockInteractor;
+ mInWindowLauncherUnlockAnimationManager = inWindowLauncherUnlockAnimationManager;
mClockChangedListener = new ClockRegistry.ClockChangeListener() {
@Override
public void onCurrentClockChanged() {
- setClock(mClockRegistry.createCurrentClock());
+ if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ setClock(mClockRegistry.createCurrentClock());
+ }
}
@Override
public void onAvailableClocksChanged() { }
@@ -344,9 +354,11 @@
addDateWeatherView();
}
}
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ setDateWeatherVisibility();
+ setWeatherVisibility();
+ }
- setDateWeatherVisibility();
- setWeatherVisibility();
}
int getNotificationIconAreaHeight() {
@@ -386,6 +398,9 @@
}
private void addDateWeatherView() {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return;
+ }
mDateWeatherView = (ViewGroup) mSmartspaceController.buildAndConnectDateView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
@@ -395,11 +410,13 @@
int endPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.below_clock_padding_end);
mDateWeatherView.setPaddingRelative(startPadding, 0, endPadding, 0);
-
addWeatherView();
}
private void addWeatherView() {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return;
+ }
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
WRAP_CONTENT, WRAP_CONTENT);
mWeatherView = mSmartspaceController.buildAndConnectWeatherView(mView);
@@ -410,6 +427,10 @@
}
private void addSmartspaceView() {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return;
+ }
+
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
@@ -421,6 +442,8 @@
mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView);
+ mInWindowLauncherUnlockAnimationManager.setLockscreenSmartspace(mSmartspaceView);
+
mView.setSmartspace(mSmartspaceView);
}
@@ -607,6 +630,9 @@
}
private void setClock(ClockController clock) {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return;
+ }
if (clock != null && mLogBuffer != null) {
mLogBuffer.log(TAG, LogLevel.INFO, "New Clock");
}
@@ -618,7 +644,11 @@
@Nullable
public ClockController getClock() {
- return mClockEventController.getClock();
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return mKeyguardClockInteractor.getClock();
+ } else {
+ return mClockEventController.getClock();
+ }
}
private int getCurrentLayoutDirection() {
@@ -626,13 +656,17 @@
}
private void updateDoubleLineClock() {
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return;
+ }
mCanShowDoubleLineClock = mSecureSettings.getIntForUser(
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, mView.getResources()
- .getInteger(com.android.internal.R.integer.config_doublelineClockDefault),
- UserHandle.USER_CURRENT) != 0;
+ .getInteger(com.android.internal.R.integer.config_doublelineClockDefault),
+ UserHandle.USER_CURRENT) != 0;
if (!mCanShowDoubleLineClock) {
- mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL, /* animate */ true));
+ mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL,
+ /* animate */ true));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/accessibility/TEST_MAPPING
index 055fad1..be26b43 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/TEST_MAPPING
@@ -5,6 +5,18 @@
"options": [
{
"include-filter": "com.android.systemui.accessibility"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.Postsubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
index 72935f7..d92b506 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IRadiiAnimationListener.java
@@ -18,4 +18,8 @@
interface IRadiiAnimationListener {
void onRadiiAnimationUpdate(float[] radii);
+
+ void onRadiiAnimationStart();
+
+ void onRadiiAnimationStop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 761551c..34d7cec 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -94,7 +94,19 @@
mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS);
mFadeOutAnimator.addUpdateListener(
(animation) -> menuView.setAlpha((float) animation.getAnimatedValue()));
- mRadiiAnimator = new RadiiAnimator(mMenuViewAppearance.getMenuRadii(), mMenuView::setRadii);
+ mRadiiAnimator = new RadiiAnimator(mMenuViewAppearance.getMenuRadii(),
+ new IRadiiAnimationListener() {
+ @Override
+ public void onRadiiAnimationUpdate(float[] radii) {
+ mMenuView.setRadii(radii);
+ }
+
+ @Override
+ public void onRadiiAnimationStart() {}
+
+ @Override
+ public void onRadiiAnimationStop() {}
+ });
}
void moveToPosition(PointF position) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
index acad36e..4aa0d89 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimator.java
@@ -55,15 +55,19 @@
@Override
public void onAnimationStart(@NonNull Animator animation) {
animationListener.onRadiiAnimationUpdate(evaluate(/* t = */ 0.0f));
+ animationListener.onRadiiAnimationStart();
}
@Override
- public void onAnimationEnd(@NonNull Animator animation) {}
+ public void onAnimationEnd(@NonNull Animator animation) {
+ animationListener.onRadiiAnimationStop();
+ }
@Override
public void onAnimationCancel(@NonNull Animator animation) {
animationListener.onRadiiAnimationUpdate(
evaluate(mAnimationDriver.getAnimatedFraction()));
+ animationListener.onRadiiAnimationStop();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 05db56f..57e252d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -80,6 +80,7 @@
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.data.repository.BiometricType;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -156,7 +157,7 @@
@Nullable private UdfpsOverlayParams mUdfpsOverlayParams;
@Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback;
@Nullable private SideFpsController mSideFpsController;
- @Nullable private UdfpsLogger mUdfpsLogger;
+ @NonNull private UdfpsLogger mUdfpsLogger;
@VisibleForTesting IBiometricSysuiReceiver mReceiver;
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
@@ -926,6 +927,23 @@
return mUdfpsRefreshRateRequestCallback;
}
+ /**
+ * Requests (or stops requesting) the max refresh rate. This can override user settings
+ * for the max refresh rate.
+ */
+ public void requestMaxRefreshRate(boolean request) throws RemoteException {
+ if (mUdfpsRefreshRateRequestCallback == null) {
+ mUdfpsLogger.log(
+ "PreAuthRefreshRate",
+ "skip request - refreshRateCallback is null",
+ LogLevel.DEBUG
+ );
+ return;
+ }
+ mUdfpsLogger.requestMaxRefreshRate(request);
+ mUdfpsRefreshRateRequestCallback.onAuthenticationPossible(mContext.getDisplayId(), request);
+ }
+
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt
new file mode 100644
index 0000000..cf699a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FpsUnlockTracker.kt
@@ -0,0 +1,208 @@
+/*
+ * 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.biometrics
+
+import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
+import android.hardware.biometrics.BiometricSourceType
+import android.hardware.biometrics.BiometricSourceType.FINGERPRINT
+import android.util.Log
+import com.android.app.tracing.TraceStateLogger
+import com.android.internal.util.LatencyTracker
+import com.android.internal.util.LatencyTracker.ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import javax.inject.Inject
+
+private const val TAG = "FpsUnlockTracker"
+private const val TRACE_COUNTER_NAME = "FpsUnlockStage"
+private const val TRACE_TAG_AOD = "AOD"
+private const val TRACE_TAG_KEYGUARD = "KEYGUARD"
+private const val DEBUG = true
+
+/** This is a class for monitoring unlock latency of fps and logging stages in perfetto. */
+@SysUISingleton
+class FpsUnlockTracker
+@Inject
+constructor(
+ private val statusBarStateController: StatusBarStateController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val keyguardUnlockAnimationController: KeyguardUnlockAnimationController,
+ private val latencyTracker: LatencyTracker,
+) {
+ private val fpsTraceStateLogger = TraceStateLogger(TRACE_COUNTER_NAME)
+ private var fpsAuthenticated: Boolean = false
+
+ private val keyguardUpdateMonitorCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAcquired(
+ biometricSourceType: BiometricSourceType?,
+ acquireInfo: Int
+ ) {
+ if (keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) {
+ onHalAuthenticationStage(acquireInfo)
+ }
+ }
+
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ if (biometricSourceType == FINGERPRINT) {
+ fpsAuthenticated = true
+ onExitKeyguard()
+ }
+ }
+
+ override fun onBiometricError(
+ msgId: Int,
+ errString: String?,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType == FINGERPRINT) {
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ }
+ }
+
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType != FINGERPRINT || !running) {
+ return
+ }
+ onWaitForAuthenticationStage()
+ }
+ }
+
+ private val keyguardUnlockAnimationListener =
+ object : KeyguardUnlockAnimationListener {
+ override fun onUnlockAnimationFinished() = onUnlockedStage()
+ }
+
+ /** Start tracking the fps unlock. */
+ fun startTracking() {
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
+ keyguardUnlockAnimationListener
+ )
+ }
+
+ /** Stop tracking the fps unlock. */
+ fun stopTracking() {
+ keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
+ keyguardUnlockAnimationController.removeKeyguardUnlockAnimationListener(
+ keyguardUnlockAnimationListener
+ )
+ }
+
+ /**
+ * The stage when the devices is locked and is possible to be unlocked via fps. However, in some
+ * situations, it might be unlocked only via bouncer.
+ */
+ fun onWaitForAuthenticationStage() {
+ val stage =
+ if (keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ FpsUnlockStage.WAIT_FOR_AUTHENTICATION.name
+ else FpsUnlockStage.WAIT_FOR_AUTHENTICATION.name + "(Not allowed)"
+ fpsTraceStateLogger.log(stage)
+ if (DEBUG) {
+ Log.d(TAG, "onWaitForAuthenticationStage: stage=$stage")
+ }
+ }
+
+ /**
+ * The stage dedicated to UDFPS, SFPS should not enter this stage. The only place where invokes
+ * this function is UdfpsController#onFingerDown.
+ */
+ fun onUiReadyStage() {
+ if (!keyguardUpdateMonitor.isUdfpsSupported || !keyguardUpdateMonitor.isUdfpsEnrolled) {
+ return
+ }
+ fpsTraceStateLogger.log(FpsUnlockStage.UI_READY.name)
+ startLatencyTracker()
+ if (DEBUG) {
+ Log.d(TAG, "onUiReadyStage: dozing=${statusBarStateController.isDozing}")
+ }
+ }
+
+ /** The stage when the HAL is authenticating the fingerprint. */
+ fun onHalAuthenticationStage(acquire: Int) {
+ fpsTraceStateLogger.log("${FpsUnlockStage.HAL_AUTHENTICATION.name}($acquire)")
+ // Start latency tracker here only for SFPS, UDFPS should start at onUiReadyStage.
+ if (
+ keyguardUpdateMonitor.isSfpsSupported &&
+ keyguardUpdateMonitor.isSfpsEnrolled &&
+ acquire == FINGERPRINT_ACQUIRED_START
+ ) {
+ startLatencyTracker()
+ }
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onHalAuthenticationStage: acquire=$acquire" +
+ ", sfpsSupported=${keyguardUpdateMonitor.isSfpsSupported}" +
+ ", sfpsEnrolled=${keyguardUpdateMonitor.isSfpsEnrolled}"
+ )
+ }
+ }
+
+ /** The stage when the authentication is succeeded and is going to exit keyguard. */
+ fun onExitKeyguard() {
+ fpsTraceStateLogger.log(FpsUnlockStage.EXIT_KEYGUARD.name)
+ if (DEBUG) {
+ Log.d(TAG, "onExitKeyguard: fpsAuthenticated=$fpsAuthenticated")
+ }
+ }
+
+ /**
+ * The stage when the unlock animation is finished which means the user can start interacting
+ * with the device.
+ */
+ fun onUnlockedStage() {
+ fpsTraceStateLogger.log(FpsUnlockStage.UNLOCKED.name)
+ if (fpsAuthenticated) {
+ // The device is unlocked successfully via fps, end the instrument.
+ latencyTracker.onActionEnd(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ } else {
+ // The device is unlocked but not via fps, maybe bouncer? Cancel the instrument.
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ }
+ if (DEBUG) {
+ Log.d(TAG, "onUnlockedStage: fpsAuthenticated=$fpsAuthenticated")
+ }
+ fpsAuthenticated = false
+ }
+
+ private fun startLatencyTracker() {
+ latencyTracker.onActionCancel(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME)
+ val tag = if (statusBarStateController.isDozing) TRACE_TAG_AOD else TRACE_TAG_KEYGUARD
+ latencyTracker.onActionStart(ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME, tag)
+ }
+}
+
+private enum class FpsUnlockStage {
+ WAIT_FOR_AUTHENTICATION,
+ UI_READY,
+ HAL_AUTHENTICATION,
+ EXIT_KEYGUARD,
+ UNLOCKED
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 10e7227..8f61dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -91,7 +91,8 @@
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
@Application private val scope: CoroutineScope,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ fpsUnlockTracker: FpsUnlockTracker
) : Dumpable {
private val requests: HashSet<SideFpsUiRequestSource> = HashSet()
@@ -167,6 +168,7 @@
}
init {
+ fpsUnlockTracker.startTracking()
fingerprintManager?.setSidefpsController(
object : ISidefpsController.Stub() {
override fun show(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3944ac2..4175937 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,6 +24,7 @@
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+import static com.android.internal.util.LatencyTracker.ACTION_UDFPS_ILLUMINATE;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
@@ -167,6 +168,7 @@
@NonNull private final InputManager mInputManager;
@NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
@NonNull private final SelectedUserInteractor mSelectedUserInteractor;
+ @NonNull private final FpsUnlockTracker mFpsUnlockTracker;
private final boolean mIgnoreRefreshRate;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
@@ -646,7 +648,8 @@
@NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
@NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate,
@NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider,
- @NonNull SelectedUserInteractor selectedUserInteractor) {
+ @NonNull SelectedUserInteractor selectedUserInteractor,
+ @NonNull FpsUnlockTracker fpsUnlockTracker) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -690,6 +693,8 @@
mInputManager = inputManager;
mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
mSelectedUserInteractor = selectedUserInteractor;
+ mFpsUnlockTracker = fpsUnlockTracker;
+ mFpsUnlockTracker.startTracking();
mTouchProcessor = singlePointerTouchProcessor;
mSessionTracker = sessionTracker;
@@ -974,7 +979,10 @@
return;
}
if (isOptical()) {
- mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ mLatencyTracker.onActionStart(ACTION_UDFPS_ILLUMINATE);
+ }
+ if (getBiometricSessionType() == SESSION_KEYGUARD) {
+ mFpsUnlockTracker.onUiReadyStage();
}
// Refresh screen timeout and boost process priority if possible.
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
index 2102a1f..65df8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
@@ -42,4 +42,8 @@
fun log(tag: String, @CompileTimeConstant msg: String, level: LogLevel) {
logBuffer.log(tag, level, msg)
}
+
+ fun requestMaxRefreshRate(request: Boolean) {
+ logBuffer.log("RefreshRate", LogLevel.DEBUG, { bool1 = request }, { "Request max: $bool1" })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index b8e2de4..c3421de 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.communal.dagger
+import com.android.systemui.communal.data.db.CommunalDatabaseModule
import com.android.systemui.communal.data.repository.CommunalRepositoryModule
import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule
import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule
@@ -27,6 +28,7 @@
CommunalRepositoryModule::class,
CommunalTutorialRepositoryModule::class,
CommunalWidgetRepositoryModule::class,
+ CommunalDatabaseModule::class,
]
)
class CommunalModule
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
new file mode 100644
index 0000000..595d320
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.data.db
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+
+@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 1)
+abstract class CommunalDatabase : RoomDatabase() {
+ abstract fun communalWidgetDao(): CommunalWidgetDao
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabaseModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabaseModule.kt
new file mode 100644
index 0000000..e766290
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabaseModule.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.communal.data.db
+
+import android.content.Context
+import androidx.room.Room
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface CommunalDatabaseModule {
+ companion object {
+ @SysUISingleton
+ @Provides
+ fun provideCommunalDatabase(
+ @Application context: Context,
+ defaultWidgetPopulation: DefaultWidgetPopulation,
+ ): CommunalDatabase {
+ return Room.databaseBuilder(
+ context,
+ CommunalDatabase::class.java,
+ context.resources.getString(R.string.config_communalDatabase)
+ )
+ .fallbackToDestructiveMigration()
+ .addCallback(defaultWidgetPopulation)
+ .build()
+ }
+
+ @SysUISingleton
+ @Provides
+ fun provideCommunalWidgetDao(database: CommunalDatabase): CommunalWidgetDao =
+ database.communalWidgetDao()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
new file mode 100644
index 0000000..0d5336a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.data.db
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "communal_widget_table")
+data class CommunalWidgetItem(
+ @PrimaryKey(autoGenerate = true) val uid: Long,
+ /** Id of an app widget */
+ @ColumnInfo(name = "widget_id") val widgetId: Int,
+ /** Component name of the app widget provider */
+ @ColumnInfo(name = "component_name") val componentName: String,
+ /** Reference the id of an item persisted in the glanceable hub */
+ @ColumnInfo(name = "item_id") val itemId: Long,
+)
+
+@Entity(tableName = "communal_item_rank_table")
+data class CommunalItemRank(
+ /** Unique id of an item persisted in the glanceable hub */
+ @PrimaryKey(autoGenerate = true) val uid: Long,
+ /** Order in which the item will be displayed */
+ @ColumnInfo(name = "rank", defaultValue = "0") val rank: Int,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
new file mode 100644
index 0000000..e50850d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.communal.data.db
+
+import android.content.ComponentName
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Query
+import androidx.room.RoomDatabase
+import androidx.room.Transaction
+import androidx.sqlite.db.SupportSQLiteDatabase
+import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule.Companion.DEFAULT_WIDGETS
+import com.android.systemui.communal.shared.CommunalWidgetHost
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import javax.inject.Inject
+import javax.inject.Named
+import javax.inject.Provider
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Callback that will be invoked when the Room database is created. Then the database will be
+ * populated with pre-configured default widgets to be rendered in the glanceable hub.
+ */
+class DefaultWidgetPopulation
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ private val communalWidgetHost: CommunalWidgetHost,
+ private val communalWidgetDaoProvider: Provider<CommunalWidgetDao>,
+ @Named(DEFAULT_WIDGETS) private val defaultWidgets: Array<String>,
+ @CommunalLog logBuffer: LogBuffer,
+) : RoomDatabase.Callback() {
+ companion object {
+ private const val TAG = "DefaultWidgetPopulation"
+ }
+ private val logger = Logger(logBuffer, TAG)
+
+ override fun onCreate(db: SupportSQLiteDatabase) {
+ super.onCreate(db)
+ applicationScope.launch {
+ addDefaultWidgets()
+ logger.i("Default widgets were populated in the database.")
+ }
+ }
+
+ // Read default widgets from config.xml and populate the database.
+ private suspend fun addDefaultWidgets() =
+ withContext(bgDispatcher) {
+ defaultWidgets.forEachIndexed { index, name ->
+ val provider = ComponentName.unflattenFromString(name)
+ provider?.let {
+ val id = communalWidgetHost.allocateIdAndBindWidget(provider)
+ id?.let {
+ communalWidgetDaoProvider
+ .get()
+ .addWidget(
+ widgetId = id,
+ provider = provider,
+ priority = defaultWidgets.size - index
+ )
+ }
+ }
+ }
+ }
+}
+
+@Dao
+interface CommunalWidgetDao {
+ @Query(
+ "SELECT * FROM communal_widget_table JOIN communal_item_rank_table " +
+ "ON communal_item_rank_table.uid = communal_widget_table.item_id"
+ )
+ fun getWidgets(): Flow<Map<CommunalItemRank, CommunalWidgetItem>>
+
+ @Query("SELECT * FROM communal_widget_table WHERE widget_id = :id")
+ fun getWidgetByIdNow(id: Int): CommunalWidgetItem
+
+ @Delete fun deleteWidgets(vararg widgets: CommunalWidgetItem)
+
+ @Query("DELETE FROM communal_item_rank_table WHERE uid = :itemId")
+ fun deleteItemRankById(itemId: Long)
+
+ @Query(
+ "INSERT INTO communal_widget_table(widget_id, component_name, item_id) " +
+ "VALUES(:widgetId, :componentName, :itemId)"
+ )
+ fun insertWidget(widgetId: Int, componentName: String, itemId: Long): Long
+
+ @Query("INSERT INTO communal_item_rank_table(rank) VALUES(:rank)")
+ fun insertItemRank(rank: Int): Long
+
+ @Transaction
+ fun addWidget(widgetId: Int, provider: ComponentName, priority: Int): Long {
+ return insertWidget(
+ widgetId = widgetId,
+ componentName = provider.flattenToString(),
+ insertItemRank(priority),
+ )
+ }
+
+ @Transaction
+ fun deleteWidgetById(widgetId: Int) {
+ val widget = getWidgetByIdNow(widgetId)
+ deleteItemRankById(widget.itemId)
+ deleteWidgets(widget)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetMetadata.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetMetadata.kt
deleted file mode 100644
index 1a214ba..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetMetadata.kt
+++ /dev/null
@@ -1,31 +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.communal.data.model
-
-import com.android.systemui.communal.shared.model.CommunalContentSize
-
-/** Metadata for the default widgets */
-data class CommunalWidgetMetadata(
- /* Widget provider component name */
- val componentName: String,
-
- /* Defines the order in which the widget will be rendered in the grid. */
- val priority: Int,
-
- /* Supported sizes */
- val sizes: List<CommunalContentSize>
-)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index 5c4ee35..b40570b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.communal.data.repository
import com.android.systemui.Flags.communalHub
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt
index 9d95b9e..1de3459 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepositoryModule.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.communal.data.repository
import dagger.Binds
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index 77025dc..6b27ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -28,47 +28,62 @@
import android.os.UserManager
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.communal.data.model.CommunalWidgetMetadata
+import com.android.systemui.communal.data.db.CommunalItemRank
+import com.android.systemui.communal.data.db.CommunalWidgetDao
+import com.android.systemui.communal.data.db.CommunalWidgetItem
+import com.android.systemui.communal.shared.CommunalWidgetHost
import com.android.systemui.communal.shared.model.CommunalAppWidgetInfo
-import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
-import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
/** Encapsulates the state of widgets for communal mode. */
interface CommunalWidgetRepository {
/** A flow of provider info for the stopwatch widget, or null if widget is unavailable. */
val stopwatchAppWidgetInfo: Flow<CommunalAppWidgetInfo?>
- /** Widgets that are allowed to render in the glanceable hub */
- val communalWidgetAllowlist: List<CommunalWidgetMetadata>
-
- /** A flow of information about all the communal widgets to show. */
+ /** A flow of information about active communal widgets stored in database. */
val communalWidgets: Flow<List<CommunalWidgetContentModel>>
+
+ /** Add a widget at the specified position in the app widget service and the database. */
+ fun addWidget(provider: ComponentName, priority: Int) {}
+
+ /** Delete a widget by id from app widget service and the database. */
+ fun deleteWidget(widgetId: Int) {}
}
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class CommunalWidgetRepositoryImpl
@Inject
constructor(
- @Application private val applicationContext: Context,
private val appWidgetManager: AppWidgetManager,
private val appWidgetHost: AppWidgetHost,
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
communalRepository: CommunalRepository,
+ private val communalWidgetHost: CommunalWidgetHost,
+ private val communalWidgetDao: CommunalWidgetDao,
private val packageManager: PackageManager,
private val userManager: UserManager,
private val userTracker: UserTracker,
@@ -79,18 +94,12 @@
const val TAG = "CommunalWidgetRepository"
const val WIDGET_LABEL = "Stopwatch"
}
- override val communalWidgetAllowlist: List<CommunalWidgetMetadata>
private val logger = Logger(logBuffer, TAG)
// Whether the [AppWidgetHost] is listening for updates.
private var isHostListening = false
- init {
- communalWidgetAllowlist =
- if (communalRepository.isCommunalEnabled) getWidgetAllowlist() else emptyList()
- }
-
// Widgets that should be rendered in communal mode.
private val widgets: HashMap<Int, CommunalAppWidgetInfo> = hashMapOf()
@@ -136,7 +145,6 @@
true
} else {
stopListening()
- clearWidgets()
false
}
}
@@ -157,57 +165,50 @@
return@map null
}
- return@map addWidget(providerInfo)
+ return@map addStopWatchWidget(providerInfo)
}
override val communalWidgets: Flow<List<CommunalWidgetContentModel>> =
- isHostActive.map { isHostActive ->
+ isHostActive.flatMapLatest { isHostActive ->
if (!isHostActive) {
- return@map emptyList()
+ return@flatMapLatest flowOf(emptyList())
}
-
- // The allowlist should be fetched from the local database with all the metadata tied to
- // a widget, including an appWidgetId if it has been bound. Before the database is set
- // up, we are going to use the app widget host as the source of truth for bound widgets,
- // and rebind each time on boot.
-
- // Remove all previously bound widgets.
- appWidgetHost.appWidgetIds.forEach { appWidgetHost.deleteAppWidgetId(it) }
-
- val inventory = mutableListOf<CommunalWidgetContentModel>()
-
- // Bind all widgets from the allowlist.
- communalWidgetAllowlist.forEach {
- val id = appWidgetHost.allocateAppWidgetId()
- appWidgetManager.bindAppWidgetId(
- id,
- ComponentName.unflattenFromString(it.componentName),
- )
-
- inventory.add(
- CommunalWidgetContentModel(
- appWidgetId = id,
- providerInfo = appWidgetManager.getAppWidgetInfo(id),
- priority = it.priority,
- )
- )
- }
-
- return@map inventory.toList()
+ communalWidgetDao.getWidgets().map { it.map(::mapToContentModel) }
}
- private fun getWidgetAllowlist(): List<CommunalWidgetMetadata> {
- val componentNames =
- applicationContext.resources.getStringArray(R.array.config_communalWidgetAllowlist)
- return componentNames.mapIndexed { index, name ->
- CommunalWidgetMetadata(
- componentName = name,
- priority = componentNames.size - index,
- sizes = listOf(CommunalContentSize.HALF),
- )
+ override fun addWidget(provider: ComponentName, priority: Int) {
+ applicationScope.launch(bgDispatcher) {
+ val id = communalWidgetHost.allocateIdAndBindWidget(provider)
+ id?.let {
+ communalWidgetDao.addWidget(
+ widgetId = it,
+ provider = provider,
+ priority = priority,
+ )
+ }
+ logger.i("Added widget ${provider.flattenToString()} at position $priority.")
}
}
+ override fun deleteWidget(widgetId: Int) {
+ applicationScope.launch(bgDispatcher) {
+ communalWidgetDao.deleteWidgetById(widgetId)
+ appWidgetHost.deleteAppWidgetId(widgetId)
+ logger.i("Deleted widget with id $widgetId.")
+ }
+ }
+
+ private fun mapToContentModel(
+ entry: Map.Entry<CommunalItemRank, CommunalWidgetItem>
+ ): CommunalWidgetContentModel {
+ val (_, widgetId) = entry.value
+ return CommunalWidgetContentModel(
+ appWidgetId = widgetId,
+ providerInfo = appWidgetManager.getAppWidgetInfo(widgetId),
+ priority = entry.key.rank,
+ )
+ }
+
private fun startListening() {
if (isHostListening) {
return
@@ -226,7 +227,8 @@
isHostListening = false
}
- private fun addWidget(providerInfo: AppWidgetProviderInfo): CommunalAppWidgetInfo {
+ // TODO(b/306471933): remove this prototype that shows a stopwatch in the communal blueprint
+ private fun addStopWatchWidget(providerInfo: AppWidgetProviderInfo): CommunalAppWidgetInfo {
val existing = widgets.values.firstOrNull { it.providerInfo == providerInfo }
if (existing != null) {
return existing
@@ -241,9 +243,4 @@
widgets[appWidgetId] = widget
return widget
}
-
- private fun clearWidgets() {
- widgets.keys.forEach { appWidgetId -> appWidgetHost.deleteAppWidgetId(appWidgetId) }
- widgets.clear()
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
index 3d1185b..5793f10 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryModule.kt
@@ -20,16 +20,24 @@
import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import android.content.Context
+import android.content.res.Resources
+import com.android.systemui.communal.shared.CommunalWidgetHost
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
import dagger.Provides
+import javax.inject.Named
@Module
interface CommunalWidgetRepositoryModule {
companion object {
private const val APP_WIDGET_HOST_ID = 116
+ const val DEFAULT_WIDGETS = "default_widgets"
@SysUISingleton
@Provides
@@ -42,6 +50,22 @@
fun provideAppWidgetHost(@Application context: Context): AppWidgetHost {
return AppWidgetHost(context, APP_WIDGET_HOST_ID)
}
+
+ @SysUISingleton
+ @Provides
+ fun provideCommunalWidgetHost(
+ appWidgetManager: AppWidgetManager,
+ appWidgetHost: AppWidgetHost,
+ @CommunalLog logBuffer: LogBuffer,
+ ): CommunalWidgetHost {
+ return CommunalWidgetHost(appWidgetManager, appWidgetHost, logBuffer)
+ }
+
+ @Provides
+ @Named(DEFAULT_WIDGETS)
+ fun provideDefaultWidgets(@Main resources: Resources): Array<String> {
+ return resources.getStringArray(R.array.config_communalWidgetAllowlist)
+ }
}
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index ccccbb6..2c683ee 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.communal.domain.interactor
+import android.content.ComponentName
import com.android.systemui.communal.data.repository.CommunalRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.shared.model.CommunalAppWidgetInfo
@@ -33,7 +34,7 @@
@Inject
constructor(
private val communalRepository: CommunalRepository,
- widgetRepository: CommunalWidgetRepository,
+ private val widgetRepository: CommunalWidgetRepository,
) {
/** Whether communal features are enabled. */
@@ -68,4 +69,11 @@
fun onSceneChanged(newScene: CommunalSceneKey) {
communalRepository.setDesiredScene(newScene)
}
+
+ /** Add a widget at the specified position. */
+ fun addWidget(componentName: ComponentName, priority: Int) =
+ widgetRepository.addWidget(componentName, priority)
+
+ /** Delete a widget by id. */
+ fun deleteWidget(id: Int) = widgetRepository.deleteWidget(id)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/CommunalWidgetHost.kt
new file mode 100644
index 0000000..086d729
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/CommunalWidgetHost.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared
+
+import android.appwidget.AppWidgetHost
+import android.appwidget.AppWidgetManager
+import android.content.ComponentName
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import javax.inject.Inject
+
+/**
+ * Widget host that interacts with AppWidget service and host to manage and provide info for widgets
+ * shown in the glanceable hub.
+ */
+class CommunalWidgetHost
+@Inject
+constructor(
+ private val appWidgetManager: AppWidgetManager,
+ private val appWidgetHost: AppWidgetHost,
+ @CommunalLog logBuffer: LogBuffer,
+) {
+ companion object {
+ private const val TAG = "CommunalWidgetHost"
+ }
+ private val logger = Logger(logBuffer, TAG)
+
+ /**
+ * Allocate an app widget id and binds the widget.
+ *
+ * @return widgetId if binding is successful; otherwise return null
+ */
+ fun allocateIdAndBindWidget(provider: ComponentName): Int? {
+ val id = appWidgetHost.allocateAppWidgetId()
+ if (bindWidget(id, provider)) {
+ logger.d("Successfully bound the widget $provider")
+ return id
+ }
+ appWidgetHost.deleteAppWidgetId(id)
+ logger.d("Failed to bind the widget $provider")
+ return null
+ }
+
+ private fun bindWidget(widgetId: Int, provider: ComponentName): Boolean =
+ appWidgetManager.bindAppWidgetIdIfAllowed(widgetId, provider)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index de9b563..197dece 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.communal.ui.viewmodel
import android.appwidget.AppWidgetHost
+import android.content.ComponentName
import android.content.Context
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor
@@ -61,4 +62,23 @@
fun onSceneChanged(scene: CommunalSceneKey) {
communalInteractor.onSceneChanged(scene)
}
+
+ /** Delete a widget by id. */
+ fun onDeleteWidget(id: Int) = communalInteractor.deleteWidget(id)
+
+ /** Open the widget picker */
+ fun onOpenWidgetPicker() {
+ // STOPSHIP(b/306500486): refactor this when integrating with the widget picker.
+ // Eventually clicking on this button will bring up the widget picker and inside
+ // the widget picker, addWidget will be called to add the user selected widget.
+ // For now, a stopwatch widget will be added to the end of the grid.
+ communalInteractor.addWidget(
+ componentName =
+ ComponentName(
+ "com.google.android.deskclock",
+ "com.android.alarmclock.StopwatchAppWidgetProvider"
+ ),
+ priority = 0
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f3353c7..58dcf069 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -109,7 +109,6 @@
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LetterboxModule;
import com.android.systemui.statusbar.phone.NotificationIconAreaControllerModule;
@@ -232,7 +231,6 @@
KeyguardBouncerComponent.class,
NavigationBarComponent.class,
NotificationRowComponent.class,
- NotificationShelfComponent.class,
WindowRootViewComponent.class,
})
public abstract class SystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index 87b0f01..d500d1c2 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -20,7 +20,6 @@
import android.view.View
import android.widget.TextView
import androidx.core.view.updatePadding
-import com.android.systemui.biometrics.Utils
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIBottomSheetDialog
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -36,6 +35,7 @@
context: Context,
private val onStartMirroringClickListener: View.OnClickListener,
private val onCancelMirroring: View.OnClickListener,
+ private val navbarBottomInsetsProvider: () -> Int,
configurationController: ConfigurationController? = null,
theme: Int = R.style.Theme_SystemUI_Dialog,
) : SystemUIBottomSheetDialog(context, configurationController, theme) {
@@ -67,12 +67,12 @@
private fun setupInsets() {
// This avoids overlap between dialog content and navigation bars.
requireViewById<View>(R.id.cd_bottom_sheet).apply {
- val navbarInsets = Utils.getNavbarInsets(context)
+ val navbarInsets = navbarBottomInsetsProvider()
val defaultDialogBottomInset =
context.resources.getDimensionPixelSize(R.dimen.dialog_bottom_padding)
// we only care about the bottom inset as in all other configuration where navigations
// are in other display sides there is no overlap with the dialog.
- updatePadding(bottom = max(navbarInsets.bottom, defaultDialogBottomInset))
+ updatePadding(bottom = max(navbarInsets, defaultDialogBottomInset))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 91f535d..19b4d22 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -17,6 +17,7 @@
import android.app.Dialog
import android.content.Context
+import com.android.systemui.biometrics.Utils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -74,7 +75,8 @@
scope.launch(bgDispatcher) { pendingDisplay.ignore() }
hideDialog()
},
- configurationController
+ navbarBottomInsetsProvider = { Utils.getNavbarInsets(context).bottom },
+ configurationController,
)
.apply { show() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 730a7a6..da3fd14 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -28,7 +28,6 @@
FlagDependenciesBase(featureFlags, handler) {
override fun defineDependencies() {
FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
- NotificationIconContainerRefactor.token dependsOn Classic.NOTIFICATION_SHELF_REFACTOR
// These two flags are effectively linked. We should migrate them to a single aconfig flag.
Classic.MIGRATE_NSSL dependsOn Classic.MIGRATE_KEYGUARD_STATUS_VIEW
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 49b8ee6..77384c4 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -68,9 +68,6 @@
"notification_drag_to_contents"
)
- // TODO(b/254512538): Tracking Bug
- val INSTANT_VOICE_REPLY = unreleasedFlag("instant_voice_reply")
-
/**
* This flag controls whether we register a listener for StatsD notification memory reports.
* For statsd to actually call the listener however, a server-side toggle needs to be
@@ -83,10 +80,6 @@
@JvmField
val NOTIFICATION_INLINE_REPLY_ANIMATION = releasedFlag("notification_inline_reply_animation")
- // TODO(b/277338665): Tracking Bug
- @JvmField
- val NOTIFICATION_SHELF_REFACTOR = releasedFlag("notification_shelf_refactor")
-
// TODO(b/288326013): Tracking Bug
@JvmField
val NOTIFICATION_ASYNC_HYBRID_VIEW_INFLATION =
@@ -398,7 +391,7 @@
@JvmField val SIGNAL_CALLBACK_DEPRECATION = releasedFlag("signal_callback_deprecation")
// TODO(b/301610137): Tracking bug
- @JvmField val NEW_NETWORK_SLICE_UI = unreleasedFlag("new_network_slice_ui", teamfood = true)
+ @JvmField val NEW_NETWORK_SLICE_UI = releasedFlag("new_network_slice_ui")
// TODO(b/308138154): Tracking bug
val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
@@ -794,11 +787,7 @@
/** Enable the share wifi button in Quick Settings internet dialog. */
@JvmField
- val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button", teamfood = true)
-
- /** Enable haptic slider component in the brightness slider */
- @JvmField
- val HAPTIC_BRIGHTNESS_SLIDER = unreleasedFlag("haptic_brightness_slider", teamfood = true)
+ val SHARE_WIFI_QS_BUTTON = releasedFlag("share_wifi_qs_button")
// TODO(b/287205379): Tracking bug
@JvmField
@@ -806,7 +795,7 @@
/** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
@JvmField
- val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog", teamfood = true)
+ val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog")
// TODO(b/300995746): Tracking Bug
/** A resource flag for whether the communal service is enabled. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index e16bb0b..1e9be09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -30,6 +30,7 @@
import android.view.ViewGroup.MarginLayoutParams
import android.view.Window
import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
@@ -78,23 +79,29 @@
private lateinit var stepProperties: StepViewProperties
@ColorInt
- var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
- @ColorInt
- var emptyRectangleColor =
- getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
- @ColorInt
- var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
- @ColorInt
- var defaultIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
- @ColorInt
- var defaultIconBackgroundColor =
+ private val filledRectangleColor =
getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
@ColorInt
- var dimmedIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
+ private val emptyRectangleColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
@ColorInt
- var dimmedIconBackgroundColor =
+ private val backgroundColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+ @ColorInt
+ private val defaultIconColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
+ @ColorInt
+ private val defaultIconBackgroundColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+ @ColorInt
+ private val dimmedIconColor =
+ getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
+ @ColorInt
+ private val dimmedIconBackgroundColor =
getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceDim)
+ private val levelContentDescription = context.getString(R.string.keyboard_backlight_value)
+
init {
currentLevel = initialCurrentLevel
maxLevel = initialMaxLevel
@@ -103,6 +110,8 @@
override fun onCreate(savedInstanceState: Bundle?) {
setUpWindowProperties(this)
setWindowPosition()
+ // title is used for a11y announcement
+ window?.setTitle(context.getString(R.string.keyboard_backlight_dialog_title))
updateResources()
rootView = buildRootView()
setContentView(rootView)
@@ -159,6 +168,12 @@
currentLevel = current
updateIconTile()
updateStepColors()
+ updateAccessibilityInfo()
+ }
+
+ private fun updateAccessibilityInfo() {
+ rootView.contentDescription = String.format(levelContentDescription, currentLevel, maxLevel)
+ rootView.sendAccessibilityEvent(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
}
private fun updateIconTile() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt
new file mode 100644
index 0000000..d23899b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepository.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/**
+ * State related to System UI's handling of the in-window Launcher unlock animations. This includes
+ * the staggered icon entry animation that plays during unlock, as well as the smartspace shared
+ * element animation, if supported.
+ *
+ * While the animations themselves occur fully in the Launcher window, System UI is responsible for
+ * preparing/starting the animations, as well as synchronizing the smartspace state so that the two
+ * smartspaces appear visually identical for the shared element animation.
+ */
+@SysUISingleton
+class InWindowLauncherUnlockAnimationRepository @Inject constructor() {
+
+ /**
+ * Whether we have called [ILauncherUnlockAnimationController.playUnlockAnimation] during this
+ * unlock sequence. This value is set back to false once
+ * [InWindowLauncherUnlockAnimationInteractor.shouldStartInWindowAnimation] reverts to false,
+ * which happens when we're no longer in transition to GONE or if the remote animation ends or
+ * is cancelled.
+ */
+ val startedUnlockAnimation = MutableStateFlow(false)
+
+ /**
+ * The unlock amount we've explicitly passed to
+ * [ILauncherUnlockAnimationController.setUnlockAmount]. This is used whenever System UI is
+ * directly controlling the amount of the unlock animation, such as during a manual swipe to
+ * unlock gesture.
+ *
+ * This value is *not* updated if we called
+ * [ILauncherUnlockAnimationController.playUnlockAnimation] to ask Launcher to animate all the
+ * way unlocked, since that animator is running in the Launcher window.
+ */
+ val manualUnlockAmount: MutableStateFlow<Float?> = MutableStateFlow(null)
+
+ /**
+ * The class name of the Launcher activity that provided us with a
+ * [ILauncherUnlockAnimationController], if applicable. We can use this to check if that
+ * launcher is underneath the lockscreen before playing in-window animations.
+ *
+ * If null, we have not been provided with a launcher unlock animation controller.
+ */
+ val launcherActivityClass: MutableStateFlow<String?> = MutableStateFlow(null)
+
+ /**
+ * Information about the Launcher's smartspace, which is passed to us via
+ * [ILauncherUnlockAnimationController].
+ */
+ val launcherSmartspaceState: MutableStateFlow<SmartspaceState?> = MutableStateFlow(null)
+
+ fun setStartedUnlockAnimation(started: Boolean) {
+ startedUnlockAnimation.value = started
+ }
+
+ fun setManualUnlockAmount(amount: Float?) {
+ manualUnlockAmount.value = amount
+ }
+
+ fun setLauncherActivityClass(className: String) {
+ launcherActivityClass.value = className
+ }
+
+ fun setLauncherSmartspaceState(state: SmartspaceState?) {
+ launcherSmartspaceState.value = state
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 16ad29a..d1c6218 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -18,6 +18,8 @@
import android.os.UserHandle
import android.provider.Settings
+import androidx.annotation.VisibleForTesting
+import com.android.keyguard.KeyguardClockSwitch.SMALL
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.shared.model.SettingsClockSize
@@ -71,7 +73,10 @@
}
.mapNotNull { it }
- private suspend fun getClockSize(): SettingsClockSize {
+ val currentClock = currentClockId.map { clockRegistry.createCurrentClock() }
+
+ @VisibleForTesting
+ suspend fun getClockSize(): SettingsClockSize {
return withContext(backgroundDispatcher) {
if (
secureSettings.getIntForUser(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 4d26466..6ff446e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -18,6 +18,8 @@
import android.graphics.Point
import android.hardware.biometrics.BiometricSourceType
+import com.android.keyguard.KeyguardClockSwitch.ClockSize
+import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.biometrics.AuthController
@@ -190,6 +192,12 @@
/** Observable updated when keyguardDone should be called either now or soon. */
val keyguardDone: Flow<KeyguardDone>
+ /** Receive SMALL or LARGE clock should be displayed on keyguard. */
+ val clockSize: Flow<Int>
+
+ /** Receive whether clock should be centered on lockscreen. */
+ val clockShouldBeCentered: Flow<Boolean>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -238,6 +246,10 @@
fun setDismissAction(dismissAction: DismissAction)
suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone)
+
+ fun setClockSize(@ClockSize size: Int)
+
+ fun setClockShouldBeCentered(shouldBeCentered: Boolean)
}
/** Encapsulates application state for the keyguard. */
@@ -281,6 +293,12 @@
private val _clockPosition = MutableStateFlow(Position(0, 0))
override val clockPosition = _clockPosition.asStateFlow()
+ private val _clockSize = MutableStateFlow(LARGE)
+ override val clockSize: Flow<Int> = _clockSize.asStateFlow()
+
+ private val _clockShouldBeCentered = MutableStateFlow(true)
+ override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered.asStateFlow()
+
override val isKeyguardShowing: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
@@ -663,6 +681,14 @@
_isActiveDreamLockscreenHosted.value = isLockscreenHosted
}
+ override fun setClockSize(@ClockSize size: Int) {
+ _clockSize.value = size
+ }
+
+ override fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
+ _clockShouldBeCentered.value = shouldBeCentered
+ }
+
private fun statusBarStateIntToObject(value: Int): StatusBarState {
return when (value) {
0 -> StatusBarState.SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
index 014b7fa..6121b633 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepository.kt
@@ -31,8 +31,14 @@
/** Whether we're running animations on the surface. */
val isAnimatingSurface: Flow<Boolean>
+ /** Whether we have a RemoteAnimationTarget to run animations on the surface. */
+ val isSurfaceRemoteAnimationTargetAvailable: Flow<Boolean>
+
/** Set whether we're running animations on the surface. */
fun setAnimatingSurface(animating: Boolean)
+
+ /** Set whether we have a RemoteAnimationTarget with which to run animations on the surface. */
+ fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean)
}
@SysUISingleton
@@ -40,7 +46,15 @@
private val _isAnimatingSurface = MutableStateFlow(false)
override val isAnimatingSurface = _isAnimatingSurface.asStateFlow()
+ private val _isSurfaceRemoteAnimationTargetAvailable = MutableStateFlow(false)
+ override val isSurfaceRemoteAnimationTargetAvailable =
+ _isSurfaceRemoteAnimationTargetAvailable.asStateFlow()
+
override fun setAnimatingSurface(animating: Boolean) {
_isAnimatingSurface.value = animating
}
+
+ override fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ _isSurfaceRemoteAnimationTargetAvailable.value = available
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index c4962a1..ea40ba0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -35,6 +35,7 @@
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -56,6 +57,7 @@
private val flags: FeatureFlags,
private val shadeRepository: ShadeRepository,
private val powerInteractor: PowerInteractor,
+ inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
) :
TransitionInteractor(
fromState = KeyguardState.LOCKSCREEN,
@@ -104,12 +106,21 @@
val surfaceBehindModel: Flow<KeyguardSurfaceBehindModel?> =
combine(
transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.transitionStepsFromState(KeyguardState.LOCKSCREEN)
- ) { startedStep, fromLockscreenStep ->
+ transitionInteractor.transitionStepsFromState(KeyguardState.LOCKSCREEN),
+ inWindowLauncherUnlockAnimationInteractor
+ .get()
+ .transitioningToGoneWithInWindowAnimation,
+ ) { startedStep, fromLockscreenStep, transitioningToGoneWithInWindowAnimation ->
if (startedStep.to != KeyguardState.GONE) {
// Only LOCKSCREEN -> GONE has specific surface params (for the unlock
// animation).
return@combine null
+ } else if (transitioningToGoneWithInWindowAnimation) {
+ // If we're prepared for the in-window unlock, we're going to play an animation
+ // in the window. Make it fully visible.
+ KeyguardSurfaceBehindModel(
+ alpha = 1f,
+ )
} else if (fromLockscreenStep.value > 0.5f) {
// Start the animation once we're 50% transitioned to GONE.
KeyguardSurfaceBehindModel(
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
new file mode 100644
index 0000000..e7d74a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractor.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+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.shared.system.ActivityManagerWrapper
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+@SysUISingleton
+class InWindowLauncherUnlockAnimationInteractor
+@Inject
+constructor(
+ private val repository: InWindowLauncherUnlockAnimationRepository,
+ @Application scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ surfaceBehindRepository: dagger.Lazy<KeyguardSurfaceBehindRepository>,
+ private val activityManager: ActivityManagerWrapper,
+) {
+ val startedUnlockAnimation = repository.startedUnlockAnimation.asStateFlow()
+
+ /**
+ * Whether we've STARTED but not FINISHED a transition to GONE, and the preconditions are met to
+ * play the in-window unlock animation.
+ */
+ val transitioningToGoneWithInWindowAnimation: StateFlow<Boolean> =
+ transitionInteractor
+ .isInTransitionToState(KeyguardState.GONE)
+ .sample(repository.launcherActivityClass, ::Pair)
+ .map { (isTransitioningToGone, launcherActivityClass) ->
+ isTransitioningToGone && isActivityClassUnderneath(launcherActivityClass)
+ }
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ /**
+ * Whether we should start the in-window unlock animation.
+ *
+ * This emits true once the Launcher surface becomes available while we're
+ * [transitioningToGoneWithInWindowAnimation].
+ */
+ val shouldStartInWindowAnimation: StateFlow<Boolean> =
+ combine(
+ transitioningToGoneWithInWindowAnimation,
+ surfaceBehindRepository.get().isSurfaceRemoteAnimationTargetAvailable,
+ ) { transitioningWithInWindowAnimation, isSurfaceAvailable ->
+ transitioningWithInWindowAnimation && isSurfaceAvailable
+ }
+ .stateIn(scope, SharingStarted.Eagerly, false)
+
+ /** Sets whether we've started */
+ fun setStartedUnlockAnimation(started: Boolean) {
+ repository.setStartedUnlockAnimation(started)
+ }
+
+ fun setManualUnlockAmount(amount: Float) {
+ repository.setManualUnlockAmount(amount)
+ }
+
+ fun setLauncherActivityClass(className: String) {
+ repository.setLauncherActivityClass(className)
+ }
+
+ fun setLauncherSmartspaceState(state: SmartspaceState?) {
+ repository.setLauncherSmartspaceState(state)
+ }
+
+ /**
+ * Whether an activity with the given [activityClass] name is currently underneath the
+ * lockscreen (it's at the top of the activity task stack).
+ */
+ private fun isActivityClassUnderneath(activityClass: String?): Boolean {
+ return activityClass?.let {
+ activityManager.runningTask?.topActivity?.className?.equals(it)
+ }
+ ?: false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index dad5831..2f103f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -17,21 +17,35 @@
package com.android.systemui.keyguard.domain.interactor
+import com.android.keyguard.ClockEventController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockId
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+private val TAG = KeyguardClockInteractor::class.simpleName
+/** Manages keyguard clock for the lockscreen root view. */
/** Encapsulates business-logic related to the keyguard clock. */
@SysUISingleton
class KeyguardClockInteractor
@Inject
constructor(
- repository: KeyguardClockRepository,
+ val eventController: ClockEventController,
+ private val keyguardClockRepository: KeyguardClockRepository,
) {
- val selectedClockSize: Flow<SettingsClockSize> = repository.selectedClockSize
- val currentClockId: Flow<ClockId> = repository.currentClockId
+ val selectedClockSize: Flow<SettingsClockSize> = keyguardClockRepository.selectedClockSize
+
+ val currentClockId: Flow<ClockId> = keyguardClockRepository.currentClockId
+
+ val currentClock: Flow<ClockController> = keyguardClockRepository.currentClock
+
+ var clock: ClockController?
+ get() = eventController.clock
+ set(value) {
+ eventController.clock = value
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index eaec0d4..e256b49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -23,6 +23,7 @@
import android.graphics.Point
import android.util.MathUtils
import com.android.app.animation.Interpolators
+import com.android.keyguard.KeyguardClockSwitch.ClockSize
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -241,6 +242,10 @@
}
}
+ val clockSize: Flow<Int> = repository.clockSize.distinctUntilChanged()
+
+ val clockShouldBeCentered: Flow<Boolean> = repository.clockShouldBeCentered
+
/** Whether to animate the next doze mode transition. */
val animateDozingTransitions: Flow<Boolean> by lazy {
if (sceneContainerFlags.isEnabled()) {
@@ -315,6 +320,14 @@
repository.setAnimateDozingTransitions(animate)
}
+ fun setClockSize(@ClockSize size: Int) {
+ repository.setClockSize(size)
+ }
+
+ fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
+ repository.setClockShouldBeCentered(shouldBeCentered)
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index 55b420b0..82c28ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -60,7 +60,6 @@
return collapseShadeLockedOrShowPrimaryBouncer()
}
}
-
when (event.keyCode) {
KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent()
}
@@ -98,7 +97,8 @@
(statusBarStateController.state != StatusBarState.SHADE) &&
statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
if (shouldUnlockOnMenuPressed) {
- return collapseShadeLockedOrShowPrimaryBouncer()
+ shadeController.animateCollapseShadeForced()
+ return true
}
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index bf04f8f..efbe261 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -20,13 +20,13 @@
import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
+import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import javax.inject.Inject
@SysUISingleton
class KeyguardSurfaceBehindInteractor
@@ -40,19 +40,18 @@
@OptIn(ExperimentalCoroutinesApi::class)
val viewParams: Flow<KeyguardSurfaceBehindModel> =
- transitionInteractor.isInTransitionToAnyState
- .flatMapLatest { isInTransition ->
- if (!isInTransition) {
- defaultParams
- } else {
- combine(
- transitionSpecificViewParams,
- defaultParams,
- ) { transitionParams, defaultParams ->
- transitionParams ?: defaultParams
- }
+ transitionInteractor.isInTransitionToAnyState.flatMapLatest { isInTransition ->
+ if (!isInTransition) {
+ defaultParams
+ } else {
+ combine(
+ transitionSpecificViewParams,
+ defaultParams,
+ ) { transitionParams, defaultParams ->
+ transitionParams ?: defaultParams
}
}
+ }
val isAnimatingSurface = repository.isAnimatingSurface
@@ -86,4 +85,8 @@
fun setAnimatingSurface(animating: Boolean) {
repository.setAnimatingSurface(animating)
}
+
+ fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ repository.setSurfaceRemoteAnimationTargetAvailable(available)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt
new file mode 100644
index 0000000..56a6e9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherAnimationViewBinder.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
+import com.android.systemui.keyguard.ui.viewmodel.InWindowLauncherAnimationViewModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Binds the [InWindowLauncherUnlockAnimationManager] "view", which manages the lifecycle and state
+ * of the in-window Launcher animation.
+ */
+object InWindowLauncherAnimationViewBinder {
+
+ @JvmStatic
+ fun bind(
+ viewModel: InWindowLauncherAnimationViewModel,
+ inWindowLauncherUnlockAnimationManager: InWindowLauncherUnlockAnimationManager,
+ scope: CoroutineScope
+ ) {
+ scope.launch {
+ viewModel.shouldPrepareForInWindowAnimation.collect { shouldPrepare ->
+ if (shouldPrepare) {
+ inWindowLauncherUnlockAnimationManager.prepareForUnlock()
+ } else {
+ // If we no longer meet the conditions to prepare for unlock, we'll need to
+ // manually set Launcher unlocked if we didn't start the unlock animation, or it
+ // will remain "prepared" (blank) forever.
+ inWindowLauncherUnlockAnimationManager.ensureUnlockedOrAnimatingUnlocked()
+ }
+ }
+ }
+
+ scope.launch {
+ viewModel.shouldStartInWindowAnimation.collect { shouldStart ->
+ if (shouldStart) {
+ inWindowLauncherUnlockAnimationManager.playUnlockAnimation(unlocked = true)
+ } else {
+ // Once the conditions to start the animation are no longer met, clear whether
+ // we started the animation, since we'll need to start it again if the
+ // conditions become true again.
+ inWindowLauncherUnlockAnimationManager.clearStartedUnlockAnimation()
+ }
+ }
+ }
+ }
+}
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
new file mode 100644
index 0000000..c688cfff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import android.transition.TransitionManager
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.ClockController
+import com.android.systemui.res.R
+import kotlinx.coroutines.launch
+
+private val TAG = KeyguardClockViewBinder::class.simpleName
+
+object KeyguardClockViewBinder {
+ @JvmStatic
+ fun bind(
+ clockSection: ClockSection,
+ keyguardRootView: ConstraintLayout,
+ viewModel: KeyguardClockViewModel,
+ keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
+ keyguardClockInteractor: KeyguardClockInteractor,
+ featureFlags: FeatureFlagsClassic,
+ ) {
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ keyguardClockInteractor.eventController.registerListeners(keyguardRootView)
+ }
+ }
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch
+ viewModel.currentClock.collect { currentClock ->
+ viewModel.clock?.let { clock -> cleanupClockViews(clock, keyguardRootView) }
+ viewModel.clock = currentClock
+ addClockViews(currentClock, keyguardRootView)
+ keyguardBlueprintInteractor.refreshBlueprint()
+ }
+ }
+ // TODO: Weather clock dozing animation
+ // will trigger both shouldBeCentered and clockSize change
+ // we should avoid this
+ launch {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch
+ viewModel.clockSize.collect {
+ applyConstraints(clockSection, keyguardRootView, true)
+ }
+ }
+ launch {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch
+ viewModel.clockShouldBeCentered.collect { shouldBeCentered ->
+ clockSection.setClockShouldBeCentered(
+ viewModel.useLargeClock && shouldBeCentered
+ )
+ applyConstraints(clockSection, keyguardRootView, true)
+ }
+ }
+ }
+ }
+ }
+
+ fun applyConstraints(
+ clockSection: ClockSection,
+ rootView: ConstraintLayout,
+ animated: Boolean
+ ) {
+ val constraintSet = ConstraintSet().apply { clone(rootView) }
+ clockSection.applyConstraints(constraintSet)
+ if (animated) {
+ TransitionManager.beginDelayedTransition(rootView)
+ }
+
+ constraintSet.applyTo(rootView)
+ }
+
+ private fun cleanupClockViews(clock: ClockController, rootView: ConstraintLayout) {
+ clock.smallClock.layout.views.forEach { rootView.removeView(it) }
+ clock.largeClock.layout.views.forEach { rootView.removeView(it) }
+ }
+
+ private fun addClockViews(clock: ClockController, rootView: ConstraintLayout) {
+ clock.smallClock.layout.views[0].id = R.id.lockscreen_clock_view
+ if (clock.largeClock.layout.views.size == 1) {
+ clock.largeClock.layout.views[0].id = R.id.lockscreen_clock_view_large
+ }
+ // small clock should either be a single view or container with id `lockscreen_clock_view`
+ clock.smallClock.layout.views.forEach { rootView.addView(it) }
+ clock.largeClock.layout.views.forEach { rootView.addView(it) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index ad48957..378656c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -224,16 +224,10 @@
deviceEntryHapticsInteractor.playSuccessHaptic
.filter { it }
.collect {
- if (
- featureFlags.isEnabled(Flags.ONE_WAY_HAPTICS_API_MIGRATION)
- ) {
- vibratorHelper.performHapticFeedback(
- view,
- HapticFeedbackConstants.CONFIRM,
- )
- } else {
- vibratorHelper.vibrateAuthSuccess("device-entry::success")
- }
+ vibratorHelper.performHapticFeedback(
+ view,
+ HapticFeedbackConstants.CONFIRM,
+ )
deviceEntryHapticsInteractor.handleSuccessHaptic()
}
}
@@ -242,16 +236,10 @@
deviceEntryHapticsInteractor.playErrorHaptic
.filter { it }
.collect {
- if (
- featureFlags.isEnabled(Flags.ONE_WAY_HAPTICS_API_MIGRATION)
- ) {
- vibratorHelper.performHapticFeedback(
- view,
- HapticFeedbackConstants.REJECT,
- )
- } else {
- vibratorHelper.vibrateAuthSuccess("device-entry::error")
- }
+ vibratorHelper.performHapticFeedback(
+ view,
+ HapticFeedbackConstants.REJECT,
+ )
deviceEntryHapticsInteractor.handleErrorHaptic()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
new file mode 100644
index 0000000..41a2e50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -0,0 +1,28 @@
+package com.android.systemui.keyguard.ui.binder
+
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+
+object KeyguardSmartspaceViewBinder {
+ @JvmStatic
+ fun bind(
+ smartspaceSection: SmartspaceSection,
+ keyguardRootView: ConstraintLayout,
+ clockViewModel: KeyguardClockViewModel,
+ ) {
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ clockViewModel.hasCustomWeatherDataDisplay.collect {
+ val constraintSet = ConstraintSet().apply { clone(keyguardRootView) }
+ smartspaceSection.applyConstraints(constraintSet)
+ constraintSet.applyTo(keyguardRootView)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
index c8dab32..8587022 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplier.kt
@@ -51,6 +51,11 @@
private val interactor: KeyguardSurfaceBehindInteractor,
) {
private var surfaceBehind: RemoteAnimationTarget? = null
+ set(value) {
+ field = value
+ interactor.setSurfaceRemoteAnimationTargetAvailable(value != null)
+ }
+
private val surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
get() = SyncRtSurfaceTransactionApplier(keyguardViewController.viewRootImpl.view)
@@ -66,7 +71,7 @@
dampingRatio = 1f
}
addUpdateListener { _, _, _ -> applyToSurfaceBehind() }
- addEndListener { _, _, _, _ ->
+ addEndListener { _, _, _, _ ->
try {
updateIsAnimatingSurface()
} catch (e: NullPointerException) {
@@ -112,6 +117,7 @@
fun applyParamsToSurface(surface: RemoteAnimationTarget) {
this.surfaceBehind = surface
startOrUpdateAnimators()
+ applyToSurfaceBehind()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
new file mode 100644
index 0000000..eb005f2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt
@@ -0,0 +1,199 @@
+/*
+ *
+ * * Copyright (C) 2023 The Android Open Source Project
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ *
+ */
+package com.android.systemui.keyguard.ui.view
+
+import android.graphics.Rect
+import android.util.Log
+import android.view.View
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import com.android.systemui.keyguard.ui.binder.InWindowLauncherAnimationViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.InWindowLauncherAnimationViewModel
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+
+private val TAG = InWindowLauncherUnlockAnimationManager::class.simpleName
+private const val UNLOCK_ANIMATION_DURATION = 633L
+private const val UNLOCK_START_DELAY = 100L
+
+/**
+ * Handles interactions between System UI and Launcher related to the in-window unlock animation.
+ *
+ * Launcher registers its unlock controller with us here, and we use that to prepare for and start
+ * the unlock animation.
+ */
+@SysUISingleton
+class InWindowLauncherUnlockAnimationManager
+@Inject
+constructor(
+ val interactor: InWindowLauncherUnlockAnimationInteractor,
+ val viewModel: InWindowLauncherAnimationViewModel,
+ @Application val scope: CoroutineScope,
+) : ISysuiUnlockAnimationController.Stub() {
+
+ /**
+ * The smartspace view on the lockscreen. This is used to perform the shared element animation
+ * between the lockscreen smartspace and the launcher one.
+ */
+ var lockscreenSmartspace: View? = null
+
+ private var launcherAnimationController: ILauncherUnlockAnimationController? = null
+
+ /**
+ * Whether we've called [ILauncherUnlockAnimationController.prepareForUnlock], and have *not*
+ * subsequently called [ILauncherUnlockAnimationController.playUnlockAnimation] or
+ * [ILauncherUnlockAnimationController.setUnlockAmount].
+ */
+ private var preparedForUnlock = false
+
+ /**
+ * Most recent value passed to [ILauncherUnlockAnimationController.setUnlockAmount] during this
+ * unlock.
+ *
+ * Null if we have not set a manual unlock amount, or once [ensureUnlockedOrAnimatingUnlocked]
+ * has been called.
+ */
+ private var manualUnlockAmount: Float? = null
+
+ /**
+ * Called from [OverviewProxyService] to provide us with the launcher unlock animation
+ * controller, which can be used to start and update the unlock animation in the launcher
+ * process.
+ */
+ override fun setLauncherUnlockController(
+ activityClass: String,
+ launcherController: ILauncherUnlockAnimationController,
+ ) {
+ interactor.setLauncherActivityClass(activityClass)
+ launcherAnimationController = launcherController
+
+ // Bind once we have a launcher controller.
+ InWindowLauncherAnimationViewBinder.bind(viewModel, this, scope)
+ }
+
+ /**
+ * Called from the launcher process when their smartspace state updates something we should know
+ * about.
+ */
+ override fun onLauncherSmartspaceStateUpdated(state: SmartspaceState?) {
+ interactor.setLauncherSmartspaceState(state)
+ }
+
+ /**
+ * Requests that the launcher prepare for unlock by becoming blank and optionally positioning
+ * its smartspace at the same position as the lockscreen smartspace.
+ *
+ * This state is dangerous - the launcher will remain blank until we ask it to animate unlocked,
+ * either via [playUnlockAnimation] or [setUnlockAmount]. If you don't want to get funny but bad
+ * bugs titled "tiny launcher" or "Expected: launcher icons; Actual: no icons ever", be very
+ * careful here.
+ */
+ fun prepareForUnlock() {
+ launcherAnimationController?.let { launcher ->
+ if (!preparedForUnlock) {
+ preparedForUnlock = true
+ manualUnlockAmount = null
+
+ launcher.prepareForUnlock(
+ false,
+ Rect(),
+ 0
+ ) // TODO(b/293894758): Add smartspace animation support.
+ }
+ }
+ }
+
+ /** Ensures that the launcher is either fully visible, or animating to be fully visible. */
+ fun ensureUnlockedOrAnimatingUnlocked() {
+ val preparedButDidNotStartAnimation =
+ preparedForUnlock && !interactor.startedUnlockAnimation.value
+ val manualUnlockSetButNotFullyVisible =
+ manualUnlockAmount != null && manualUnlockAmount != 1f
+
+ if (preparedButDidNotStartAnimation) {
+ Log.e(
+ TAG,
+ "Called prepareForUnlock(), but not playUnlockAnimation(). " +
+ "Failing-safe by calling setUnlockAmount(1f)"
+ )
+ setUnlockAmount(1f, forceIfAnimating = true)
+ } else if (manualUnlockSetButNotFullyVisible) {
+ Log.e(
+ TAG,
+ "Unlock has ended, but manual unlock amount != 1f. " +
+ "Failing-safe by calling setUnlockAmount(1f)"
+ )
+ setUnlockAmount(1f, forceIfAnimating = true)
+ }
+
+ manualUnlockAmount = null // Un-set the manual unlock amount as we're now visible.
+ }
+
+ /**
+ * Asks launcher to play the in-window unlock animation with the specified parameters.
+ *
+ * Once this is called, we're no longer [preparedForUnlock] as unlock is underway.
+ */
+ fun playUnlockAnimation(
+ unlocked: Boolean,
+ duration: Long = UNLOCK_ANIMATION_DURATION,
+ startDelay: Long = UNLOCK_START_DELAY,
+ ) {
+ if (preparedForUnlock) {
+ launcherAnimationController?.let { launcher ->
+ launcher.playUnlockAnimation(unlocked, duration, startDelay)
+ interactor.setStartedUnlockAnimation(true)
+ }
+ } else {
+ Log.e(TAG, "Attempted to call playUnlockAnimation() before prepareToUnlock().")
+ }
+
+ preparedForUnlock = false
+ }
+
+ /**
+ * Clears the played unlock animation flag. Since we don't have access to an onAnimationEnd
+ * event for the launcher animation (since it's in a different process), this is called whenever
+ * the transition to GONE ends or the surface becomes unavailable. In both cases, we'd need to
+ * play the animation next time we unlock.
+ */
+ fun clearStartedUnlockAnimation() {
+ interactor.setStartedUnlockAnimation(false)
+ }
+
+ /**
+ * Manually sets the unlock amount on launcher. This is used to explicitly set us to fully
+ * unlocked, or to manually control the animation (such as during a swipe to unlock).
+ *
+ * Once this is called, we're no longer [preparedForUnlock] since the Launcher icons are not
+ * configured to be invisible for the start of the unlock animation.
+ */
+ fun setUnlockAmount(amount: Float, forceIfAnimating: Boolean) {
+ preparedForUnlock = false
+
+ launcherAnimationController?.let {
+ manualUnlockAmount = amount
+ it.setUnlockAmount(amount, forceIfAnimating)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index 21eba56..f1ea446 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -20,6 +20,7 @@
import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
+import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
@@ -30,6 +31,7 @@
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import javax.inject.Inject
@@ -55,6 +57,8 @@
aodNotificationIconsSection: AodNotificationIconsSection,
aodBurnInSection: AodBurnInSection,
communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
+ clockSection: ClockSection,
+ smartspaceSection: SmartspaceSection
) : KeyguardBlueprint {
override val id: String = DEFAULT
@@ -72,6 +76,8 @@
aodNotificationIconsSection,
aodBurnInSection,
communalTutorialIndicatorSection,
+ clockSection,
+ smartspaceSection
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index 0390077..06bb0a6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -30,6 +30,7 @@
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -53,6 +54,7 @@
private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
private val notificationIconAreaController: NotificationIconAreaController,
+ private val smartspaceViewModel: KeyguardSmartspaceViewModel,
) : KeyguardSection() {
private var nicBindingDisposable: DisposableHandle? = null
@@ -115,9 +117,19 @@
} else {
BOTTOM
}
-
constraintSet.apply {
- connect(nicId, TOP, R.id.keyguard_status_view, topAlignment, bottomMargin)
+ if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ connect(
+ nicId,
+ TOP,
+ smartspaceViewModel.smartspaceViewId,
+ topAlignment,
+ bottomMargin
+ )
+ setGoneMargin(nicId, topAlignment, bottomMargin)
+ } else {
+ connect(nicId, TOP, R.id.keyguard_status_view, topAlignment, bottomMargin)
+ }
connect(nicId, START, PARENT_ID, START)
connect(nicId, END, PARENT_ID, END)
constrainHeight(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
new file mode 100644
index 0000000..941c295
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.items
+
+import android.content.Context
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.plugins.ClockController
+import com.android.systemui.plugins.ClockFaceLayout
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.util.Utils
+import dagger.Lazy
+import javax.inject.Inject
+
+internal fun ConstraintSet.setVisibility(
+ views: Iterable<View>,
+ visibility: Int,
+) = views.forEach { view -> this.setVisibility(view.id, visibility) }
+
+internal fun ConstraintSet.setAlpha(
+ views: Iterable<View>,
+ alpha: Float,
+) = views.forEach { view -> this.setAlpha(view.id, alpha) }
+
+class ClockSection
+@Inject
+constructor(
+ private val clockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
+ val smartspaceViewModel: KeyguardSmartspaceViewModel,
+ private val context: Context,
+ private val splitShadeStateController: SplitShadeStateController,
+ private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
+ private val featureFlags: FeatureFlagsClassic,
+) : KeyguardSection() {
+ override fun addViews(constraintLayout: ConstraintLayout) {}
+
+ override fun bindData(constraintLayout: ConstraintLayout) {
+ KeyguardClockViewBinder.bind(
+ this,
+ constraintLayout,
+ keyguardClockViewModel,
+ keyguardBlueprintInteractor.get(),
+ clockInteractor,
+ featureFlags
+ )
+ }
+
+ override fun applyConstraints(constraintSet: ConstraintSet) {
+ clockInteractor.clock?.let { clock ->
+ constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet))
+ }
+ }
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {}
+
+ private fun buildConstraints(
+ clock: ClockController,
+ constraintSet: ConstraintSet
+ ): ConstraintSet {
+ // Add constraint between rootView and clockContainer
+ applyDefaultConstraints(constraintSet)
+ getTargetClockFace(clock).applyConstraints(constraintSet)
+
+ // Add constraint between elements in clock and clock container
+ return constraintSet.apply {
+ setAlpha(getTargetClockFace(clock).views, 1F)
+ setAlpha(getNonTargetClockFace(clock).views, 0F)
+ }
+ }
+
+ var largeClockEndGuideline = PARENT_ID
+
+ // Return if largeClockEndGuideline changes,
+ // and use it to decide whether to refresh blueprint
+ fun setClockShouldBeCentered(shouldBeCentered: Boolean): Boolean {
+ val previousValue = largeClockEndGuideline
+ largeClockEndGuideline = if (shouldBeCentered) PARENT_ID else R.id.split_shade_guideline
+ return previousValue != largeClockEndGuideline
+ }
+
+ fun getTargetClockFace(clock: ClockController): ClockFaceLayout =
+ if (keyguardClockViewModel.useLargeClock) getLargeClockFace(clock)
+ else getSmallClockFace(clock)
+ fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout =
+ if (keyguardClockViewModel.useLargeClock) getSmallClockFace(clock)
+ else getLargeClockFace(clock)
+
+ fun getLargeClockFace(clock: ClockController): ClockFaceLayout = clock.largeClock.layout
+ fun getSmallClockFace(clock: ClockController): ClockFaceLayout = clock.smallClock.layout
+ fun applyDefaultConstraints(constraints: ConstraintSet) {
+ constraints.apply {
+ connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START)
+ connect(R.id.lockscreen_clock_view_large, END, largeClockEndGuideline, END)
+ connect(R.id.lockscreen_clock_view_large, BOTTOM, R.id.lock_icon_view, TOP)
+ var largeClockTopMargin =
+ context.resources.getDimensionPixelSize(R.dimen.status_bar_height) +
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_padding_top
+ ) +
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset)
+ largeClockTopMargin += smartspaceViewModel.getDimen(DATE_WEATHER_VIEW_HEIGHT)
+ largeClockTopMargin += smartspaceViewModel.getDimen(ENHANCED_SMARTSPACE_HEIGHT)
+ if (!keyguardClockViewModel.useLargeClock) {
+ largeClockTopMargin -=
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
+ )
+ }
+ connect(R.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin)
+ constrainWidth(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
+ constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
+ constrainHeight(
+ R.id.lockscreen_clock_view,
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
+ )
+ )
+ connect(
+ R.id.lockscreen_clock_view,
+ START,
+ PARENT_ID,
+ START,
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.clock_padding_start
+ )
+ )
+ var smallClockTopMargin =
+ if (splitShadeStateController.shouldUseSplitNotificationShade(context.resources)) {
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
+ } else {
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
+ Utils.getStatusBarHeaderHeightKeyguard(context)
+ }
+ if (keyguardClockViewModel.useLargeClock) {
+ smallClockTopMargin -=
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
+ )
+ }
+ connect(R.id.lockscreen_clock_view, TOP, PARENT_ID, TOP, smallClockTopMargin)
+ }
+ }
+
+ companion object {
+ private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
+ private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index afa49bd..1995661 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -27,10 +27,11 @@
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.res.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
@@ -47,6 +48,7 @@
private val sharedNotificationContainer: SharedNotificationContainer,
private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
private val controller: NotificationStackScrollLayoutController,
+ private val smartspaceViewModel: KeyguardSmartspaceViewModel
) : KeyguardSection() {
private val placeHolderId = R.id.nssl_placeholder
@@ -92,13 +94,25 @@
} else {
BOTTOM
}
- connect(
- R.id.nssl_placeholder,
- TOP,
- R.id.keyguard_status_view,
- topAlignment,
- bottomMargin
- )
+ if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ connect(
+ R.id.nssl_placeholder,
+ TOP,
+ smartspaceViewModel.smartspaceViewId,
+ topAlignment,
+ bottomMargin
+ )
+ setGoneMargin(R.id.nssl_placeholder, TOP, bottomMargin)
+ } else {
+ connect(
+ R.id.nssl_placeholder,
+ TOP,
+ R.id.keyguard_status_view,
+ topAlignment,
+ bottomMargin
+ )
+ }
+
connect(R.id.nssl_placeholder, START, PARENT_ID, START)
connect(R.id.nssl_placeholder, END, PARENT_ID, END)
connect(R.id.nssl_placeholder, BOTTOM, R.id.lock_icon_view, TOP)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
new file mode 100644
index 0000000..25931a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardSmartspaceViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
+import javax.inject.Inject
+
+class SmartspaceSection
+@Inject
+constructor(
+ val keyguardClockViewModel: KeyguardClockViewModel,
+ val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
+ private val context: Context,
+ val smartspaceController: LockscreenSmartspaceController,
+ val keyguardUnlockAnimationController: KeyguardUnlockAnimationController,
+ val featureFlags: FeatureFlagsClassic,
+) : KeyguardSection() {
+ var smartspaceView: View? = null
+ var weatherView: View? = null
+ var dateView: View? = null
+
+ override fun addViews(constraintLayout: ConstraintLayout) {
+ if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ return
+ }
+ smartspaceView = smartspaceController.buildAndConnectView(constraintLayout)
+ weatherView = smartspaceController.buildAndConnectWeatherView(constraintLayout)
+ dateView = smartspaceController.buildAndConnectDateView(constraintLayout)
+ if (keyguardSmartspaceViewModel.isSmartspaceEnabled) {
+ constraintLayout.addView(smartspaceView)
+ if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) {
+ constraintLayout.addView(weatherView)
+ constraintLayout.addView(dateView)
+ }
+ }
+
+ keyguardUnlockAnimationController.lockscreenSmartspace = smartspaceView
+ }
+
+ override fun bindData(constraintLayout: ConstraintLayout) {
+ KeyguardSmartspaceViewBinder.bind(
+ this,
+ constraintLayout,
+ keyguardClockViewModel,
+ )
+ }
+
+ override fun applyConstraints(constraintSet: ConstraintSet) {
+ // Generally, weather should be next to dateView
+ // smartspace should be below date & weather views
+ constraintSet.apply {
+ // migrate addDateWeatherView, addWeatherView from KeyguardClockSwitchController
+ dateView?.let { dateView ->
+ constrainHeight(dateView.id, WRAP_CONTENT)
+ constrainWidth(dateView.id, WRAP_CONTENT)
+ connect(
+ dateView.id,
+ START,
+ PARENT_ID,
+ START,
+ context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
+ )
+ }
+ weatherView?.let {
+ constrainWidth(it.id, WRAP_CONTENT)
+ dateView?.let { dateView ->
+ connect(it.id, TOP, dateView.id, TOP)
+ connect(it.id, BOTTOM, dateView.id, BOTTOM)
+ connect(it.id, START, dateView.id, END, 4)
+ }
+ }
+ // migrate addSmartspaceView from KeyguardClockSwitchController
+ smartspaceView?.let {
+ constrainHeight(it.id, WRAP_CONTENT)
+ connect(
+ it.id,
+ START,
+ PARENT_ID,
+ START,
+ context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)
+ )
+ connect(
+ it.id,
+ END,
+ PARENT_ID,
+ END,
+ context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)
+ )
+ }
+
+ if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) {
+ dateView?.let { dateView ->
+ smartspaceView?.let { smartspaceView ->
+ connect(dateView.id, BOTTOM, smartspaceView.id, TOP)
+ }
+ }
+ } else {
+ dateView?.let { dateView ->
+ clear(dateView.id, BOTTOM)
+ connect(dateView.id, TOP, R.id.lockscreen_clock_view, BOTTOM)
+ constrainHeight(dateView.id, WRAP_CONTENT)
+ smartspaceView?.let { smartspaceView ->
+ clear(smartspaceView.id, TOP)
+ connect(smartspaceView.id, TOP, dateView.id, BOTTOM)
+ }
+ }
+ }
+ updateVisibility(constraintSet)
+ }
+ }
+
+ private fun updateVisibility(constraintSet: ConstraintSet) {
+ constraintSet.apply {
+ weatherView?.let {
+ setVisibility(
+ it.id,
+ when (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) {
+ true -> ConstraintSet.GONE
+ false ->
+ when (keyguardSmartspaceViewModel.isWeatherEnabled) {
+ true -> ConstraintSet.VISIBLE
+ false -> ConstraintSet.GONE
+ }
+ }
+ )
+ }
+ dateView?.let {
+ setVisibility(
+ it.id,
+ if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) ConstraintSet.GONE
+ else ConstraintSet.VISIBLE
+ )
+ }
+ }
+ }
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ listOf(smartspaceView, dateView, weatherView).forEach {
+ it?.let {
+ if (it.parent == constraintLayout) {
+ constraintLayout.removeView(it)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt
new file mode 100644
index 0000000..2807558
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/InWindowLauncherAnimationViewModel.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
+import javax.inject.Inject
+
+@SysUISingleton
+class InWindowLauncherAnimationViewModel
+@Inject
+constructor(interactor: InWindowLauncherUnlockAnimationInteractor) {
+
+ /**
+ * Whether we should call [ILauncherUnlockAnimationController.prepareForUnlock] to set up the
+ * Launcher icons for the in-window unlock.
+ *
+ * We'll do this as soon as we're transitioning to GONE when the necessary preconditions are
+ * met.
+ */
+ val shouldPrepareForInWindowAnimation = interactor.transitioningToGoneWithInWindowAnimation
+
+ /**
+ * Whether we should call [ILauncherUnlockAnimationController.playUnlockAnimation] to start the
+ * in-window unlock animation.
+ */
+ val shouldStartInWindowAnimation = interactor.shouldStartInWindowAnimation
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
new file mode 100644
index 0000000..c54f47b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.keyguard.KeyguardClockSwitch.LARGE
+import com.android.keyguard.KeyguardClockSwitch.SMALL
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import com.android.systemui.plugins.ClockController
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.stateIn
+
+@SysUISingleton
+class KeyguardClockViewModel
+@Inject
+constructor(
+ val keyguardInteractor: KeyguardInteractor,
+ val keyguardClockInteractor: KeyguardClockInteractor,
+ @Application private val applicationScope: CoroutineScope,
+) {
+ val useLargeClock: Boolean
+ get() = clockSize.value == LARGE
+
+ var clock: ClockController?
+ set(value) {
+ keyguardClockInteractor.clock = value
+ }
+ get() {
+ return keyguardClockInteractor.clock
+ }
+
+ val clockSize =
+ combine(keyguardClockInteractor.selectedClockSize, keyguardInteractor.clockSize) {
+ selectedSize,
+ clockSize ->
+ if (selectedSize == SettingsClockSize.SMALL) {
+ SMALL
+ } else {
+ clockSize
+ }
+ }
+ .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = LARGE
+ )
+
+ val currentClock = keyguardClockInteractor.currentClock
+
+ val hasCustomWeatherDataDisplay =
+ combine(clockSize, currentClock) { size, clock ->
+ (if (size == LARGE) clock.largeClock.config.hasCustomWeatherDataDisplay
+ else clock.smallClock.config.hasCustomWeatherDataDisplay)
+ }
+ .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false
+ )
+
+ val clockShouldBeCentered: Flow<Boolean> =
+ keyguardInteractor.clockShouldBeCentered.distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
new file mode 100644
index 0000000..8e33651
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.content.Context
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
+import javax.inject.Inject
+
+@SysUISingleton
+class KeyguardSmartspaceViewModel
+@Inject
+constructor(val context: Context, smartspaceController: LockscreenSmartspaceController) {
+ val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled()
+ val isWeatherEnabled: Boolean = smartspaceController.isWeatherEnabled()
+ val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled()
+ val smartspaceViewId: Int
+ get() {
+ return context.resources
+ .getIdentifier("bc_smartspace_view", "id", context.packageName)
+ .also {
+ if (it == 0) {
+ Log.d(TAG, "Cannot resolve id bc_smartspace_view")
+ }
+ }
+ }
+
+ fun getDimen(name: String): Int {
+ val res = context.packageManager.getResourcesForApplication(context.packageName)
+ val id = res.getIdentifier(name, "dimen", context.packageName)
+ return res.getDimensionPixelSize(id)
+ }
+
+ companion object {
+ private val TAG = KeyguardSmartspaceViewModel::class.java.simpleName
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 093d098..d9a8080 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -325,7 +325,13 @@
} else {
// TODO(b/278729185): Replace fire and forget service with a bounded service.
val intent = NoteTaskControllerUpdateService.createIntent(context)
- context.startServiceAsUser(intent, user)
+ try {
+ // If the user is stopped before 'startServiceAsUser' kicks-in, a
+ // 'SecurityException' will be thrown.
+ context.startServiceAsUser(intent, user)
+ } catch (e: SecurityException) {
+ debugLog(error = e) { "Unable to start 'NoteTaskControllerUpdateService'." }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
index 905d8ef..840db26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
@@ -29,12 +29,18 @@
* Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard
* dismissing and tile from-view animations.
*/
-@SysUISingleton
-class QSTileIntentUserInputHandler
-@Inject
-constructor(private val activityStarter: ActivityStarter) {
+interface QSTileIntentUserInputHandler {
- fun handle(view: View?, intent: Intent) {
+ fun handle(view: View?, intent: Intent)
+ fun handle(view: View?, pendingIntent: PendingIntent)
+}
+
+@SysUISingleton
+class QSTileIntentUserInputHandlerImpl
+@Inject
+constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler {
+
+ override fun handle(view: View?, intent: Intent) {
val animationController: ActivityLaunchAnimator.Controller? =
view?.let {
ActivityLaunchAnimator.Controller.fromView(
@@ -46,7 +52,7 @@
}
// TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939
- fun handle(view: View?, pendingIntent: PendingIntent) {
+ override fun handle(view: View?, pendingIntent: PendingIntent) {
if (!pendingIntent.isActivity) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index 32522ad..94137c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles.di
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerImpl
import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
@@ -45,4 +47,9 @@
@Multibinds fun tileViewModelMap(): Map<String, QSTileViewModel>
@Binds fun bindQSTileConfigProvider(impl: QSTileConfigProviderImpl): QSTileConfigProvider
+
+ @Binds
+ fun bindQSTileIntentUserInputHandler(
+ impl: QSTileIntentUserInputHandlerImpl
+ ): QSTileIntentUserInputHandler
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1334660..377803f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -85,8 +85,10 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBar;
import com.android.systemui.navigationbar.NavigationBarController;
@@ -102,6 +104,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
@@ -109,8 +112,6 @@
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.wm.shell.sysui.ShellInterface;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -122,6 +123,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import dagger.Lazy;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -160,7 +163,7 @@
private final ScreenshotHelper mScreenshotHelper;
private final CommandQueue mCommandQueue;
private final UserTracker mUserTracker;
- private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
+ private final ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder;
private final UiEventLogger mUiEventLogger;
private final DisplayTracker mDisplayTracker;
@@ -580,6 +583,7 @@
UiEventLogger uiEventLogger,
DisplayTracker displayTracker,
KeyguardUnlockAnimationController sysuiUnlockAnimationController,
+ InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager,
AssistUtils assistUtils,
FeatureFlags featureFlags,
SceneContainerFlags sceneContainerFlags,
@@ -613,7 +617,12 @@
mUiEventLogger = uiEventLogger;
mDisplayTracker = displayTracker;
mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
- mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
+
+ if (!featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
+ mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
+ } else {
+ mSysuiUnlockAnimationController = inWindowLauncherUnlockAnimationManager;
+ }
dumpManager.registerDumpable(getClass().getSimpleName(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 49bceef..018f31b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -61,7 +61,6 @@
Flags.MIGRATE_LOCK_ICON,
Flags.MIGRATE_NSSL,
Flags.MIGRATE_KEYGUARD_STATUS_VIEW,
- Flags.NOTIFICATION_SHELF_REFACTOR,
Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 6fa592c..b30bc56 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -16,7 +16,7 @@
package com.android.systemui.settings.brightness;
-import static com.android.systemui.flags.Flags.HAPTIC_BRIGHTNESS_SLIDER;
+import static com.android.systemui.Flags.hapticBrightnessSlider;
import android.content.Context;
import android.view.LayoutInflater;
@@ -32,7 +32,6 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.haptics.slider.SeekableSliderEventProducer;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -280,7 +279,6 @@
private final FalsingManager mFalsingManager;
private final UiEventLogger mUiEventLogger;
- private final FeatureFlagsClassic mFeatureFlags;
private final VibratorHelper mVibratorHelper;
private final SystemClock mSystemClock;
private final CoroutineDispatcher mMainDispatcher;
@@ -292,12 +290,10 @@
UiEventLogger uiEventLogger,
VibratorHelper vibratorHelper,
SystemClock clock,
- FeatureFlagsClassic featureFlags,
@Main CoroutineDispatcher mainDispatcher,
ActivityStarter activityStarter) {
mFalsingManager = falsingManager;
mUiEventLogger = uiEventLogger;
- mFeatureFlags = featureFlags;
mVibratorHelper = vibratorHelper;
mSystemClock = clock;
mMainDispatcher = mainDispatcher;
@@ -320,7 +316,7 @@
root.setActivityStarter(mActivityStarter);
BrightnessSliderHapticPlugin plugin;
- if (mFeatureFlags.isEnabled(HAPTIC_BRIGHTNESS_SLIDER)) {
+ if (hapticBrightnessSlider()) {
plugin = new BrightnessSliderHapticPluginImpl(
mVibratorHelper,
mSystemClock,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index dfe6adc..85a4a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -173,7 +173,6 @@
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -520,7 +519,6 @@
/** Are we currently in gesture navigation. */
private boolean mIsGestureNavigation;
private int mOldLayoutDirection;
- private NotificationShelfController mNotificationShelfController;
private final ContentResolver mContentResolver;
private float mMinFraction;
@@ -1600,8 +1598,12 @@
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange();
- mKeyguardStatusViewController.displayClock(computeDesiredClockSize(),
- shouldAnimateClockChange);
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ mKeyguardInteractor.setClockSize(computeDesiredClockSize());
+ } else {
+ mKeyguardStatusViewController.displayClock(computeDesiredClockSize(),
+ shouldAnimateClockChange);
+ }
updateKeyguardStatusViewAlignment(/* animate= */shouldAnimateKeyguardStatusViewAlignment());
int userSwitcherHeight = mKeyguardQsUserSwitchController != null
? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
@@ -1729,9 +1731,13 @@
} else {
layout = mNotificationContainerParent;
}
- mKeyguardStatusViewController.updateAlignment(
- layout, mSplitShadeEnabled, shouldBeCentered, animate);
- mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) {
+ mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
+ } else {
+ mKeyguardStatusViewController.updateAlignment(
+ layout, mSplitShadeEnabled, shouldBeCentered, animate);
+ mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
+ }
}
private boolean shouldKeyguardStatusViewBeCentered() {
@@ -1886,11 +1892,7 @@
}
private int getShelfHeight() {
- if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- return mNotificationStackScrollLayoutController.getShelfHeight();
- } else {
- return mNotificationShelfController.getIntrinsicHeight();
- }
+ return mNotificationStackScrollLayoutController.getShelfHeight();
}
private void updateClock() {
@@ -3498,7 +3500,6 @@
CentralSurfaces centralSurfaces,
GestureRecorder recorder,
Runnable hideExpandedRunnable,
- NotificationShelfController notificationShelfController,
HeadsUpManager headsUpManager) {
setHeadsUpManager(headsUpManager);
// TODO(b/254859580): this can be injected.
@@ -3506,12 +3507,6 @@
mGestureRecorder = recorder;
mHideExpandedRunnable = hideExpandedRunnable;
- mNotificationShelfController = notificationShelfController;
- if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- mNotificationStackScrollLayoutController.setShelfController(
- notificationShelfController);
- mLockscreenShadeTransitionController.bindController(notificationShelfController);
- }
updateMaxDisplayedNotifications(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 5114826..121aa42 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -355,7 +355,10 @@
&& !state.keyguardFadingAway && !state.keyguardGoingAway;
if (onKeyguard
&& mAuthController.isUdfpsEnrolled(mUserInteractor.get().getSelectedUserId())) {
- // both max and min display refresh rate must be set to take effect:
+ // Requests the max refresh rate (ie: for smooth display). Note: By setting
+ // the preferred refresh rates below, the refresh rate will not override the max
+ // refresh rate in settings (ie: if smooth display is OFF).
+ // Both max and min display refresh rate must be set to take effect:
mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardPreferredRefreshRate;
mLpChanged.preferredMinDisplayRefreshRate = mKeyguardPreferredRefreshRate;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 4e23e7d..e54286f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -17,7 +17,6 @@
import android.view.ViewPropertyAnimator
import com.android.systemui.statusbar.GestureRecorder
-import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -33,7 +32,6 @@
centralSurfaces: CentralSurfaces,
recorder: GestureRecorder,
hideExpandedRunnable: Runnable,
- notificationShelfController: NotificationShelfController,
headsUpManager: HeadsUpManager
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 38b358f..37073a6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -22,16 +22,15 @@
import android.view.LayoutInflater
import android.view.ViewStub
import androidx.constraintlayout.motion.widget.MotionLayout
-import com.android.systemui.res.R
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.biometrics.AuthRippleView
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -41,10 +40,6 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.NotificationInsetsController
-import com.android.systemui.statusbar.NotificationShelf
-import com.android.systemui.statusbar.NotificationShelfController
-import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent
-import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
@@ -118,32 +113,6 @@
return notificationShadeWindowView.requireViewById(R.id.notification_stack_scroller)
}
- @Provides
- @SysUISingleton
- fun providesNotificationShelfController(
- featureFlags: FeatureFlags,
- newImpl: Provider<NotificationShelfViewBinderWrapperControllerImpl>,
- notificationShelfComponentBuilder: NotificationShelfComponent.Builder,
- layoutInflater: LayoutInflater,
- notificationStackScrollLayout: NotificationStackScrollLayout,
- ): NotificationShelfController {
- return if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- newImpl.get()
- } else {
- val shelfView =
- layoutInflater.inflate(
- R.layout.status_bar_notification_shelf,
- notificationStackScrollLayout,
- false
- ) as NotificationShelf
- val component =
- notificationShelfComponentBuilder.notificationShelf(shelfView).build()
- val notificationShelfController = component.notificationShelfController
- notificationShelfController.init()
- notificationShelfController
- }
- }
-
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index ab015ef..de334bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -145,7 +145,7 @@
if (view instanceof EmptyShadeView) {
EmptyShadeView emptyShadeView = (EmptyShadeView) view;
boolean visible = this.clipTopAmount <= mEmptyText.getPaddingTop() * 0.6f;
- emptyShadeView.setContentVisible(visible && emptyShadeView.isVisible());
+ emptyShadeView.setContentVisibleAnimated(visible && emptyShadeView.isVisible());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
deleted file mode 100644
index 7a989cf..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ /dev/null
@@ -1,110 +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.statusbar;
-
-import android.view.View;
-
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
-import com.android.systemui.statusbar.notification.stack.AmbientState;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationIconContainer;
-
-import javax.inject.Inject;
-
-/**
- * Controller class for {@link NotificationShelf}.
- */
-@NotificationRowScope
-public class LegacyNotificationShelfControllerImpl implements NotificationShelfController {
- private final NotificationShelf mView;
- private final ActivatableNotificationViewController mActivatableNotificationViewController;
- private final KeyguardBypassController mKeyguardBypassController;
- private final SysuiStatusBarStateController mStatusBarStateController;
- private final View.OnAttachStateChangeListener mOnAttachStateChangeListener;
- private AmbientState mAmbientState;
-
- @Inject
- public LegacyNotificationShelfControllerImpl(
- NotificationShelf notificationShelf,
- ActivatableNotificationViewController activatableNotificationViewController,
- KeyguardBypassController keyguardBypassController,
- SysuiStatusBarStateController statusBarStateController,
- FeatureFlags featureFlags) {
- mView = notificationShelf;
- mActivatableNotificationViewController = activatableNotificationViewController;
- mKeyguardBypassController = keyguardBypassController;
- mStatusBarStateController = statusBarStateController;
- mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- mStatusBarStateController.addCallback(
- mView, SysuiStatusBarStateController.RANK_SHELF);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- mStatusBarStateController.removeCallback(mView);
- }
- };
- }
-
- public void init() {
- mActivatableNotificationViewController.init();
- mView.setController(this);
- mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
- if (mView.isAttachedToWindow()) {
- mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
- }
- }
-
- @Override
- public NotificationShelf getView() {
- return mView;
- }
-
- @Override
- public boolean canModifyColorOfNotifications() {
- return mAmbientState.isShadeExpanded()
- && !(mAmbientState.isOnKeyguard() && mKeyguardBypassController.getBypassEnabled());
- }
-
- @Override
- public NotificationIconContainer getShelfIcons() {
- return mView.getShelfIcons();
- }
-
- @Override
- public void bind(AmbientState ambientState,
- NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
- mView.bind(ambientState, notificationStackScrollLayoutController);
- mAmbientState = ambientState;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mView.getIntrinsicHeight();
- }
-
- @Override
- public void setOnClickListener(View.OnClickListener onClickListener) {
- mView.setOnClickListener(onClickListener);
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 143e620..bf722af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -5,7 +5,6 @@
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
-import android.os.PowerManager
import android.util.IndentingPrintWriter
import android.util.MathUtils
import android.view.MotionEvent
@@ -16,7 +15,6 @@
import com.android.systemui.Dumpable
import com.android.systemui.ExpandHelper
import com.android.systemui.Gefingerpoken
-import com.android.systemui.res.R
import com.android.systemui.biometrics.UdfpsKeyguardViewControllerLegacy
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
@@ -30,6 +28,7 @@
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.res.R
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -51,11 +50,11 @@
private const val RUBBERBAND_FACTOR_STATIC = 0.15f
private const val RUBBERBAND_FACTOR_EXPANDABLE = 0.5f
-/**
- * A class that controls the lockscreen to shade transition
- */
+/** A class that controls the lockscreen to shade transition */
@SysUISingleton
-class LockscreenShadeTransitionController @Inject constructor(
+class LockscreenShadeTransitionController
+@Inject
+constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val logger: LSShadeTransitionLogger,
private val keyguardBypassController: KeyguardBypassController,
@@ -65,7 +64,7 @@
private val mediaHierarchyManager: MediaHierarchyManager,
private val scrimTransitionController: LockscreenShadeScrimTransitionController,
private val keyguardTransitionControllerFactory:
- LockscreenShadeKeyguardTransitionController.Factory,
+ LockscreenShadeKeyguardTransitionController.Factory,
private val depthController: NotificationShadeDepthController,
private val context: Context,
private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory,
@@ -92,31 +91,19 @@
lateinit var centralSurfaces: CentralSurfaces
lateinit var qS: QS
- /**
- * A handler that handles the next keyguard dismiss animation.
- */
+ /** A handler that handles the next keyguard dismiss animation. */
private var animationHandlerOnKeyguardDismiss: ((Long) -> Unit)? = null
- /**
- * The entry that was just dragged down on.
- */
+ /** The entry that was just dragged down on. */
private var draggedDownEntry: NotificationEntry? = null
- /**
- * The current animator if any
- */
- @VisibleForTesting
- internal var dragDownAnimator: ValueAnimator? = null
+ /** The current animator if any */
+ @VisibleForTesting internal var dragDownAnimator: ValueAnimator? = null
- /**
- * The current pulse height animator if any
- */
- @VisibleForTesting
- internal var pulseHeightAnimator: ValueAnimator? = null
+ /** The current pulse height animator if any */
+ @VisibleForTesting internal var pulseHeightAnimator: ValueAnimator? = null
- /**
- * Distance that the full shade transition takes in order to complete.
- */
+ /** Distance that the full shade transition takes in order to complete. */
private var fullTransitionDistance = 0
/**
@@ -150,36 +137,26 @@
private var statusBarTransitionDistance = 0
/**
- * Flag to make sure that the dragDownAmount is applied to the listeners even when in the
- * locked down shade.
+ * Flag to make sure that the dragDownAmount is applied to the listeners even when in the locked
+ * down shade.
*/
private var forceApplyAmount = false
- /**
- * A flag to suppress the default animation when unlocking in the locked down shade.
- */
+ /** A flag to suppress the default animation when unlocking in the locked down shade. */
private var nextHideKeyguardNeedsNoAnimation = false
- /**
- * Are we currently waking up to the shade locked
- */
+ /** Are we currently waking up to the shade locked */
var isWakingToShadeLocked: Boolean = false
private set
- /**
- * The distance until we're showing the notifications when pulsing
- */
+ /** The distance until we're showing the notifications when pulsing */
val distanceUntilShowingPulsingNotifications
get() = fullTransitionDistance
- /**
- * The udfpsKeyguardViewController if it exists.
- */
+ /** The udfpsKeyguardViewController if it exists. */
var mUdfpsKeyguardViewControllerLegacy: UdfpsKeyguardViewControllerLegacy? = null
- /**
- * The touch helper responsible for the drag down animation.
- */
+ /** The touch helper responsible for the drag down animation. */
val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context)
private val splitShadeOverScroller: SplitShadeLockScreenOverScroller by lazy {
@@ -198,12 +175,12 @@
private val callbacks = mutableListOf<Callback>()
- /** See [LockscreenShadeQsTransitionController.qsTransitionFraction].*/
+ /** See [LockscreenShadeQsTransitionController.qsTransitionFraction]. */
@get:FloatRange(from = 0.0, to = 1.0)
val qSDragProgress: Float
get() = qsTransitionController.qsTransitionFraction
- /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction].*/
+ /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction]. */
@get:FloatRange(from = 0.0, to = 1.0)
val qsSquishTransitionFraction: Float
get() = qsTransitionController.qsSquishTransitionFraction
@@ -223,54 +200,71 @@
init {
updateResources()
- configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration?) {
- updateResources()
- touchHelper.updateResources(context)
+ configurationController.addCallback(
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateResources()
+ touchHelper.updateResources(context)
+ }
}
- })
+ )
dumpManager.registerDumpable(this)
- statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
- override fun onExpandedChanged(isExpanded: Boolean) {
- // safeguard: When the panel is fully collapsed, let's make sure to reset.
- // See b/198098523
- if (!isExpanded) {
- if (dragDownAmount != 0f && dragDownAnimator?.isRunning != true) {
- logger.logDragDownAmountResetWhenFullyCollapsed()
- dragDownAmount = 0f
- }
- if (pulseHeight != 0f && pulseHeightAnimator?.isRunning != true) {
- logger.logPulseHeightNotResetWhenFullyCollapsed()
- setPulseHeight(0f, animate = false)
+ statusBarStateController.addCallback(
+ object : StatusBarStateController.StateListener {
+ override fun onExpandedChanged(isExpanded: Boolean) {
+ // safeguard: When the panel is fully collapsed, let's make sure to reset.
+ // See b/198098523
+ if (!isExpanded) {
+ if (dragDownAmount != 0f && dragDownAnimator?.isRunning != true) {
+ logger.logDragDownAmountResetWhenFullyCollapsed()
+ dragDownAmount = 0f
+ }
+ if (pulseHeight != 0f && pulseHeightAnimator?.isRunning != true) {
+ logger.logPulseHeightNotResetWhenFullyCollapsed()
+ setPulseHeight(0f, animate = false)
+ }
}
}
}
- })
- wakefulnessLifecycle.addObserver(object : WakefulnessLifecycle.Observer {
- override fun onPostFinishedWakingUp() {
- // when finishing waking up, the UnlockedScreenOffAnimation has another attempt
- // to reset keyguard. Let's do it in post
- isWakingToShadeLocked = false
+ )
+ wakefulnessLifecycle.addObserver(
+ object : WakefulnessLifecycle.Observer {
+ override fun onPostFinishedWakingUp() {
+ // when finishing waking up, the UnlockedScreenOffAnimation has another attempt
+ // to reset keyguard. Let's do it in post
+ isWakingToShadeLocked = false
+ }
}
- })
+ )
}
private fun updateResources() {
- fullTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_full_transition_distance)
- fullTransitionDistanceByTap = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_transition_by_tap_distance)
- notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_notif_shelf_transition_distance)
- depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_depth_controller_transition_distance)
- udfpsTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_udfps_keyguard_transition_distance)
- statusBarTransitionDistance = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_status_bar_transition_distance)
+ fullTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_full_transition_distance
+ )
+ fullTransitionDistanceByTap =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_transition_by_tap_distance
+ )
+ notificationShelfTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notif_shelf_transition_distance
+ )
+ depthControllerTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_depth_controller_transition_distance
+ )
+ udfpsTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_udfps_keyguard_transition_distance
+ )
+ statusBarTransitionDistance =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_status_bar_transition_distance
+ )
- useSplitShade = splitShadeStateController
- .shouldUseSplitNotificationShade(context.resources)
+ useSplitShade = splitShadeStateController.shouldUseSplitNotificationShade(context.resources)
}
fun setStackScroller(nsslController: NotificationStackScrollLayoutController) {
@@ -278,31 +272,13 @@
touchHelper.expandCallback = nsslController.expandHelperCallback
}
- /**
- * Initialize the shelf controller such that clicks on it will expand the shade
- */
- fun bindController(notificationShelfController: NotificationShelfController) {
- // Bind the click listener of the shelf to go to the full shade
- notificationShelfController.setOnClickListener {
- if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- powerInteractor.wakeUpIfDozing("SHADE_CLICK", PowerManager.WAKE_REASON_GESTURE)
- goToLockedShade(it)
- }
- }
- }
-
- /**
- * @return true if the interaction is accepted, false if it should be cancelled
- */
+ /** @return true if the interaction is accepted, false if it should be cancelled */
internal fun canDragDown(): Boolean {
return (statusBarStateController.state == StatusBarState.KEYGUARD ||
- nsslController.isInLockedDownShade()) &&
- (qS.isFullyCollapsed || useSplitShade)
+ nsslController.isInLockedDownShade()) && (qS.isFullyCollapsed || useSplitShade)
}
- /**
- * Called by the touch helper when when a gesture has completed all the way and released.
- */
+ /** Called by the touch helper when when a gesture has completed all the way and released. */
internal fun onDraggedDown(startingChild: View?, dragLengthY: Int) {
if (canDragDown()) {
val cancelRunnable = Runnable {
@@ -318,8 +294,7 @@
false
},
cancelRunnable,
- /* afterKeyguardGone= */
- false,
+ /* afterKeyguardGone= */ false,
)
} else {
logger.logDraggedDown(startingChild, dragLengthY)
@@ -334,12 +309,7 @@
}
shadeViewController.transitionToExpandedShade(delay)
callbacks.forEach {
- it.setTransitionToFullShadeAmount(
- 0f,
- /* animated= */
- true,
- delay
- )
+ it.setTransitionToFullShadeAmount(0f, /* animated= */ true, delay)
}
// Let's reset ourselves, ready for the next animation
@@ -361,16 +331,12 @@
}
}
- /**
- * Called by the touch helper when the drag down was aborted and should be reset.
- */
+ /** Called by the touch helper when the drag down was aborted and should be reset. */
internal fun onDragDownReset() {
logger.logDragDownAborted()
nsslController.setDimmed(
- /* dimmed= */
- true,
- /* animate= */
- true,
+ /* dimmed= */ true,
+ /* animate= */ true,
)
nsslController.resetScrollPosition()
nsslController.resetCheckSnoozeLeavebehind()
@@ -379,20 +345,17 @@
/**
* The user has dragged either above or below the threshold which changes the dimmed state.
+ *
* @param above whether they dragged above it
*/
internal fun onCrossedThreshold(above: Boolean) {
nsslController.setDimmed(
- /* dimmed= */
- !above,
- /* animate= */
- true,
+ /* dimmed= */ !above,
+ /* animate= */ true,
)
}
- /**
- * Called by the touch helper when the drag down was started
- */
+ /** Called by the touch helper when the drag down was started */
internal fun onDragDownStarted(startingChild: ExpandableView?) {
logger.logDragDownStarted(startingChild)
nsslController.cancelLongPress()
@@ -405,14 +368,13 @@
}
}
- /**
- * Do we need a falsing check currently?
- */
+ /** Do we need a falsing check currently? */
internal val isFalsingCheckNeeded: Boolean
get() = statusBarStateController.state == StatusBarState.KEYGUARD
/**
* Is dragging down enabled on a given view
+ *
* @param view The view to check or `null` to check if it's enabled at all
*/
internal fun isDragDownEnabledForView(view: ExpandableView?): Boolean {
@@ -432,17 +394,14 @@
return false
}
- /**
- * @return if drag down is enabled anywhere, not just on selected views.
- */
+ /** @return if drag down is enabled anywhere, not just on selected views. */
internal val isDragDownAnywhereEnabled: Boolean
- get() = (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
- !keyguardBypassController.bypassEnabled &&
- (qS.isFullyCollapsed || useSplitShade))
+ get() =
+ (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
+ !keyguardBypassController.bypassEnabled &&
+ (qS.isFullyCollapsed || useSplitShade))
- /**
- * The amount in pixels that the user has dragged down.
- */
+ /** The amount in pixels that the user has dragged down. */
internal var dragDownAmount = 0f
set(value) {
if (field != value || forceApplyAmount) {
@@ -458,10 +417,8 @@
callbacks.forEach {
it.setTransitionToFullShadeAmount(
field,
- /* animate= */
- false,
- /* delay= */
- 0,
+ /* animate= */ false,
+ /* delay= */ 0,
)
}
@@ -507,19 +464,19 @@
dragDownAnimator.startDelay = delay
}
if (endlistener != null) {
- dragDownAnimator.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- endlistener.invoke()
+ dragDownAnimator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ endlistener.invoke()
+ }
}
- })
+ )
}
dragDownAnimator.start()
this.dragDownAnimator = dragDownAnimator
}
- /**
- * Animate appear the drag down amount.
- */
+ /** Animate appear the drag down amount. */
private fun animateAppear(delay: Long = 0) {
// changing to shade locked will make isInLockDownShade true, so let's override
// that
@@ -541,20 +498,20 @@
}
/**
- * Ask this controller to go to the locked shade, changing the state change and doing
- * an animation, where the qs appears from 0 from the top
+ * Ask this controller to go to the locked shade, changing the state change and doing an
+ * animation, where the qs appears from 0 from the top
*
- * If secure with redaction: Show bouncer, go to unlocked shade.
- * If secure without redaction or no security: Go to [StatusBarState.SHADE_LOCKED].
+ * If secure with redaction: Show bouncer, go to unlocked shade. If secure without redaction or
+ * no security: Go to [StatusBarState.SHADE_LOCKED].
*
- * Split shade is special case and [needsQSAnimation] will be always overridden to true.
- * That's because handheld shade will automatically follow notifications animation, but that's
- * not the case for split shade.
+ * Split shade is special case and [needsQSAnimation] will be always overridden to true. That's
+ * because handheld shade will automatically follow notifications animation, but that's not the
+ * case for split shade.
*
* @param expandView The view to expand after going to the shade
* @param needsQSAnimation if this needs the quick settings to slide in from the top or if
- * that's already handled separately. This argument will be ignored on
- * split shade as there QS animation can't be handled separately.
+ * that's already handled separately. This argument will be ignored on split shade as there QS
+ * animation can't be handled separately.
*/
@JvmOverloads
fun goToLockedShade(expandedView: View?, needsQSAnimation: Boolean = true) {
@@ -571,11 +528,7 @@
shadeViewController.transitionToExpandedShade(delay)
}
}
- goToLockedShadeInternal(
- expandedView,
- animationHandler,
- cancelAction = null
- )
+ goToLockedShadeInternal(expandedView, animationHandler, cancelAction = null)
}
}
@@ -586,11 +539,10 @@
*
* @param expandView The view to expand after going to the shade.
* @param animationHandler The handler which performs the go to full shade animation. If null,
- * the default handler will do the animation, otherwise the caller is
- * responsible for the animation. The input value is a Long for the
- * delay for the animation.
+ * the default handler will do the animation, otherwise the caller is responsible for the
+ * animation. The input value is a Long for the delay for the animation.
* @param cancelAction The runnable to invoke when the transition is aborted. This happens if
- * the user goes to the bouncer and goes back.
+ * the user goes to the bouncer and goes back.
*/
private fun goToLockedShadeInternal(
expandView: View?,
@@ -607,18 +559,16 @@
if (expandView is ExpandableNotificationRow) {
entry = expandView.entry
entry.setUserExpanded(
- /* userExpanded= */
- true,
- /* allowChildExpansion= */
- true,
+ /* userExpanded= */ true,
+ /* allowChildExpansion= */ true,
)
// Indicate that the group expansion is changing at this time -- this way the group
// and children backgrounds / divider animations will look correct.
entry.setGroupExpansionChanging(true)
userId = entry.sbn.userId
}
- var fullShadeNeedsBouncer = (
- !lockScreenUserManager.shouldShowLockscreenNotifications() ||
+ var fullShadeNeedsBouncer =
+ (!lockScreenUserManager.shouldShowLockscreenNotifications() ||
falsingCollector.shouldEnforceBouncer())
if (keyguardBypassController.bypassEnabled) {
fullShadeNeedsBouncer = false
@@ -638,8 +588,7 @@
draggedDownEntry?.apply {
setUserLocked(false)
notifyHeightChanged(
- /* needsAnimation= */
- false,
+ /* needsAnimation= */ false,
)
draggedDownEntry = null
}
@@ -659,8 +608,7 @@
// the scrimstate resets too early
if (animationHandler != null) {
animationHandler.invoke(
- /* delay= */
- 0,
+ /* delay= */ 0,
)
} else {
performDefaultGoToFullShadeAnimation(0)
@@ -669,8 +617,8 @@
}
/**
- * Notify this handler that the keyguard was just dismissed and that a animation to
- * the full shade should happen.
+ * Notify this handler that the keyguard was just dismissed and that a animation to the full
+ * shade should happen.
*
* @param delay the delay to do the animation with
* @param previousState which state were we in when we hid the keyguard?
@@ -695,8 +643,8 @@
}
/**
- * Perform the default appear animation when going to the full shade. This is called when
- * not triggered by gestures, e.g. when clicking on the shelf or expand button.
+ * Perform the default appear animation when going to the full shade. This is called when not
+ * triggered by gestures, e.g. when clicking on the shelf or expand button.
*/
private fun performDefaultGoToFullShadeAnimation(delay: Long) {
logger.logDefaultGoToFullShadeAnimation(delay)
@@ -733,6 +681,7 @@
/**
* Finish the pulse animation when the touch interaction finishes
+ *
* @param cancelled was the interaction cancelled and this is a reset?
*/
fun finishPulseAnimation(cancelled: Boolean) {
@@ -745,9 +694,7 @@
}
}
- /**
- * Notify this class that a pulse expansion is starting
- */
+ /** Notify this class that a pulse expansion is starting */
fun onPulseExpansionStarted() {
logger.logPulseExpansionStarted()
pulseHeightAnimator?.apply {
@@ -781,16 +728,14 @@
}
}
- /**
- * Callback for authentication events.
- */
+ /** Callback for authentication events. */
interface Callback {
- /** TODO: comment here */
+ /** TODO: comment here */
fun onPulseExpansionFinished() {}
/**
- * Sets the amount of pixels we have currently dragged down if we're transitioning
- * to the full shade. 0.0f means we're not transitioning yet.
+ * Sets the amount of pixels we have currently dragged down if we're transitioning to the
+ * full shade. 0.0f means we're not transitioning yet.
*/
fun setTransitionToFullShadeAmount(pxAmount: Float, animate: Boolean, delay: Long) {}
}
@@ -838,8 +783,8 @@
}
fun updateResources(context: Context) {
- minDragDistance = context.resources.getDimensionPixelSize(
- R.dimen.keyguard_drag_down_min_distance)
+ minDragDistance =
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_drag_down_min_distance)
val configuration = ViewConfiguration.get(context)
touchSlop = configuration.scaledTouchSlop.toFloat()
slopMultiplier = configuration.scaledAmbiguousGestureMultiplier
@@ -856,7 +801,6 @@
initialTouchY = y
initialTouchX = x
}
-
MotionEvent.ACTION_MOVE -> {
val h = y - initialTouchY
// Adjust the touch slop if another gesture may be being performed.
@@ -907,20 +851,22 @@
}
return true
}
-
- MotionEvent.ACTION_UP -> if (!falsingManager.isUnlockingDisabled && !isFalseTouch &&
- dragDownCallback.canDragDown()) {
- dragDownCallback.onDraggedDown(startingChild, (y - initialTouchY).toInt())
- if (startingChild != null) {
- expandCallback.setUserLockedChild(startingChild, false)
- startingChild = null
+ MotionEvent.ACTION_UP ->
+ if (
+ !falsingManager.isUnlockingDisabled &&
+ !isFalseTouch &&
+ dragDownCallback.canDragDown()
+ ) {
+ dragDownCallback.onDraggedDown(startingChild, (y - initialTouchY).toInt())
+ if (startingChild != null) {
+ expandCallback.setUserLockedChild(startingChild, false)
+ startingChild = null
+ }
+ isDraggingDown = false
+ } else {
+ stopDragging()
+ return false
}
- isDraggingDown = false
- } else {
- stopDragging()
- return false
- }
-
MotionEvent.ACTION_CANCEL -> {
stopDragging()
return false
@@ -948,11 +894,12 @@
hDelta = 0f
}
val expandable = child.isContentExpandable
- val rubberbandFactor = if (expandable) {
- RUBBERBAND_FACTOR_EXPANDABLE
- } else {
- RUBBERBAND_FACTOR_STATIC
- }
+ val rubberbandFactor =
+ if (expandable) {
+ RUBBERBAND_FACTOR_EXPANDABLE
+ } else {
+ RUBBERBAND_FACTOR_STATIC
+ }
var rubberband = hDelta * rubberbandFactor
if (expandable && rubberband + child.collapsedHeight > child.maxContentHeight) {
var overshoot = rubberband + child.collapsedHeight - child.maxContentHeight
@@ -978,11 +925,13 @@
// don't use reflection, because the `actualHeight` field may be obfuscated
child.actualHeight = animation.animatedValue as Int
}
- anim.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- expandCallback.setUserLockedChild(child, false)
+ anim.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ expandCallback.setUserLockedChild(child, false)
+ }
}
- })
+ )
anim.start()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 23b697e..0b6e400 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -40,7 +40,6 @@
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.RefactorFlag;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -48,12 +47,12 @@
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -65,7 +64,7 @@
* A notification shelf view that is placed inside the notification scroller. It manages the
* overflow icons that don't fit into the regular list anymore.
*/
-public class NotificationShelf extends ActivatableNotificationView implements StateListener {
+public class NotificationShelf extends ActivatableNotificationView {
private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
private static final String TAG = "NotificationShelf";
@@ -82,24 +81,19 @@
private int mStatusBarHeight;
private boolean mEnableNotificationClipping;
private AmbientState mAmbientState;
- private NotificationStackScrollLayoutController mHostLayoutController;
private int mPaddingBetweenElements;
private int mNotGoneIndex;
private boolean mHasItemsInStableShelf;
private int mScrollFastThreshold;
- private int mStatusBarState;
private boolean mInteractive;
private boolean mAnimationsEnabled = true;
private boolean mShowNotificationShelf;
- private Rect mClipRect = new Rect();
+ private final Rect mClipRect = new Rect();
private int mIndexOfFirstViewInShelf = -1;
private float mCornerAnimationDistance;
- private NotificationShelfController mController;
private float mActualWidth = -1;
private final RefactorFlag mSensitiveRevealAnim =
RefactorFlag.forView(Flags.SENSITIVE_REVEAL_ANIM);
- private final RefactorFlag mShelfRefactor =
- RefactorFlag.forView(Flags.NOTIFICATION_SHELF_REFACTOR);
private boolean mCanModifyColorOfNotifications;
private boolean mCanInteract;
private NotificationStackScrollLayout mHostLayout;
@@ -131,19 +125,8 @@
updateResources();
}
- public void bind(AmbientState ambientState,
- NotificationStackScrollLayoutController hostLayoutController) {
- mShelfRefactor.assertInLegacyMode();
- mAmbientState = ambientState;
- mHostLayoutController = hostLayoutController;
- hostLayoutController.setOnNotificationRemovedListener((child, isTransferInProgress) -> {
- child.requestRoundnessReset(SHELF_SCROLL);
- });
- }
-
public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout,
NotificationRoundnessManager roundnessManager) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
mAmbientState = ambientState;
mHostLayout = hostLayout;
mRoundnessManager = roundnessManager;
@@ -169,7 +152,11 @@
R.dimen.notification_corner_animation_distance);
mEnableNotificationClipping = res.getBoolean(R.bool.notification_enable_clipping);
- mShelfIcons.setInNotificationIconShelf(true);
+ if (NotificationIconContainerRefactor.isEnabled()) {
+ mShelfIcons.setOverrideIconColor(true);
+ } else {
+ mShelfIcons.setInNotificationIconShelf(true);
+ }
if (!mShowNotificationShelf) {
setVisibility(GONE);
}
@@ -198,13 +185,15 @@
@Override
public String toString() {
- return "NotificationShelf("
- + "hideBackground=" + mHideBackground + " notGoneIndex=" + mNotGoneIndex
+ return "NotificationShelf"
+ + "(hideBackground=" + mHideBackground
+ + " notGoneIndex=" + mNotGoneIndex
+ " hasItemsInStableShelf=" + mHasItemsInStableShelf
- + " statusBarState=" + mStatusBarState + " interactive=" + mInteractive
+ + " interactive=" + mInteractive
+ " animationsEnabled=" + mAnimationsEnabled
+ " showNotificationShelf=" + mShowNotificationShelf
- + " indexOfFirstViewInShelf=" + mIndexOfFirstViewInShelf + ')';
+ + " indexOfFirstViewInShelf=" + mIndexOfFirstViewInShelf
+ + ')';
}
/**
@@ -282,11 +271,7 @@
}
private int getSpeedBumpIndex() {
- if (mShelfRefactor.isEnabled()) {
- return mHostLayout.getSpeedBumpIndex();
- } else {
- return mHostLayoutController.getSpeedBumpIndex();
- }
+ return mHostLayout.getSpeedBumpIndex();
}
/**
@@ -507,27 +492,15 @@
}
private ExpandableView getHostLayoutChildAt(int index) {
- if (mShelfRefactor.isEnabled()) {
- return (ExpandableView) mHostLayout.getChildAt(index);
- } else {
- return mHostLayoutController.getChildAt(index);
- }
+ return (ExpandableView) mHostLayout.getChildAt(index);
}
private int getHostLayoutChildCount() {
- if (mShelfRefactor.isEnabled()) {
- return mHostLayout.getChildCount();
- } else {
- return mHostLayoutController.getChildCount();
- }
+ return mHostLayout.getChildCount();
}
private boolean canModifyColorOfNotifications() {
- if (mShelfRefactor.isEnabled()) {
- return mCanModifyColorOfNotifications && mAmbientState.isShadeExpanded();
- } else {
- return mController.canModifyColorOfNotifications();
- }
+ return mCanModifyColorOfNotifications && mAmbientState.isShadeExpanded();
}
private void updateCornerRoundnessOnScroll(
@@ -586,11 +559,7 @@
}
private boolean isViewAffectedBySwipe(ExpandableView expandableView) {
- if (!mShelfRefactor.isEnabled()) {
- return mHostLayoutController.isViewAffectedBySwipe(expandableView);
- } else {
- return mRoundnessManager.isViewAffectedBySwipe(expandableView);
- }
+ return mRoundnessManager.isViewAffectedBySwipe(expandableView);
}
/**
@@ -610,19 +579,11 @@
}
private View getHostLayoutTransientView(int index) {
- if (mShelfRefactor.isEnabled()) {
- return mHostLayout.getTransientView(index);
- } else {
- return mHostLayoutController.getTransientView(index);
- }
+ return mHostLayout.getTransientView(index);
}
private int getHostLayoutTransientViewCount() {
- if (mShelfRefactor.isEnabled()) {
- return mHostLayout.getTransientViewCount();
- } else {
- return mHostLayoutController.getTransientViewCount();
- }
+ return mHostLayout.getTransientViewCount();
}
private void updateIconClipAmount(ExpandableNotificationRow row) {
@@ -962,29 +923,14 @@
}
}
- @Override
- public void onStateChanged(int newState) {
- mShelfRefactor.assertInLegacyMode();
- mStatusBarState = newState;
- updateInteractiveness();
- }
-
private void updateInteractiveness() {
- mInteractive = canInteract() && mHasItemsInStableShelf;
+ mInteractive = mCanInteract && mHasItemsInStableShelf;
setClickable(mInteractive);
setFocusable(mInteractive);
setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
- private boolean canInteract() {
- if (mShelfRefactor.isEnabled()) {
- return mCanInteract;
- } else {
- return mStatusBarState == StatusBarState.KEYGUARD;
- }
- }
-
@Override
protected boolean isInteractive() {
return mInteractive;
@@ -1021,18 +967,11 @@
return false;
}
- public void setController(NotificationShelfController notificationShelfController) {
- mShelfRefactor.assertInLegacyMode();
- mController = notificationShelfController;
- }
-
public void setCanModifyColorOfNotifications(boolean canModifyColorOfNotifications) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
mCanModifyColorOfNotifications = canModifyColorOfNotifications;
}
public void setCanInteract(boolean canInteract) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
mCanInteract = canInteract;
updateInteractiveness();
}
@@ -1042,15 +981,10 @@
}
private int getIndexOfViewInHostLayout(ExpandableView child) {
- if (mShelfRefactor.isEnabled()) {
- return mHostLayout.indexOfChild(child);
- } else {
- return mHostLayoutController.indexOfChild(child);
- }
+ return mHostLayout.indexOfChild(child);
}
public void requestRoundnessResetFor(ExpandableView child) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
child.requestRoundnessReset(SHELF_SCROLL);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
deleted file mode 100644
index 8a3e217..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar
-
-import android.view.View
-import android.view.View.OnClickListener
-import com.android.systemui.statusbar.notification.row.ExpandableView
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
-import com.android.systemui.statusbar.phone.NotificationIconContainer
-
-/** Controller interface for [NotificationShelf]. */
-interface NotificationShelfController {
- /** The [NotificationShelf] controlled by this Controller. */
- val view: NotificationShelf
-
- /** @see ExpandableView.getIntrinsicHeight */
- val intrinsicHeight: Int
-
- /** Container view for icons displayed in the shelf. */
- val shelfIcons: NotificationIconContainer
-
- /** Whether or not the shelf can modify the color of notifications in the shade. */
- fun canModifyColorOfNotifications(): Boolean
-
- /** Binds the shelf to the host [NotificationStackScrollLayout], via its Controller. */
- fun bind(
- ambientState: AmbientState,
- notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
- )
-
- /** @see View.setOnClickListener */
- fun setOnClickListener(listener: OnClickListener)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3a4ad0e..3bf8057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -59,7 +59,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.res.R;
-import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
+import com.android.systemui.statusbar.notification.NotificationDozeHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.util.drawable.DrawableSize;
@@ -174,7 +174,7 @@
animation.getAnimatedFraction());
setColorInternal(newColor);
};
- private final NotificationIconDozeHelper mDozer;
+ private final NotificationDozeHelper mDozer;
private int mContrastedDrawableColor;
private int mCachedContrastBackgroundColor = NO_COLOR;
private float[] mMatrix;
@@ -192,7 +192,7 @@
public StatusBarIconView(Context context, String slot, StatusBarNotification sbn,
boolean blocked) {
super(context);
- mDozer = new NotificationIconDozeHelper(context);
+ mDozer = new NotificationDozeHelper();
mBlocked = blocked;
mSlot = slot;
mNumberPain = new Paint();
@@ -712,7 +712,6 @@
setColorInternal(color);
updateContrastedStaticColor();
mIconColor = color;
- mDozer.setColor(color);
}
private void setColorInternal(int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index dc0eb7b..2f9917f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -36,26 +36,6 @@
private static final int DOZE_ANIMATOR_TAG = R.id.doze_intensity_tag;
private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
- public void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
- startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- updateGrayscale(target, (float) animation.getAnimatedValue());
- }
- }, dark, delay, new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!dark) {
- target.setColorFilter(null);
- }
- }
- });
- }
-
- public void updateGrayscale(ImageView target, boolean dark) {
- updateGrayscale(target, dark ? 1 : 0);
- }
-
public void updateGrayscale(ImageView target, float darkAmount) {
if (darkAmount > 0) {
updateGrayscaleMatrix(darkAmount);
@@ -66,7 +46,7 @@
}
// TODO: this should be using StatusBarStateController#getDozeAmount
- public void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+ private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
boolean dark, long delay, Animator.AnimatorListener listener) {
float startIntensity = dark ? 0f : 1f;
float endIntensity = dark ? 1f : 0f;
@@ -82,11 +62,6 @@
}
public void setDozing(Consumer<Float> listener, boolean dozing,
- boolean animate, long delay, View view) {
- setDozing(listener, dozing, animate, delay, view, /* endRunnable= */ null);
- }
-
- public void setDozing(Consumer<Float> listener, boolean dozing,
boolean animate, long delay, View view, @Nullable Runnable endRunnable) {
if (animate) {
startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dozing,
@@ -118,11 +93,7 @@
}
}
- public void updateGrayscaleMatrix(float intensity) {
+ private void updateGrayscaleMatrix(float intensity) {
mGrayscaleColorMatrix.setSaturation(1 - intensity);
}
-
- public ColorMatrix getGrayscaleColorMatrix() {
- return mGrayscaleColorMatrix;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
deleted file mode 100644
index 552bfb2..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
-
-import com.android.systemui.res.R;
-
-public class NotificationIconDozeHelper extends NotificationDozeHelper {
-
- private final int mImageDarkAlpha;
- private final int mImageDarkColor = 0xffffffff;
-
- @Nullable
- private PorterDuffColorFilter mImageColorFilter = null;
-
- private int mColor = Color.BLACK;
-
- public NotificationIconDozeHelper(Context ctx) {
- mImageDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
- }
-
- public void setColor(int color) {
- mColor = color;
- }
-
- public void setImageDark(ImageView target, boolean dark, boolean fade, long delay,
- boolean useGrayscale) {
- if (fade) {
- if (!useGrayscale) {
- fadeImageColorFilter(target, dark, delay);
- fadeImageAlpha(target, dark, delay);
- } else {
- fadeGrayscale(target, dark, delay);
- }
- } else {
- if (!useGrayscale) {
- updateImageColorFilter(target, dark);
- updateImageAlpha(target, dark);
- } else {
- updateGrayscale(target, dark);
- }
- }
- }
-
- private void fadeImageColorFilter(final ImageView target, boolean dark, long delay) {
- startIntensityAnimation(animation -> {
- updateImageColorFilter(target, (Float) animation.getAnimatedValue());
- }, dark, delay, null /* listener */);
- }
-
- private void fadeImageAlpha(final ImageView target, boolean dark, long delay) {
- startIntensityAnimation(animation -> {
- float t = (float) animation.getAnimatedValue();
- target.setImageAlpha((int) (255 * (1f - t) + mImageDarkAlpha * t));
- }, dark, delay, null /* listener */);
- }
-
- private void updateImageColorFilter(ImageView target, boolean dark) {
- updateImageColorFilter(target, dark ? 1f : 0f);
- }
-
- private void updateImageColorFilter(ImageView target, float intensity) {
- int color = NotificationUtils.interpolateColors(mColor, mImageDarkColor, intensity);
- if (mImageColorFilter == null || mImageColorFilter.getColor() != color) {
- mImageColorFilter = new PorterDuffColorFilter(color, Mode.SRC_ATOP);
- }
- Drawable imageDrawable = target.getDrawable();
-
- // Also, the notification might have been modified during the animation, so background
- // might be null here.
- if (imageDrawable != null) {
- Drawable d = imageDrawable.mutate();
- // DrawableContainer ignores the color filter if it's already set, so clear it first to
- // get it set and invalidated properly.
- d.setColorFilter(null);
- d.setColorFilter(mImageColorFilter);
- }
- }
-
- private void updateImageAlpha(ImageView target, boolean dark) {
- target.setImageAlpha(dark ? mImageDarkAlpha : 255);
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
index c2b6f32..5464d08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
@@ -95,7 +95,7 @@
}
override fun onViewAdded() {
- headerView?.isContentVisible = true
+ headerView?.setContentVisibleAnimated(true)
}
override val view: View
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index fa366c6..860ad63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -55,6 +55,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule;
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor;
+import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModelModule;
import com.android.systemui.statusbar.notification.icon.ConversationIconManager;
import com.android.systemui.statusbar.notification.icon.IconManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -73,7 +74,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -94,12 +94,12 @@
*/
@Module(includes = {
CoordinatorsModule.class,
+ FooterViewModelModule.class,
KeyguardNotificationVisibilityProviderModule.class,
ShadeEventsModule.class,
NotificationDataLayerModule.class,
NotifPipelineChoreographerModule.class,
NotificationSectionHeadersModule.class,
- NotificationListViewModelModule.class,
ActivatableNotificationViewModelModule.class,
NotificationMemoryModule.class,
})
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 9c51e3b..10a43d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -79,6 +79,19 @@
return findViewById(R.id.dismiss_text);
}
+ /** Whether the "Clear all" button is currently visible. */
+ public boolean isClearAllButtonVisible() {
+ return isSecondaryVisible();
+ }
+
+ /**
+ * Set the visibility of the "Clear all" button to {@code visible}. Animate the change if
+ * {@code animate} is true.
+ */
+ public void setClearAllButtonVisible(boolean visible, boolean animate) {
+ setSecondaryVisible(visible, animate);
+ }
+
@Override
public void dump(PrintWriter pwOriginal, String[] args) {
IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
@@ -293,7 +306,7 @@
super.applyToView(view);
if (view instanceof FooterView) {
FooterView footerView = (FooterView) view;
- footerView.setContentVisible(!hideContent);
+ footerView.setContentVisibleAnimated(!hideContent);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
index ffa5ff0..7390485 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -21,15 +21,15 @@
import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
-import javax.inject.Inject
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+import javax.inject.Provider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/** ViewModel for [FooterView]. */
-@SysUISingleton
-class FooterViewModel
-@Inject
-constructor(seenNotificationsInteractor: SeenNotificationsInteractor) {
+class FooterViewModel(seenNotificationsInteractor: SeenNotificationsInteractor) {
init {
/* Check if */ FooterViewRefactor.isUnexpectedlyInLegacyMode()
}
@@ -43,3 +43,18 @@
)
}
}
+
+@Module
+object FooterViewModelModule {
+ @Provides
+ @SysUISingleton
+ fun provideOptional(
+ seenNotificationsInteractor: Provider<SeenNotificationsInteractor>,
+ ): Optional<FooterViewModel> {
+ return if (FooterViewRefactor.isEnabled) {
+ Optional.of(FooterViewModel(seenNotificationsInteractor.get()))
+ } else {
+ Optional.empty()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
index 1992ea8..1bcab3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -19,11 +19,9 @@
import android.graphics.Rect
import android.view.View
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
-import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import javax.inject.Inject
@@ -42,9 +40,6 @@
/** Called by the Keyguard*ViewController whose view contains the aod icons. */
override fun setupAodIcons(aodIcons: NotificationIconContainer?) = unsupported
- override fun setupShelf(notificationShelfController: NotificationShelfController) =
- NotificationShelfViewBinderWrapperControllerImpl.unsupported
-
override fun setShelfIcons(icons: NotificationIconContainer) = unsupported
override fun onDensityOrFontScaleChanged(context: Context) = unsupported
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index db0fa99..65b798a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -251,7 +251,7 @@
val replacingIcons =
iconsDiff.groupReplacements.mapValuesNotNullTo(ArrayMap()) { (_, v) ->
- viewStore.iconView(v.notifKey)?.statusBarIcon
+ viewStore.iconView(v.notifKey).statusBarIcon
}
view.setReplacingIcons(replacingIcons)
@@ -264,7 +264,7 @@
.mapNotNull { key -> childrenByNotifKey[key] }
.forEach { child -> view.removeView(child) }
- val toAdd = iconsDiff.added.mapNotNull { viewStore.iconView(it.notifKey) }
+ val toAdd = iconsDiff.added.map { viewStore.iconView(it.notifKey) }
for ((i, sbiv) in toAdd.withIndex()) {
// The view might still be transiently added if it was just removed
// and added again
@@ -277,7 +277,7 @@
val childCount = view.childCount
for (i in 0 until childCount) {
val actual = view.getChildAt(i)
- val expected = viewStore.iconView(iconsData.visibleKeys[i].notifKey)!!
+ val expected = viewStore.iconView(iconsData.visibleKeys[i].notifKey)
if (actual === expected) {
continue
}
@@ -314,7 +314,7 @@
/** External storage for [StatusBarIconView] instances. */
fun interface IconViewStore {
- fun iconView(key: String): StatusBarIconView?
+ fun iconView(key: String): StatusBarIconView
}
@ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE
@@ -326,8 +326,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.shelfIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.shelfIcon ?: error("No shelf IconView found for key: $key")
+ }
}
/** [IconViewStore] for the always-on display. */
@@ -336,8 +338,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.aodIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.aodIcon ?: error("No AOD IconView found for key: $key")
+ }
}
/** [IconViewStore] for the status bar. */
@@ -346,8 +350,10 @@
constructor(
private val notifCollection: NotifCollection,
) : IconViewStore {
- override fun iconView(key: String): StatusBarIconView? =
- notifCollection.getEntry(key)?.icons?.statusBarIcon
+ override fun iconView(key: String): StatusBarIconView {
+ val entry = notifCollection.getEntry(key) ?: error("No entry found for key: $key")
+ return entry.icons.statusBarIcon ?: error("No status bar IconView found for key: $key")
+ }
}
private val View.viewBounds: Rect
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index aabf295..ec90a8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -39,28 +39,9 @@
private boolean mIsVisible = true;
private boolean mContentVisible = true;
private boolean mIsSecondaryVisible = true;
- private int mDuration = 260;
+ private int mAnimationDuration = 260;
private boolean mContentAnimating;
- private final Runnable mContentVisibilityEndRunnable = () -> {
- mContentAnimating = false;
- if (getVisibility() != View.GONE && !mIsVisible) {
- setVisibility(GONE);
- setWillBeGone(false);
- notifyHeightChanged(false /* needsAnimation */);
- }
- };
-
private boolean mSecondaryAnimating = false;
- private final Consumer<Boolean> mSecondaryVisibilityEndRunnable = (cancelled) -> {
- mSecondaryAnimating = false;
- // If we were on screen, become GONE to avoid touches
- if (mSecondaryView == null) return;
- if (getVisibility() != View.GONE
- && mSecondaryView.getVisibility() != View.GONE
- && !mIsSecondaryVisible) {
- mSecondaryView.setVisibility(View.GONE);
- }
- };
public StackScrollerDecorView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -72,8 +53,8 @@
super.onFinishInflate();
mContent = findContentView();
mSecondaryView = findSecondaryView();
- setVisible(false /* nowVisible */, false /* animate */);
- setSecondaryVisible(false /* nowVisible */, false /* animate */);
+ setVisible(false /* visible */, false /* animate */);
+ setSecondaryVisible(false /* visible */, false /* animate */);
setOutlineProvider(null);
}
@@ -83,95 +64,6 @@
}
/**
- * @param visible True if we should animate contents visible
- */
- public void setContentVisible(boolean visible) {
- setContentVisible(visible, true /* animate */, null /* runAfter */);
- }
-
- /**
- * @param visible True if the contents should be visible
- * @param animate True if we should fade to new visibility
- * @param runAfter Runnable to run after visibility updates
- */
- public void setContentVisible(boolean visible, boolean animate, Consumer<Boolean> runAfter) {
- if (mContentVisible != visible) {
- mContentAnimating = animate;
- mContentVisible = visible;
- Consumer<Boolean> endRunnable = (cancelled) -> {
- mContentVisibilityEndRunnable.run();
- if (runAfter != null) {
- runAfter.accept(cancelled);
- }
- };
- setViewVisible(mContent, visible, animate, endRunnable);
- } else if (runAfter != null) {
- // Execute the runAfter runnable immediately if there's no animation to perform.
- runAfter.accept(true);
- }
-
- if (!mContentAnimating) {
- mContentVisibilityEndRunnable.run();
- }
- }
-
- public boolean isContentVisible() {
- return mContentVisible;
- }
-
- /**
- * Make this view visible. If {@code false} is passed, the view will fade out it's content
- * and set the view Visibility to GONE. If only the content should be changed
- * {@link #setContentVisible(boolean)} can be used.
- *
- * @param nowVisible should the view be visible
- * @param animate should the change be animated.
- */
- public void setVisible(boolean nowVisible, boolean animate) {
- if (mIsVisible != nowVisible) {
- mIsVisible = nowVisible;
- if (animate) {
- if (nowVisible) {
- setVisibility(VISIBLE);
- setWillBeGone(false);
- notifyHeightChanged(false /* needsAnimation */);
- } else {
- setWillBeGone(true);
- }
- setContentVisible(nowVisible, true /* animate */, null /* runAfter */);
- } else {
- setVisibility(nowVisible ? VISIBLE : GONE);
- setContentVisible(nowVisible, false /* animate */, null /* runAfter */);
- setWillBeGone(false);
- notifyHeightChanged(false /* needsAnimation */);
- }
- }
- }
-
- /**
- * Set the secondary view of this layout to visible.
- *
- * @param nowVisible should the secondary view be visible
- * @param animate should the change be animated
- */
- public void setSecondaryVisible(boolean nowVisible, boolean animate) {
- if (mIsSecondaryVisible != nowVisible) {
- mSecondaryAnimating = animate;
- mIsSecondaryVisible = nowVisible;
- setViewVisible(mSecondaryView, nowVisible, animate, mSecondaryVisibilityEndRunnable);
- }
-
- if (!mSecondaryAnimating) {
- mSecondaryVisibilityEndRunnable.accept(true /* cancelled */);
- }
- }
-
- @VisibleForTesting
- public boolean isSecondaryVisible() {
- return mIsSecondaryVisible;
- }
-
- /**
* Is this view visible. If a view is currently animating to gone, it will
* return {@code false}.
*/
@@ -179,20 +71,128 @@
return mIsVisible;
}
- @VisibleForTesting
- public void setDuration(int duration) {
- mDuration = duration;
+ /**
+ * Make this view visible. If {@code false} is passed, the view will fade out its content
+ * and set the view Visibility to GONE. If only the content should be changed,
+ * {@link #setContentVisibleAnimated(boolean)} can be used.
+ *
+ * @param visible True if the contents should be visible.
+ * @param animate True if we should fade to new visibility.
+ */
+ public void setVisible(boolean visible, boolean animate) {
+ if (mIsVisible != visible) {
+ mIsVisible = visible;
+ if (animate) {
+ if (visible) {
+ setVisibility(VISIBLE);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ } else {
+ setWillBeGone(true);
+ }
+ setContentVisible(visible, true /* animate */, null /* onAnimationEnded */);
+ } else {
+ setVisibility(visible ? VISIBLE : GONE);
+ setContentVisible(visible, false /* animate */, null /* onAnimationEnded */);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ }
+ }
+
+ public boolean isContentVisible() {
+ return mContentVisible;
+ }
+
+ /**
+ * Change content visibility to {@code visible}, animated.
+ */
+ public void setContentVisibleAnimated(boolean visible) {
+ setContentVisible(visible, true /* animate */, null /* onAnimationEnded */);
+ }
+
+ /**
+ * @param visible True if the contents should be visible.
+ * @param animate True if we should fade to new visibility.
+ * @param onAnimationEnded Callback to run after visibility updates, takes a boolean as a
+ * parameter that represents whether the animation was cancelled.
+ */
+ public void setContentVisible(boolean visible, boolean animate,
+ Consumer<Boolean> onAnimationEnded) {
+ if (mContentVisible != visible) {
+ mContentAnimating = animate;
+ mContentVisible = visible;
+ Consumer<Boolean> onAnimationEndedWrapper = (cancelled) -> {
+ onContentVisibilityAnimationEnd();
+ if (onAnimationEnded != null) {
+ onAnimationEnded.accept(cancelled);
+ }
+ };
+ setViewVisible(mContent, visible, animate, onAnimationEndedWrapper);
+ } else if (onAnimationEnded != null) {
+ // Execute onAnimationEnded immediately if there's no animation to perform.
+ onAnimationEnded.accept(true /* cancelled */);
+ }
+
+ if (!mContentAnimating) {
+ onContentVisibilityAnimationEnd();
+ }
+ }
+
+ private void onContentVisibilityAnimationEnd() {
+ mContentAnimating = false;
+ if (getVisibility() != View.GONE && !mIsVisible) {
+ setVisibility(GONE);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ }
+
+ protected boolean isSecondaryVisible() {
+ return mIsSecondaryVisible;
+ }
+
+ /**
+ * Set the secondary view of this layout to visible.
+ *
+ * @param visible should the secondary view be visible
+ * @param animate should the change be animated
+ */
+ protected void setSecondaryVisible(boolean visible, boolean animate) {
+ if (mIsSecondaryVisible != visible) {
+ mSecondaryAnimating = animate;
+ mIsSecondaryVisible = visible;
+ setViewVisible(mSecondaryView, visible, animate,
+ (cancelled) -> onSecondaryVisibilityAnimationEnd());
+ }
+
+ if (!mSecondaryAnimating) {
+ onSecondaryVisibilityAnimationEnd();
+ }
+ }
+
+ private void onSecondaryVisibilityAnimationEnd() {
+ mSecondaryAnimating = false;
+ // If we were on screen, become GONE to avoid touches
+ if (mSecondaryView == null) return;
+ if (getVisibility() != View.GONE
+ && mSecondaryView.getVisibility() != View.GONE
+ && !mIsSecondaryVisible) {
+ mSecondaryView.setVisibility(View.GONE);
+ }
}
/**
* Animate a view to a new visibility.
- * @param view Target view, maybe content view or dismiss view.
- * @param nowVisible Should it now be visible.
- * @param animate Should this be done in an animated way.
- * @param endRunnable A runnable that is run when the animation is done.
+ *
+ * @param view Target view, maybe content view or dismiss view.
+ * @param visible Should it now be visible.
+ * @param animate Should this be done in an animated way.
+ * @param onAnimationEnded Callback to run after visibility updates, takes a boolean as a
+ * parameter that represents whether the animation was cancelled.
*/
- private void setViewVisible(View view, boolean nowVisible,
- boolean animate, Consumer<Boolean> endRunnable) {
+ private void setViewVisible(View view, boolean visible,
+ boolean animate, Consumer<Boolean> onAnimationEnded) {
if (view == null) {
return;
}
@@ -204,21 +204,21 @@
// cancel any previous animations
view.animate().cancel();
- float endValue = nowVisible ? 1.0f : 0.0f;
+ float endValue = visible ? 1.0f : 0.0f;
if (!animate) {
view.setAlpha(endValue);
- if (endRunnable != null) {
- endRunnable.accept(true);
+ if (onAnimationEnded != null) {
+ onAnimationEnded.accept(true);
}
return;
}
// Animate the view alpha
- Interpolator interpolator = nowVisible ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT;
+ Interpolator interpolator = visible ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT;
view.animate()
.alpha(endValue)
.setInterpolator(interpolator)
- .setDuration(mDuration)
+ .setDuration(mAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
boolean mCancelled;
@@ -229,11 +229,16 @@
@Override
public void onAnimationEnd(Animator animation) {
- endRunnable.accept(mCancelled);
+ onAnimationEnded.accept(mCancelled);
}
});
}
+ @VisibleForTesting
+ public void setAnimationDuration(int animationDuration) {
+ mAnimationDuration = animationDuration;
+ }
+
@Override
public long performRemoveAnimation(long duration, long delay,
float translationDirection, boolean isHeadsUpAnimation,
@@ -251,14 +256,14 @@
@Override
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
// TODO: use delay and duration
- setContentVisible(true);
+ setContentVisibleAnimated(true);
}
@Override
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear,
Runnable endRunnable) {
// TODO: use delay and duration
- setContentVisible(true);
+ setContentVisibleAnimated(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java
deleted file mode 100644
index 98cd84d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java
+++ /dev/null
@@ -1,61 +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.statusbar.notification.row.dagger;
-
-import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl;
-import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
-
-import dagger.Binds;
-import dagger.BindsInstance;
-import dagger.Module;
-import dagger.Subcomponent;
-
-/**
- * Dagger subcomponent for NotificationShelf.
- */
-@Subcomponent(modules = {ActivatableNotificationViewModule.class,
- NotificationShelfComponent.NotificationShelfModule.class})
-@NotificationRowScope
-public interface NotificationShelfComponent {
- /**
- * Builder for {@link NotificationShelfComponent}.
- */
- @Subcomponent.Builder
- interface Builder {
- @BindsInstance
- Builder notificationShelf(NotificationShelf view);
- NotificationShelfComponent build();
- }
-
- /**
- * Creates a NotificationShelfController.
- */
- @NotificationRowScope
- LegacyNotificationShelfControllerImpl getNotificationShelfController();
-
- /**
- * Dagger Module that extracts interesting properties from a NotificationShelf.
- */
- @Module
- abstract class NotificationShelfModule {
-
- /** NotificationShelf is provided as an instance of ActivatableNotificationView. */
- @Binds
- abstract ActivatableNotificationView bindNotificationShelf(NotificationShelf view);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/AsyncHybridViewInflation.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/AsyncHybridViewInflation.kt
new file mode 100644
index 0000000..24e7f05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/AsyncHybridViewInflation.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the async hybrid view inflation flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object AsyncHybridViewInflation {
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_ASYNC_HYBRID_VIEW_INFLATION
+
+ /** Is async hybrid (single-line) view inflation enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationAsyncHybridViewInflation()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
new file mode 100644
index 0000000..44387c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the notifications live data store refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationsLiveDataStoreRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATIONS_LIVE_DATA_STORE_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationsLiveDataStoreRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index d35e4b5..7667e17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -16,64 +16,22 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewbinder
-import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.ConfigurationState
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
import com.android.systemui.statusbar.NotificationShelf
-import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ShelfNotificationIconViewStore
import com.android.systemui.statusbar.notification.row.ui.viewbinder.ActivatableNotificationViewBinder
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
-import com.android.systemui.statusbar.notification.stack.AmbientState
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
-import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.policy.ConfigurationController
-import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch
-/**
- * Controller class for [NotificationShelf]. This implementation serves as a temporary wrapper
- * around a [NotificationShelfViewBinder], so that external code can continue to depend on the
- * [NotificationShelfController] interface. Once the [LegacyNotificationShelfControllerImpl] is
- * removed, this class can go away and the ViewBinder can be used directly.
- */
-@SysUISingleton
-class NotificationShelfViewBinderWrapperControllerImpl @Inject constructor() :
- NotificationShelfController {
-
- override val view: NotificationShelf
- get() = unsupported
-
- override val intrinsicHeight: Int
- get() = unsupported
-
- override val shelfIcons: NotificationIconContainer
- get() = unsupported
-
- override fun canModifyColorOfNotifications(): Boolean = unsupported
-
- override fun bind(
- ambientState: AmbientState,
- notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
- ) = unsupported
-
- override fun setOnClickListener(listener: View.OnClickListener) = unsupported
-
- companion object {
- val unsupported: Nothing
- get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
- }
-}
-
/** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */
object NotificationShelfViewBinder {
fun bind(
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 1774000..a0ad560 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
@@ -98,7 +98,6 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
@@ -203,7 +202,6 @@
private final boolean mDebugRemoveAnimation;
private final boolean mSensitiveRevealAnimEndabled;
private final RefactorFlag mAnimatedInsets;
- private final RefactorFlag mShelfRefactor;
private final boolean mNewAodTransition;
@@ -639,7 +637,6 @@
mSensitiveRevealAnimEndabled = mFeatureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
mAnimatedInsets =
new RefactorFlag(mFeatureFlags, Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
- mShelfRefactor = new RefactorFlag(mFeatureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
mScreenOffAnimationController =
Dependency.get(ScreenOffAnimationController.class);
@@ -2734,15 +2731,6 @@
mChildTransferInProgress = childTransferInProgress;
}
- /**
- * Set the remove notification listener
- * @param listener callback for notification removed
- */
- public void setOnNotificationRemovedListener(OnNotificationRemovedListener listener) {
- mShelfRefactor.assertInLegacyMode();
- mOnNotificationRemovedListener = listener;
- }
-
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
@@ -2752,15 +2740,7 @@
if (!mChildTransferInProgress) {
onViewRemovedInternal(expandableView, this);
}
- if (mShelfRefactor.isEnabled()) {
- mShelf.requestRoundnessResetFor(expandableView);
- } else {
- if (mOnNotificationRemovedListener != null) {
- mOnNotificationRemovedListener.onNotificationRemoved(
- expandableView,
- mChildTransferInProgress);
- }
- }
+ mShelf.requestRoundnessResetFor(expandableView);
}
public void cleanUpViewStateForEntry(NotificationEntry entry) {
@@ -4573,7 +4553,7 @@
mFooterClearAllListener.onClearAll();
}
clearNotifications(ROWS_ALL, true /* closeShade */);
- footerView.setSecondaryVisible(false /* visible */, true /* animate */);
+ footerView.setClearAllButtonVisible(false /* visible */, true /* animate */);
});
if (FooterViewRefactor.isEnabled()) {
updateFooter();
@@ -4638,7 +4618,7 @@
}
boolean animate = mIsExpanded && mAnimationsEnabled;
mFooterView.setVisible(visible, animate);
- mFooterView.setSecondaryVisible(showDismissView, animate);
+ mFooterView.setClearAllButtonVisible(showDismissView, animate);
mFooterView.showHistory(showHistory);
if (!FooterViewRefactor.isEnabled()) {
mFooterView.setFooterLabelVisible(mHasFilteredOutSeenNotifications);
@@ -4987,12 +4967,10 @@
@Nullable
public ExpandableView getShelf() {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return null;
return mShelf;
}
public void setShelf(NotificationShelf shelf) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
int index = -1;
if (mShelf != null) {
index = indexOfChild(mShelf);
@@ -5005,20 +4983,6 @@
shelf.bind(mAmbientState, this, mController.getNotificationRoundnessManager());
}
- public void setShelfController(NotificationShelfController notificationShelfController) {
- mShelfRefactor.assertInLegacyMode();
- int index = -1;
- if (mShelf != null) {
- index = indexOfChild(mShelf);
- removeView(mShelf);
- }
- mShelf = notificationShelfController.getView();
- addView(mShelf, index);
- mAmbientState.setShelf(mShelf);
- mStateAnimator.setShelf(mShelf);
- notificationShelfController.bind(mAmbientState, mController);
- }
-
public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
mMaxDisplayedNotifications = maxDisplayedNotifications;
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 21efd63..44140b9 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
@@ -18,7 +18,6 @@
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
@@ -65,7 +64,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.RefactorFlag;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -84,7 +82,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -119,12 +116,10 @@
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
-import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -140,7 +135,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -168,12 +162,10 @@
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
- private final Optional<NotificationListViewModel> mViewModel;
private final DumpManager mDumpManager;
private final FalsingCollector mFalsingCollector;
private final FalsingManager mFalsingManager;
- private final Resources mResources;
private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
private final ScrimController mScrimController;
private final NotifPipeline mNotifPipeline;
@@ -194,10 +186,8 @@
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
- private final NotificationIconAreaController mNotifIconAreaController;
private final GroupExpansionManager mGroupExpansionManager;
- private final NotifPipelineFlags mNotifPipelineFlags;
private final SeenNotificationsInteractor mSeenNotificationsInteractor;
private final KeyguardTransitionRepository mKeyguardTransitionRepo;
@@ -211,13 +201,10 @@
private boolean mIsInTransitionToAod = false;
private final FeatureFlagsClassic mFeatureFlags;
- private final RefactorFlag mShelfRefactor;
private final NotificationTargetsHelper mNotificationTargetsHelper;
private final SecureSettings mSecureSettings;
private final NotificationDismissibilityProvider mDismissibilityProvider;
private final ActivityStarter mActivityStarter;
- private final ConfigurationState mConfigurationState;
- private final ShelfNotificationIconViewStore mShelfIconViewStore;
private View mLongPressedView;
@@ -316,6 +303,8 @@
private NotifStats mNotifStats = NotifStats.getEmpty();
+ private final NotificationListViewBinder mViewBinder;
+
private void updateResources() {
mNotificationStackSizeCalculator.updateResources();
}
@@ -651,40 +640,36 @@
KeyguardTransitionRepository keyguardTransitionRepo,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
- Optional<NotificationListViewModel> nsslViewModel,
MetricsLogger metricsLogger,
DumpManager dumpManager,
FalsingCollector falsingCollector,
FalsingManager falsingManager,
- @Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
ScrimController scrimController,
GroupExpansionManager groupManager,
@SilentHeader SectionHeaderController silentHeaderController,
NotifPipeline notifPipeline,
- NotifPipelineFlags notifPipelineFlags,
NotifCollection notifCollection,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
UiEventLogger uiEventLogger,
NotificationRemoteInputManager remoteInputManager,
VisibilityLocationProviderDelegator visibilityLocationProviderDelegator,
SeenNotificationsInteractor seenNotificationsInteractor,
+ NotificationListViewBinder viewBinder,
ShadeController shadeController,
InteractionJankMonitor jankMonitor,
StackStateLogger stackLogger,
NotificationStackScrollLogger logger,
NotificationStackSizeCalculator notificationStackSizeCalculator,
- NotificationIconAreaController notifIconAreaController,
FeatureFlagsClassic featureFlags,
NotificationTargetsHelper notificationTargetsHelper,
SecureSettings secureSettings,
NotificationDismissibilityProvider dismissibilityProvider,
ActivityStarter activityStarter,
- SplitShadeStateController splitShadeStateController,
- ConfigurationState configurationState,
- ShelfNotificationIconViewStore shelfIconViewStore) {
+ SplitShadeStateController splitShadeStateController) {
mView = view;
mKeyguardTransitionRepo = keyguardTransitionRepo;
+ mViewBinder = viewBinder;
mStackStateLogger = stackLogger;
mLogger = logger;
mAllowLongPress = allowLongPress;
@@ -704,13 +689,11 @@
mPrimaryBouncerInteractor = primaryBouncerInteractor;
mZenModeController = zenModeController;
mLockscreenUserManager = lockscreenUserManager;
- mViewModel = nsslViewModel;
mMetricsLogger = metricsLogger;
mDumpManager = dumpManager;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
- mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
@@ -718,22 +701,17 @@
mGroupExpansionManager = groupManager;
mSilentHeaderController = silentHeaderController;
mNotifPipeline = notifPipeline;
- mNotifPipelineFlags = notifPipelineFlags;
mNotifCollection = notifCollection;
mUiEventLogger = uiEventLogger;
mRemoteInputManager = remoteInputManager;
mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator;
mSeenNotificationsInteractor = seenNotificationsInteractor;
mShadeController = shadeController;
- mNotifIconAreaController = notifIconAreaController;
mFeatureFlags = featureFlags;
- mShelfRefactor = new RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
mNotificationTargetsHelper = notificationTargetsHelper;
mSecureSettings = secureSettings;
mDismissibilityProvider = dismissibilityProvider;
mActivityStarter = activityStarter;
- mConfigurationState = configurationState;
- mShelfIconViewStore = shelfIconViewStore;
mView.passSplitShadeStateController(splitShadeStateController);
updateResources();
setUpView();
@@ -840,12 +818,7 @@
mGroupExpansionManager.registerGroupExpansionChangeListener(
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
- mViewModel.ifPresent(
- vm -> NotificationListViewBinder
- .bind(mView, vm, mConfigurationState, mConfigurationController,
- mFalsingManager,
- mNotifIconAreaController,
- mShelfIconViewStore));
+ mViewBinder.bind(mView);
collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
this::onKeyguardTransitionChanged);
@@ -1443,11 +1416,6 @@
mView.runAfterAnimationFinished(r);
}
- public void setShelfController(NotificationShelfController notificationShelfController) {
- mShelfRefactor.assertInLegacyMode();
- mView.setShelfController(notificationShelfController);
- }
-
public ExpandableView getFirstChildNotGone() {
return mView.getFirstChildNotGone();
}
@@ -1647,24 +1615,11 @@
return mNotificationTargetsHelper;
}
- /**
- * Set the remove notification listener
- * @param listener callback for notification removed
- */
- public void setOnNotificationRemovedListener(
- NotificationStackScrollLayout.OnNotificationRemovedListener listener) {
- mView.setOnNotificationRemovedListener(listener);
- }
-
public void setShelf(NotificationShelf shelf) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
mView.setShelf(shelf);
}
public int getShelfHeight() {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) {
- return 0;
- }
ExpandableView shelf = mView.getShelf();
return shelf == null ? 0 : shelf.getIntrinsicHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index 5c1149b..580431a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -53,7 +53,7 @@
mContents = requireViewById(R.id.content);
bindContents();
super.onFinishInflate();
- setVisible(true /* nowVisible */, false /* animate */);
+ setVisible(true /* visible */, false /* animate */);
}
private void bindContents() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index af2ca26..d55c0de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -32,48 +32,33 @@
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.policy.ConfigurationController
+import javax.inject.Inject
/** Binds a [NotificationStackScrollLayout] to its [view model][NotificationListViewModel]. */
-object NotificationListViewBinder {
- @JvmStatic
- fun bind(
- view: NotificationStackScrollLayout,
- viewModel: NotificationListViewModel,
- configuration: ConfigurationState,
- configurationController: ConfigurationController,
- falsingManager: FalsingManager,
- iconAreaController: NotificationIconAreaController,
- shelfIconViewStore: ShelfNotificationIconViewStore,
- ) {
- bindShelf(
- view,
- viewModel,
- configuration,
- configurationController,
- falsingManager,
- iconAreaController,
- shelfIconViewStore
- )
+class NotificationListViewBinder
+@Inject
+constructor(
+ private val viewModel: NotificationListViewModel,
+ private val configuration: ConfigurationState,
+ private val configurationController: ConfigurationController,
+ private val falsingManager: FalsingManager,
+ private val iconAreaController: NotificationIconAreaController,
+ private val shelfIconViewStore: ShelfNotificationIconViewStore,
+) {
- bindFooter(view, viewModel, configuration)
+ fun bind(view: NotificationStackScrollLayout) {
+ bindShelf(view)
+ bindFooter(view)
}
- private fun bindShelf(
- parentView: NotificationStackScrollLayout,
- parentViewModel: NotificationListViewModel,
- configuration: ConfigurationState,
- configurationController: ConfigurationController,
- falsingManager: FalsingManager,
- iconAreaController: NotificationIconAreaController,
- shelfIconViewStore: ShelfNotificationIconViewStore
- ) {
+ private fun bindShelf(parentView: NotificationStackScrollLayout) {
val shelf =
LayoutInflater.from(parentView.context)
.inflate(R.layout.status_bar_notification_shelf, parentView, false)
as NotificationShelf
NotificationShelfViewBinder.bind(
shelf,
- parentViewModel.shelf,
+ viewModel.shelf,
configuration,
configurationController,
falsingManager,
@@ -83,12 +68,8 @@
parentView.setShelf(shelf)
}
- private fun bindFooter(
- parentView: NotificationStackScrollLayout,
- parentViewModel: NotificationListViewModel,
- configuration: ConfigurationState
- ) {
- parentViewModel.footer.ifPresent { footerViewModel ->
+ private fun bindFooter(parentView: NotificationStackScrollLayout) {
+ viewModel.footer.ifPresent { footerViewModel ->
// The footer needs to be re-inflated every time the theme or the font size changes.
parentView.repeatWhenAttached {
configuration.reinflateAndBindLatest(
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 261371d..f01245f 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
@@ -16,55 +16,15 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
-import dagger.Module
-import dagger.Provides
import java.util.Optional
-import javax.inject.Provider
+import javax.inject.Inject
/** ViewModel for the list of notifications. */
-class NotificationListViewModel(
+class NotificationListViewModel
+@Inject
+constructor(
val shelf: NotificationShelfViewModel,
val footer: Optional<FooterViewModel>,
)
-
-@Module
-object NotificationListViewModelModule {
- @JvmStatic
- @Provides
- @SysUISingleton
- fun maybeProvideViewModel(
- featureFlags: FeatureFlagsClassic,
- shelfViewModel: Provider<NotificationShelfViewModel>,
- footerViewModel: Provider<FooterViewModel>,
- ): Optional<NotificationListViewModel> {
- return if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- if (com.android.systemui.Flags.notificationsFooterViewRefactor()) {
- Optional.of(
- NotificationListViewModel(
- shelfViewModel.get(),
- Optional.of(footerViewModel.get())
- )
- )
- } else {
- Optional.of(NotificationListViewModel(shelfViewModel.get(), Optional.empty()))
- }
- } else {
- if (com.android.systemui.Flags.notificationsFooterViewRefactor()) {
- throw IllegalStateException(
- "The com.android.systemui.notifications_footer_view_refactor flag requires " +
- "the notification_shelf_refactor flag to be enabled. First disable the " +
- "footer flag using `adb shell device_config put systemui " +
- "com.android.systemui.notifications_footer_view_refactor false`, then " +
- "enable the notification_shelf_refactor flag in Flag Flipper. " +
- "Afterwards, you can try re-enabling the footer refactor flag via adb."
- )
- }
- Optional.empty()
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegate.kt
new file mode 100644
index 0000000..6211e17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AlertDialogWithDelegate.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.app.AlertDialog
+import android.content.Context
+import android.content.res.Configuration
+import android.os.Bundle
+import android.view.ViewRootImpl
+import android.view.ViewRootImpl.ConfigChangedCallback
+import androidx.annotation.StyleRes
+
+/**
+ * Implementation of [AlertDialog] that takes as parameter a [DialogDelegate].
+ *
+ * Can be used when composition is preferred over inheritance.
+ */
+class AlertDialogWithDelegate(
+ context: Context,
+ @StyleRes theme: Int,
+ private val delegate: DialogDelegate<AlertDialog>
+) : AlertDialog(context, theme), ConfigChangedCallback {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ delegate.beforeCreate(dialog = this, savedInstanceState)
+ super.onCreate(savedInstanceState)
+ delegate.onCreate(dialog = this, savedInstanceState)
+ }
+
+ override fun onConfigurationChanged(configuration: Configuration) {
+ delegate.onConfigurationChanged(dialog = this, configuration)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ ViewRootImpl.addConfigCallback(this)
+ delegate.onStart(dialog = this)
+ }
+
+ override fun onStop() {
+ super.onStop()
+ ViewRootImpl.removeConfigCallback(this)
+ delegate.onStop(dialog = this)
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ delegate.onWindowFocusChanged(dialog = this, hasFocus)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 897bb42..2e5717d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -190,7 +190,6 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PowerButtonReveal;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
@@ -643,7 +642,6 @@
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewControllerLazy,
- NotificationShelfController notificationShelfController,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
// Lazys due to b/298099682.
Lazy<NotificationPresenter> notificationPresenterLazy,
@@ -750,7 +748,6 @@
mConfigurationController = configurationController;
mNotificationShadeWindowController = notificationShadeWindowController;
mNotificationShadeWindowViewControllerLazy = notificationShadeWindowViewControllerLazy;
- mNotificationShelfController = notificationShelfController;
mStackScrollerController = notificationStackScrollLayoutController;
mStackScroller = mStackScrollerController.getView();
mNotifListContainer = mStackScrollerController.getNotificationListContainer();
@@ -1152,9 +1149,6 @@
// TODO: Deal with the ugliness that comes from having some of the status bar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
- if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- mNotificationIconAreaController.setupShelf(mNotificationShelfController);
- }
ShadeExpansionChangeEvent currentState =
mShadeExpansionStateManager.addExpansionListener(mWakeUpCoordinator);
mWakeUpCoordinator.onPanelExpansionChanged(currentState);
@@ -1249,7 +1243,6 @@
this,
mGestureRec,
mShadeController::makeExpandedInvisible,
- mNotificationShelfController,
mHeadsUpManager);
// Set up the quick settings tile panel
@@ -2869,8 +2862,6 @@
protected Display mDisplay;
private int mDisplayId;
- private final NotificationShelfController mNotificationShelfController;
-
private final Lazy<AssistManager> mAssistManagerLazy;
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DialogDelegate.kt
new file mode 100644
index 0000000..b56baee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DialogDelegate.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.app.Dialog
+import android.content.res.Configuration
+import android.os.Bundle
+import android.view.ViewRootImpl
+
+/**
+ * A delegate class that should be implemented in place of subclassing [Dialog].
+ *
+ * To use with [SystemUIDialog], implement this interface and then pass an instance of your
+ * implementation to [SystemUIDialog.Factory.create].
+ */
+interface DialogDelegate<T : Dialog> {
+ /** Called before [Dialog.onCreate] is called. */
+ fun beforeCreate(dialog: T, savedInstanceState: Bundle?) {}
+
+ /** Called after [Dialog.onCreate] is called. */
+ fun onCreate(dialog: T, savedInstanceState: Bundle?) {}
+
+ /** Called after [Dialog.onStart] is called. */
+ fun onStart(dialog: T) {}
+
+ /** Called after [Dialog.onStop] is called. */
+ fun onStop(dialog: T) {}
+
+ /** Called after [Dialog.onWindowFocusChanged] is called. */
+ fun onWindowFocusChanged(dialog: T, hasFocus: Boolean) {}
+
+ /** Called as part of [ViewRootImpl.ConfigChangedCallback.onConfigurationChanged]. */
+ fun onConfigurationChanged(dialog: T, configuration: Configuration) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index 649a4ac..3b3d8b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -41,7 +41,6 @@
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.flags.RefactorFlag;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -49,7 +48,6 @@
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -109,8 +107,6 @@
private final ArrayList<Rect> mTintAreas = new ArrayList<>();
private final Context mContext;
- private final RefactorFlag mShelfRefactor;
-
private final boolean mNewAodTransition;
private int mAodIconAppearTranslation;
@@ -150,7 +146,6 @@
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mStatusBarStateController = statusBarStateController;
- mShelfRefactor = new RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR);
mNewAodTransition = featureFlags.isEnabled(NEW_AOD_TRANSITION);
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
@@ -204,13 +199,7 @@
updateIconLayoutParams(mContext);
}
- public void setupShelf(NotificationShelfController notificationShelfController) {
- mShelfRefactor.assertInLegacyMode();
- mShelfIcons = notificationShelfController.getShelfIcons();
- }
-
public void setShelfIcons(NotificationIconContainer icons) {
- if (mShelfRefactor.isUnexpectedlyInLegacyMode()) return;
mShelfIcons = icons;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
index 2823b28..4385a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
@@ -18,7 +18,6 @@
import android.content.Context
import android.graphics.Rect
import android.view.View
-import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -29,7 +28,6 @@
interface NotificationIconAreaController {
/** Called by the Keyguard*ViewController whose view contains the aod icons. */
fun setupAodIcons(aodIcons: NotificationIconContainer?)
- fun setupShelf(notificationShelfController: NotificationShelfController)
fun setShelfIcons(icons: NotificationIconContainer)
fun onDensityOrFontScaleChanged(context: Context)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 75a697f..01f3b63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -132,13 +132,16 @@
}
}.setDuration(CONTENT_FADE_DURATION);
+ // TODO(b/278765923): Replace these with domain-agnostic state
/* Maximum number of icons on AOD when also showing overflow dot. */
private int mMaxIconsOnAod;
-
/* Maximum number of icons in short shelf on lockscreen when also showing overflow dot. */
private int mMaxIconsOnLockscreen;
/* Maximum number of icons in the status bar when also showing overflow dot. */
private int mMaxStaticIcons;
+ private boolean mDozing;
+ private boolean mOnLockScreen;
+ private boolean mOverrideIconColor;
private boolean mIsStaticLayout = true;
private final HashMap<View, IconState> mIconStates = new HashMap<>();
@@ -147,9 +150,6 @@
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
private float mActualPaddingStart = NO_VALUE;
- private boolean mDozing;
- private boolean mOnLockScreen;
- private boolean mInNotificationIconShelf;
private boolean mChangingViewPositions;
private int mAddAnimationStartIndex = -1;
private int mCannedAnimationStartIndex = -1;
@@ -284,7 +284,7 @@
public String toString() {
return "NotificationIconContainer("
+ "dozing=" + mDozing + " onLockScreen=" + mOnLockScreen
- + " inNotificationIconShelf=" + mInNotificationIconShelf
+ + " overrideIconColor=" + mOverrideIconColor
+ " speedBumpIndex=" + mSpeedBumpIndex
+ " themedTextColorPrimary=#" + Integer.toHexString(mThemedTextColorPrimary) + ')';
}
@@ -739,8 +739,15 @@
mOnLockScreen = onLockScreen;
}
+ @Deprecated
public void setInNotificationIconShelf(boolean inShelf) {
- mInNotificationIconShelf = inShelf;
+ NotificationIconContainerRefactor.assertInLegacyMode();
+ mOverrideIconColor = inShelf;
+ }
+
+ public void setOverrideIconColor(boolean override) {
+ if (NotificationIconContainerRefactor.isUnexpectedlyInLegacyMode()) return;
+ mOverrideIconColor = override;
}
public class IconState extends ViewState {
@@ -858,7 +865,7 @@
}
}
icon.setVisibleState(visibleState, animationsAllowed);
- icon.setIconColor(mInNotificationIconShelf ? mThemedTextColorPrimary : iconColor,
+ icon.setIconColor(mOverrideIconColor ? mThemedTextColorPrimary : iconColor,
needsCannedAnimation && animationsAllowed);
if (animate) {
animateTo(icon, animationProperties);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 2558645..824de01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -42,13 +42,13 @@
import androidx.annotation.Nullable;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.res.R;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.util.DialogKt;
@@ -60,7 +60,7 @@
/**
* Class for dialogs that should appear over panels and keyguard.
*
- * DO NOT SUBCLASS THIS. See {@link SystemUIDialog.Delegate} for an interface that enables
+ * DO NOT SUBCLASS THIS. See {@link DialogDelegate} for an interface that enables
* customizing behavior via composition instead of inheritance. Clients should implement the
* Delegate class and then pass their implementation into the SystemUIDialog constructor.
*
@@ -79,7 +79,7 @@
private final Context mContext;
private final FeatureFlags mFeatureFlags;
- private final Delegate mDelegate;
+ private final DialogDelegate<SystemUIDialog> mDelegate;
@Nullable private final DismissReceiver mDismissReceiver;
private final Handler mHandler = new Handler();
private final SystemUIDialogManager mDialogManager;
@@ -110,7 +110,7 @@
Dependency.get(SysUiState.class),
Dependency.get(BroadcastDispatcher.class),
Dependency.get(DialogLaunchAnimator.class),
- new Delegate() {});
+ new DialogDelegate<>() {});
}
@Inject
@@ -129,7 +129,7 @@
sysUiState,
broadcastDispatcher,
dialogLaunchAnimator,
- new Delegate(){});
+ new DialogDelegate<>(){});
}
public static class Factory {
@@ -156,7 +156,11 @@
mDialogLaunchAnimator = dialogLaunchAnimator;
}
- public SystemUIDialog create(Delegate delegate) {
+ /**
+ * Creates a new instance of {@link SystemUIDialog} with {@code delegate} as the {@link
+ * DialogDelegate}.
+ */
+ public SystemUIDialog create(DialogDelegate<SystemUIDialog> delegate) {
return new SystemUIDialog(
mContext,
DEFAULT_THEME,
@@ -188,7 +192,7 @@
sysUiState,
broadcastDispatcher,
dialogLaunchAnimator,
- new Delegate(){});
+ new DialogDelegate<>(){});
}
public SystemUIDialog(
@@ -200,7 +204,7 @@
SysUiState sysUiState,
BroadcastDispatcher broadcastDispatcher,
DialogLaunchAnimator dialogLaunchAnimator,
- Delegate delegate) {
+ DialogDelegate<SystemUIDialog> delegate) {
super(context, theme);
mContext = context;
mFeatureFlags = featureFlags;
@@ -309,7 +313,7 @@
* should override this method instead.
*/
protected void start() {
- mDelegate.start(this);
+ mDelegate.onStart(this);
}
@Override
@@ -333,7 +337,7 @@
* should override this method instead.
*/
protected void stop() {
- mDelegate.stop(this);
+ mDelegate.onStop(this);
}
@Override
@@ -584,43 +588,4 @@
mDialog.dismiss();
}
}
-
- /**
- * A delegate class that should be implemented in place of sublcassing {@link SystemUIDialog}.
- *
- * Implement this interface and then pass an instance of your implementation to
- * {@link SystemUIDialog.Factory#create(Delegate)}.
- */
- public interface Delegate {
- /**
- * Called before {@link AlertDialog#onCreate} is called.
- */
- default void beforeCreate(SystemUIDialog dialog, Bundle savedInstanceState) {}
-
- /**
- * Called after {@link AlertDialog#onCreate} is called.
- */
- default void onCreate(SystemUIDialog dialog, Bundle savedInstanceState) {}
-
- /**
- * Called after {@link AlertDialog#onStart} is called.
- */
- default void start(SystemUIDialog dialog) {}
-
- /**
- * Called after {@link AlertDialog#onStop} is called.
- */
- default void stop(SystemUIDialog dialog) {}
-
- /**
- * Called after {@link AlertDialog#onWindowFocusChanged(boolean)} is called.
- */
- default void onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus) {}
-
- /**
- * Called as part of
- * {@link ViewRootImpl.ConfigChangedCallback#onConfigurationChanged(Configuration)}.
- */
- default void onConfigurationChanged(SystemUIDialog dialog, Configuration configuration) {}
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 771a8c8..799e5af 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -48,6 +48,8 @@
import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
import com.android.systemui.tuner.ShortcutParser.Shortcut;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
import java.util.ArrayList;
import java.util.Map;
@@ -69,6 +71,9 @@
private TunerService mTunerService;
private Handler mHandler;
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.lockscreen_settings`. See b/120445169.
+ @UsesReflection(@KeepTarget(classConstant = ShortcutPicker.class))
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
mTunerService = Dependency.get(TunerService.class);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
index 32b1b26..8d85999 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
@@ -19,8 +19,13 @@
import androidx.preference.PreferenceFragment;
import com.android.systemui.res.R;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
public class OtherPrefs extends PreferenceFragment {
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.other_settings`. See b/120445169.
+ @UsesReflection(@KeepTarget(classConstant = PowerNotificationControlsFragment.class))
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.other_settings);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 9cc526a..873b6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -35,6 +35,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.res.R;
import com.android.systemui.shared.plugins.PluginPrefs;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
public class TunerFragment extends PreferenceFragment {
@@ -77,6 +79,13 @@
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
+ // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
+ // explicitly declare references per usage in `R.xml.tuner_prefs`. See b/120445169.
+ @UsesReflection({
+ @KeepTarget(classConstant = LockscreenFragment.class),
+ @KeepTarget(classConstant = NavBarTuner.class),
+ @KeepTarget(classConstant = PluginFragment.class),
+ })
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.tuner_prefs);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 280c66a..84d2b37 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1636,6 +1636,11 @@
|| activeRow.stream == STREAM_ACCESSIBILITY
|| mDynamic.get(activeRow.stream);
}
+
+ // Continue to display row if it is visible to user.
+ if (row.view != null && mShowing) {
+ return row.view.getVisibility() == VISIBLE;
+ }
}
return false;
diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
index c4b43e1..97e43ad 100644
--- a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
+++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
@@ -24,11 +24,21 @@
import com.android.systemui.SysuiTestableContext
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.FakeBroadcastDispatcher
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import dagger.Binds
import dagger.Module
import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
@Module(
includes =
@@ -64,3 +74,35 @@
test.fakeBroadcastDispatcher
}
}
+
+interface SysUITestComponent<out T> {
+ val testScope: TestScope
+ val underTest: T
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit =
+ testScope.runTest {
+ // Access underTest immediately to force Dagger to instantiate it prior to the test running
+ underTest
+ runCurrent()
+ block()
+ }
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun SysUITestComponent<*>.runCurrent() = testScope.runCurrent()
+
+fun <T> SysUITestComponent<*>.collectLastValue(
+ flow: Flow<T>,
+ context: CoroutineContext = EmptyCoroutineContext,
+ start: CoroutineStart = CoroutineStart.DEFAULT,
+) = testScope.collectLastValue(flow, context, start)
+
+fun <T> SysUITestComponent<*>.collectValues(
+ flow: Flow<T>,
+ context: CoroutineContext = EmptyCoroutineContext,
+ start: CoroutineStart = CoroutineStart.DEFAULT,
+) = testScope.collectValues(flow, context, start)
+
+val SysUITestComponent<*>.backgroundScope
+ get() = testScope.backgroundScope
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index 0cb913b..fd50f15 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -38,6 +38,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -66,6 +67,7 @@
@Module(includes = [TestMocksModule.Bindings::class])
data class TestMocksModule(
@get:Provides val activityStarter: ActivityStarter = mock(),
+ @get:Provides val activityManagerWrapper: ActivityManagerWrapper = mock(),
@get:Provides val ambientState: AmbientState = mock(),
@get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()),
@get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index 4a799d8..a38ba00 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -20,6 +20,7 @@
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.flags.Flags.MIGRATE_CLOCKS_TO_BLUEPRINT;
import static com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_VIEW;
import static org.mockito.ArgumentMatchers.any;
@@ -40,7 +41,9 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.ClockAnimations;
@@ -124,6 +127,9 @@
@Mock
protected LogBuffer mLogBuffer;
+ @Mock
+ protected KeyguardClockInteractor mKeyguardClockInteractor;
+
protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {}
@@ -176,6 +182,7 @@
mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFakeFeatureFlags.set(MIGRATE_KEYGUARD_STATUS_VIEW, false);
+ mFakeFeatureFlags.set(MIGRATE_CLOCKS_TO_BLUEPRINT, false);
mController = new KeyguardClockSwitchController(
mView,
mStatusBarStateController,
@@ -197,7 +204,9 @@
mock(DozeParameters.class),
mock(AlwaysOnDisplayNotificationIconViewStore.class),
KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
- mFakeFeatureFlags
+ mKeyguardClockInteractor,
+ mFakeFeatureFlags,
+ mock(InWindowLauncherUnlockAnimationManager.class)
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
index e3a2c59..d77a80a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
@@ -31,42 +31,60 @@
import org.junit.runner.RunWith;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
/** Tests for {@link RadiiAnimator}. */
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class RadiiAnimatorTest extends SysuiTestCase {
float[] mResultRadii = new float[RadiiAnimator.RADII_COUNT];
+ final AtomicBoolean mAnimationStarted = new AtomicBoolean(false);
+ final AtomicBoolean mAnimationStopped = new AtomicBoolean(false);
+ final IRadiiAnimationListener mRadiiAnimationListener = new IRadiiAnimationListener() {
+ @Override
+ public void onRadiiAnimationUpdate(float[] radii) {
+ mResultRadii = radii;
+ }
+
+ @Override
+ public void onRadiiAnimationStart() {
+ mAnimationStarted.set(true);
+ }
+
+ @Override
+ public void onRadiiAnimationStop() {
+ mAnimationStopped.set(true);
+ }
+ };
@Test
public void constructor() {
final float[] radii = generateRadii(0.0f);
- final RadiiAnimator radiiAnimator = new RadiiAnimator(radii, newRadii -> {});
-
+ final RadiiAnimator radiiAnimator = new RadiiAnimator(radii, mRadiiAnimationListener);
assertThat(radiiAnimator.evaluate(0.0f)).isEqualTo(radii);
}
@Test
- public void skip_updates_to_end() {
+ public void skipAnimation_updatesToEnd() {
final float[] startRadii = generateRadii(0.0f);
final float[] endRadii = generateRadii(1.0f);
final RadiiAnimator radiiAnimator = setupAnimator(startRadii);
+ mAnimationStarted.set(false);
+ mAnimationStopped.set(false);
new Handler(Looper.getMainLooper()).post(() -> radiiAnimator.startAnimation(endRadii));
- TestUtils.waitForCondition(radiiAnimator::isStarted, "Animation did not start.");
+ TestUtils.waitForCondition(mAnimationStarted::get, "Animation did not start.");
TestUtils.waitForCondition(() -> Arrays.equals(radiiAnimator.evaluate(0.0f), startRadii)
- && Arrays.equals(radiiAnimator.evaluate(1.0f), endRadii),
+ && Arrays.equals(radiiAnimator.evaluate(1.0f), endRadii),
"Animator did not initialize to start and end values");
-
new Handler(Looper.getMainLooper()).post(radiiAnimator::skipAnimationToEnd);
- TestUtils.waitForCondition(
- () -> !radiiAnimator.isStarted(), "Animation did not end.");
+ TestUtils.waitForCondition(mAnimationStopped::get, "Animation did not stop.");
assertThat(mResultRadii).usingTolerance(0.001).containsExactly(endRadii);
}
@Test
- public void animation_can_repeat() {
+ public void finishedAnimation_canRepeat() {
final float[] startRadii = generateRadii(0.0f);
final float[] midRadii = generateRadii(1.0f);
final float[] endRadii = generateRadii(2.0f);
@@ -88,15 +106,15 @@
private RadiiAnimator setupAnimator(float[] startRadii) {
mResultRadii = new float[RadiiAnimator.RADII_COUNT];
- return new RadiiAnimator(startRadii,
- newRadii -> mResultRadii = newRadii);
+ return new RadiiAnimator(startRadii, mRadiiAnimationListener);
}
private void playAndSkipAnimation(RadiiAnimator animator, float[] endRadii) {
+ mAnimationStarted.set(false);
+ mAnimationStopped.set(false);
new Handler(Looper.getMainLooper()).post(() -> animator.startAnimation(endRadii));
- TestUtils.waitForCondition(animator::isStarted, "Animation did not start.");
+ TestUtils.waitForCondition(mAnimationStarted::get, "Animation did not start.");
new Handler(Looper.getMainLooper()).post(animator::skipAnimationToEnd);
- TestUtils.waitForCondition(
- () -> !animator.isStarted(), "Animation did not end.");
+ TestUtils.waitForCondition(mAnimationStopped::get, "Animation did not stop.");
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 8c26776..d2b81e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -17,7 +17,10 @@
package com.android.systemui.biometrics
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
@@ -26,10 +29,6 @@
import com.android.systemui.user.domain.UserDomainLayerModule
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
@@ -38,9 +37,29 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<AuthDialogPanelInteractionDetector> {
+
+ val shadeRepository: FakeShadeRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ ): TestComponent
+ }
+ }
+
private val testComponent: TestComponent =
DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory()
.create(
@@ -52,11 +71,9 @@
},
)
- @Mock private lateinit var action: Runnable
+ private val detector: AuthDialogPanelInteractionDetector = testComponent.underTest
- private val testScope = testComponent.testScope
- private val shadeRepository = testComponent.shadeRepository
- private val detector = testComponent.detector
+ @Mock private lateinit var action: Runnable
@Before
fun setUp() {
@@ -65,7 +82,7 @@
@Test
fun enableDetector_expand_shouldRunAction() =
- testScope.runTest {
+ testComponent.runTest {
// GIVEN shade is closed and detector is enabled
shadeRepository.setLegacyShadeExpansion(0f)
detector.enable(action)
@@ -82,7 +99,7 @@
@Test
fun enableDetector_shadeExpandImmediate_shouldNotPostRunnable() =
- testScope.runTest {
+ testComponent.runTest {
// GIVEN shade is closed and detector is enabled
shadeRepository.setLegacyShadeExpansion(0f)
detector.enable(action)
@@ -94,14 +111,11 @@
// THEN action not run
verifyZeroInteractions(action)
-
- // Clean up job
- detector.disable()
}
@Test
fun disableDetector_shouldNotPostRunnable() =
- testScope.runTest {
+ testComponent.runTest {
// GIVEN shade is closed and detector is enabled
shadeRepository.setLegacyShadeExpansion(0f)
detector.enable(action)
@@ -109,6 +123,7 @@
// WHEN detector is disabled and shade opens
detector.disable()
+ runCurrent()
shadeRepository.setLegacyShadeTracking(true)
shadeRepository.setLegacyShadeExpansion(.5f)
runCurrent()
@@ -119,7 +134,7 @@
@Test
fun enableDetector_beginCollapse_shouldNotPostRunnable() =
- testScope.runTest {
+ testComponent.runTest {
// GIVEN shade is open and detector is enabled
shadeRepository.setLegacyShadeExpansion(1f)
detector.enable(action)
@@ -131,31 +146,5 @@
// THEN action not run
verifyZeroInteractions(action)
-
- // Clean up job
- detector.disable()
}
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent {
-
- val detector: AuthDialogPanelInteractionDetector
- val shadeRepository: FakeShadeRepository
- val testScope: TestScope
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- ): TestComponent
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index ef06e0e..b4b02a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -52,7 +52,6 @@
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
@@ -64,6 +63,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -111,6 +111,7 @@
@Mock lateinit var displayManager: DisplayManager
@Mock lateinit var handler: Handler
@Mock lateinit var dumpManager: DumpManager
+ @Mock lateinit var fpsUnlockTracker: FpsUnlockTracker
@Captor lateinit var overlayCaptor: ArgumentCaptor<View>
@Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
@@ -269,7 +270,8 @@
handler,
alternateBouncerInteractor,
TestCoroutineScope(),
- dumpManager
+ dumpManager,
+ fpsUnlockTracker
)
displayStateRepository.setIsInRearDisplayMode(inRearDisplayMode)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index cbde78b..675ca63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -235,6 +235,8 @@
private InputManager mInputManager;
@Mock
private ViewRootImpl mViewRootImpl;
+ @Mock
+ private FpsUnlockTracker mFpsUnlockTracker;
@Before
public void setUp() {
@@ -326,7 +328,8 @@
mock(KeyguardFaceAuthInteractor.class),
mUdfpsKeyguardAccessibilityDelegate,
mUdfpsKeyguardViewModels,
- mSelectedUserInteractor
+ mSelectedUserInteractor,
+ mFpsUnlockTracker
);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
new file mode 100644
index 0000000..14ec4d4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
@@ -0,0 +1,163 @@
+/*
+ * 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.communal.data.db
+
+import android.content.ComponentName
+import androidx.room.Room
+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.lifecycle.InstantTaskExecutorRule
+import com.google.common.truth.Truth.assertThat
+import java.io.IOException
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalWidgetDaoTest : SysuiTestCase() {
+ @JvmField @Rule val instantTaskExecutor = InstantTaskExecutorRule()
+
+ private lateinit var db: CommunalDatabase
+ private lateinit var communalWidgetDao: CommunalWidgetDao
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Before
+ @Throws(IOException::class)
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ db =
+ Room.inMemoryDatabaseBuilder(context, CommunalDatabase::class.java)
+ .allowMainThreadQueries()
+ .build()
+ communalWidgetDao = db.communalWidgetDao()
+ }
+
+ @After
+ @Throws(IOException::class)
+ fun teardown() {
+ db.close()
+ }
+
+ @Test
+ fun addWidget_readValueInDb() =
+ testScope.runTest {
+ val (widgetId, provider, priority) = widgetInfo1
+ communalWidgetDao.addWidget(
+ widgetId = widgetId,
+ provider = provider,
+ priority = priority,
+ )
+ val entry = communalWidgetDao.getWidgetByIdNow(id = 1)
+ assertThat(entry).isEqualTo(communalWidgetItemEntry1)
+ }
+
+ @Test
+ fun addWidget_emitsActiveWidgetsInDb(): Unit =
+ testScope.runTest {
+ val widgetsToAdd = listOf(widgetInfo1, widgetInfo2)
+ val widgets = collectLastValue(communalWidgetDao.getWidgets())
+ widgetsToAdd.forEach {
+ val (widgetId, provider, priority) = it
+ communalWidgetDao.addWidget(
+ widgetId = widgetId,
+ provider = provider,
+ priority = priority,
+ )
+ }
+ assertThat(widgets())
+ .containsExactly(
+ communalItemRankEntry1,
+ communalWidgetItemEntry1,
+ communalItemRankEntry2,
+ communalWidgetItemEntry2
+ )
+ }
+
+ @Test
+ fun deleteWidget_emitsActiveWidgetsInDb() =
+ testScope.runTest {
+ val widgetsToAdd = listOf(widgetInfo1, widgetInfo2)
+ val widgets = collectLastValue(communalWidgetDao.getWidgets())
+
+ widgetsToAdd.forEach {
+ val (widgetId, provider, priority) = it
+ communalWidgetDao.addWidget(
+ widgetId = widgetId,
+ provider = provider,
+ priority = priority,
+ )
+ }
+ assertThat(widgets())
+ .containsExactly(
+ communalItemRankEntry1,
+ communalWidgetItemEntry1,
+ communalItemRankEntry2,
+ communalWidgetItemEntry2
+ )
+
+ communalWidgetDao.deleteWidgetById(communalWidgetItemEntry1.widgetId)
+ assertThat(widgets()).containsExactly(communalItemRankEntry2, communalWidgetItemEntry2)
+ }
+
+ data class FakeWidgetMetadata(
+ val widgetId: Int,
+ val provider: ComponentName,
+ val priority: Int
+ )
+
+ companion object {
+ val widgetInfo1 =
+ FakeWidgetMetadata(
+ widgetId = 1,
+ provider = ComponentName("pk_name", "cls_name_1"),
+ priority = 1
+ )
+ val widgetInfo2 =
+ FakeWidgetMetadata(
+ widgetId = 2,
+ provider = ComponentName("pk_name", "cls_name_2"),
+ priority = 2
+ )
+ val communalItemRankEntry1 = CommunalItemRank(uid = 1L, rank = widgetInfo1.priority)
+ val communalItemRankEntry2 = CommunalItemRank(uid = 2L, rank = widgetInfo2.priority)
+ val communalWidgetItemEntry1 =
+ CommunalWidgetItem(
+ uid = 1L,
+ widgetId = widgetInfo1.widgetId,
+ componentName = widgetInfo1.provider.flattenToString(),
+ itemId = communalItemRankEntry1.uid,
+ )
+ val communalWidgetItemEntry2 =
+ CommunalWidgetItem(
+ uid = 2L,
+ widgetId = widgetInfo2.widgetId,
+ componentName = widgetInfo2.provider.flattenToString(),
+ itemId = communalItemRankEntry2.uid,
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index fcb191b..ca8316d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -1,9 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.communal.data.repository
import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.BroadcastReceiver
+import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.UserHandle
import android.os.UserManager
@@ -11,8 +28,10 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.communal.data.model.CommunalWidgetMetadata
-import com.android.systemui.communal.shared.model.CommunalContentSize
+import com.android.systemui.communal.data.db.CommunalItemRank
+import com.android.systemui.communal.data.db.CommunalWidgetDao
+import com.android.systemui.communal.data.db.CommunalWidgetItem
+import com.android.systemui.communal.shared.CommunalWidgetHost
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FeatureFlagsClassic
@@ -28,6 +47,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -66,9 +86,9 @@
@Mock private lateinit var providerInfoA: AppWidgetProviderInfo
- @Mock private lateinit var providerInfoB: AppWidgetProviderInfo
+ @Mock private lateinit var communalWidgetHost: CommunalWidgetHost
- @Mock private lateinit var providerInfoC: AppWidgetProviderInfo
+ @Mock private lateinit var communalWidgetDao: CommunalWidgetDao
private lateinit var communalRepository: FakeCommunalRepository
@@ -103,6 +123,92 @@
}
@Test
+ fun neverQueryDbForWidgets_whenFeatureIsDisabled() =
+ testScope.runTest {
+ communalEnabled(false)
+ val repository = initCommunalWidgetRepository()
+ collectLastValue(repository.communalWidgets)()
+ runCurrent()
+
+ verify(communalWidgetDao, Mockito.never()).getWidgets()
+ }
+
+ @Test
+ fun neverQueryDbForWidgets_whenFeatureEnabled_andUserLocked() =
+ testScope.runTest {
+ userUnlocked(false)
+ val repository = initCommunalWidgetRepository()
+ collectLastValue(repository.communalWidgets)()
+ runCurrent()
+
+ verify(communalWidgetDao, Mockito.never()).getWidgets()
+ }
+
+ @Test
+ fun communalWidgets_whenUserUnlocked_queryWidgetsFromDb() =
+ testScope.runTest {
+ userUnlocked(false)
+ val repository = initCommunalWidgetRepository()
+ val communalWidgets = collectLastValue(repository.communalWidgets)
+ communalWidgets()
+ runCurrent()
+ val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
+ val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L)
+ whenever(communalWidgetDao.getWidgets())
+ .thenReturn(flowOf(mapOf(communalItemRankEntry to communalWidgetItemEntry)))
+ whenever(appWidgetManager.getAppWidgetInfo(anyInt())).thenReturn(providerInfoA)
+
+ userUnlocked(true)
+ installedProviders(listOf(stopwatchProviderInfo))
+ broadcastReceiverUpdate()
+ runCurrent()
+
+ verify(communalWidgetDao).getWidgets()
+ assertThat(communalWidgets())
+ .containsExactly(
+ CommunalWidgetContentModel(
+ appWidgetId = communalWidgetItemEntry.widgetId,
+ providerInfo = providerInfoA,
+ priority = communalItemRankEntry.rank,
+ )
+ )
+ }
+
+ @Test
+ fun addWidget_allocateId_bindWidget_andAddToDb() =
+ testScope.runTest {
+ userUnlocked(true)
+ val repository = initCommunalWidgetRepository()
+ runCurrent()
+
+ val provider = ComponentName("pkg_name", "cls_name")
+ val id = 1
+ val priority = 1
+ whenever(communalWidgetHost.allocateIdAndBindWidget(any<ComponentName>()))
+ .thenReturn(id)
+ repository.addWidget(provider, priority)
+ runCurrent()
+
+ verify(communalWidgetHost).allocateIdAndBindWidget(provider)
+ verify(communalWidgetDao).addWidget(id, provider, priority)
+ }
+
+ @Test
+ fun deleteWidget_removeWidgetId_andDeleteFromDb() =
+ testScope.runTest {
+ userUnlocked(true)
+ val repository = initCommunalWidgetRepository()
+ runCurrent()
+
+ val id = 1
+ repository.deleteWidget(id)
+ runCurrent()
+
+ verify(communalWidgetDao).deleteWidgetById(id)
+ verify(appWidgetHost).deleteAppWidgetId(id)
+ }
+
+ @Test
fun broadcastReceiver_communalDisabled_doNotRegisterUserUnlockedBroadcastReceiver() =
testScope.runTest {
communalEnabled(false)
@@ -183,34 +289,6 @@
}
@Test
- fun appWidgetId_userLockedAgainAfterProviderInfoAvailable_deleteAppWidgetId() =
- testScope.runTest {
- whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(123456)
- userUnlocked(false)
- val repository = initCommunalWidgetRepository()
- val lastStopwatchProviderInfo = collectLastValue(repository.stopwatchAppWidgetInfo)
- assertThat(lastStopwatchProviderInfo()).isNull()
-
- // User unlocks
- userUnlocked(true)
- installedProviders(listOf(stopwatchProviderInfo))
- broadcastReceiverUpdate()
-
- // Verify app widget id allocated
- assertThat(lastStopwatchProviderInfo()?.appWidgetId).isEqualTo(123456)
- verify(appWidgetHost).allocateAppWidgetId()
- verify(appWidgetHost, Mockito.never()).deleteAppWidgetId(anyInt())
-
- // User locked again
- userUnlocked(false)
- broadcastReceiverUpdate()
-
- // Verify app widget id deleted
- assertThat(lastStopwatchProviderInfo()).isNull()
- verify(appWidgetHost).deleteAppWidgetId(123456)
- }
-
- @Test
fun appWidgetHost_userUnlocked_startListening() =
testScope.runTest {
userUnlocked(false)
@@ -246,95 +324,16 @@
verify(appWidgetHost).stopListening()
}
- @Test
- fun getCommunalWidgetAllowList_onInit() {
- testScope.runTest {
- val repository = initCommunalWidgetRepository()
- val communalWidgetAllowlist = repository.communalWidgetAllowlist
- assertThat(
- listOf(
- CommunalWidgetMetadata(
- componentName = fakeAllowlist[0],
- priority = 3,
- sizes = listOf(CommunalContentSize.HALF),
- ),
- CommunalWidgetMetadata(
- componentName = fakeAllowlist[1],
- priority = 2,
- sizes = listOf(CommunalContentSize.HALF),
- ),
- CommunalWidgetMetadata(
- componentName = fakeAllowlist[2],
- priority = 1,
- sizes = listOf(CommunalContentSize.HALF),
- ),
- )
- )
- .containsExactly(*communalWidgetAllowlist.toTypedArray())
- }
- }
-
- // This behavior is temporary before the local database is set up.
- @Test
- fun communalWidgets_withPreviouslyBoundWidgets_removeEachBinding() =
- testScope.runTest {
- whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(1, 2, 3)
- setAppWidgetIds(listOf(1, 2, 3))
- whenever(appWidgetManager.getAppWidgetInfo(anyInt())).thenReturn(providerInfoA)
- userUnlocked(true)
-
- val repository = initCommunalWidgetRepository()
-
- collectLastValue(repository.communalWidgets)()
-
- verify(appWidgetHost).deleteAppWidgetId(1)
- verify(appWidgetHost).deleteAppWidgetId(2)
- verify(appWidgetHost).deleteAppWidgetId(3)
- }
-
- @Test
- fun communalWidgets_allowlistNotEmpty_bindEachWidgetFromTheAllowlist() =
- testScope.runTest {
- whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(0, 1, 2)
- userUnlocked(true)
-
- whenever(appWidgetManager.getAppWidgetInfo(0)).thenReturn(providerInfoA)
- whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfoB)
- whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfoC)
-
- val repository = initCommunalWidgetRepository()
-
- val inventory by collectLastValue(repository.communalWidgets)
-
- assertThat(
- listOf(
- CommunalWidgetContentModel(
- appWidgetId = 0,
- providerInfo = providerInfoA,
- priority = 3,
- ),
- CommunalWidgetContentModel(
- appWidgetId = 1,
- providerInfo = providerInfoB,
- priority = 2,
- ),
- CommunalWidgetContentModel(
- appWidgetId = 2,
- providerInfo = providerInfoC,
- priority = 1,
- ),
- )
- )
- .containsExactly(*inventory!!.toTypedArray())
- }
-
private fun initCommunalWidgetRepository(): CommunalWidgetRepositoryImpl {
return CommunalWidgetRepositoryImpl(
- context,
appWidgetManager,
appWidgetHost,
+ testScope.backgroundScope,
+ testDispatcher,
broadcastDispatcher,
communalRepository,
+ communalWidgetHost,
+ communalWidgetDao,
packageManager,
userManager,
userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
index dcc15ae..b25fb6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
@@ -20,8 +20,8 @@
import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import org.junit.After
@@ -45,7 +45,13 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- dialog = MirroringConfirmationDialog(context, onStartMirroringCallback, onCancelCallback)
+ dialog =
+ MirroringConfirmationDialog(
+ context,
+ onStartMirroringCallback,
+ onCancelCallback,
+ navbarBottomInsetsProvider = { 0 },
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
index b589a2a..a903d25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -22,6 +22,7 @@
import android.content.res.Resources
import android.content.res.Resources.NotFoundException
import android.test.suitebuilder.annotation.SmallTest
+import com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -72,6 +73,8 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ mSetFlagsRule.disableFlags(FLAG_SYSUI_TEAMFOOD)
+
flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
mFeatureFlagsClassicDebug =
@@ -130,7 +133,7 @@
@Test
fun teamFoodFlag_True() {
- mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD)
+ mSetFlagsRule.enableFlags(FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -145,7 +148,7 @@
.thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
.thenReturn(false)
- mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD)
+ mSetFlagsRule.enableFlags(FLAG_SYSUI_TEAMFOOD)
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsClassicDebug.isEnabled(teamfoodableFlagB)).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
new file mode 100644
index 0000000..8b572eb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.keyboard.backlight.ui.view
+
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWithLooper
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyboardBacklightDialogTest : SysuiTestCase() {
+
+ private lateinit var dialog: KeyboardBacklightDialog
+ private lateinit var rootView: View
+ private val descriptionString = context.getString(R.string.keyboard_backlight_value)
+
+ @Before
+ fun setUp() {
+ dialog =
+ KeyboardBacklightDialog(context, initialCurrentLevel = 0, initialMaxLevel = MAX_LEVEL)
+ dialog.show()
+ rootView = dialog.requireViewById(R.id.keyboard_backlight_dialog_container)
+ }
+
+ @Test
+ fun rootViewContentDescription_containsInitialLevel() {
+ assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(INITIAL_LEVEL))
+ }
+
+ @Test
+ fun contentDescriptionUpdated_afterEveryLevelUpdate() {
+ val events = startCollectingAccessibilityEvents(rootView)
+
+ dialog.updateState(current = 1, max = MAX_LEVEL)
+
+ assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(1))
+ assertThat(events).contains(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
+ }
+
+ private fun contentDescriptionForLevel(level: Int): String {
+ return String.format(descriptionString, level, MAX_LEVEL)
+ }
+
+ private fun startCollectingAccessibilityEvents(rootView: View): MutableList<Int> {
+ val events = mutableListOf<Int>()
+ rootView.accessibilityDelegate =
+ object : View.AccessibilityDelegate() {
+ override fun sendAccessibilityEvent(host: View, eventType: Int) {
+ super.sendAccessibilityEvent(host, eventType)
+ events.add(eventType)
+ }
+ }
+ return events
+ }
+
+ companion object {
+ private const val MAX_LEVEL = 5
+ private const val INITIAL_LEVEL = 0
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt
new file mode 100644
index 0000000..bc40c2d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlin.test.Test
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+@SmallTest
+class KeyguardClockRepositoryTest : SysuiTestCase() {
+
+ private lateinit var scheduler: TestCoroutineScheduler
+ private lateinit var dispatcher: CoroutineDispatcher
+ private lateinit var scope: TestScope
+
+ private lateinit var underTest: KeyguardClockRepository
+ private lateinit var fakeSettings: FakeSettings
+ @Mock private lateinit var clockRegistry: ClockRegistry
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeSettings = FakeSettings()
+ scheduler = TestCoroutineScheduler()
+ dispatcher = StandardTestDispatcher(scheduler)
+ scope = TestScope(dispatcher)
+ underTest = KeyguardClockRepository(fakeSettings, clockRegistry, dispatcher)
+ }
+
+ @Test
+ fun testSelectedClockSize_small() =
+ scope.runTest {
+ fakeSettings.putInt(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 0)
+ val value = collectLastValue(underTest.selectedClockSize)
+ Truth.assertThat(value()).isEqualTo(SettingsClockSize.SMALL)
+ }
+
+ @Test
+ fun testSelectedClockSize_dynamic() =
+ scope.runTest {
+ fakeSettings.putInt(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1)
+ val value = collectLastValue(underTest.selectedClockSize)
+ Truth.assertThat(value()).isEqualTo(SettingsClockSize.DYNAMIC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
index 4f6ec71..b439fcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
@@ -18,23 +18,34 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
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.power.domain.interactor.PowerInteractorFactory
-import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.keyguard.util.mockTopActivityClassName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import dagger.BindsInstance
+import dagger.Component
import dagger.Lazy
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import junit.framework.Assert.fail
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -49,20 +60,30 @@
underTest
}
+ private lateinit var testComponent: TestComponent
+ @Mock private lateinit var activityManagerWrapper: ActivityManagerWrapper
+
+ private var topActivityClassName = "launcher"
+
@Before
override fun setUp() {
super.setUp()
+ MockitoAnnotations.initMocks(this)
- underTest =
- FromLockscreenTransitionInteractor(
- transitionRepository = super.transitionRepository,
- transitionInteractor = super.transitionInteractor,
- scope = super.testScope.backgroundScope,
- keyguardInteractor = super.keyguardInteractor,
- flags = FakeFeatureFlags(),
- shadeRepository = FakeShadeRepository(),
- powerInteractor = PowerInteractorFactory.create().powerInteractor,
- )
+ testComponent =
+ DaggerFromLockscreenTransitionInteractorTest_TestComponent.factory()
+ .create(
+ test = this,
+ mocks =
+ TestMocksModule(
+ activityManagerWrapper = activityManagerWrapper,
+ ),
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+ transitionRepository = testComponent.transitionRepository
+
+ activityManagerWrapper.mockTopActivityClassName(topActivityClassName)
}
@Test
@@ -189,4 +210,73 @@
fail("surfaceBehindModel was unexpectedly null.")
}
}
+
+ @Test
+ fun testSurfaceBehindModel_alpha1_whenTransitioningWithInWindowAnimation() =
+ testScope.runTest {
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ topActivityClassName
+ )
+ runCurrent()
+
+ val values by collectValues(underTest.surfaceBehindModel)
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(1f, values[values.size - 1]?.alpha)
+ }
+
+ @Test
+ fun testSurfaceBehindModel_alphaZero_whenNotTransitioningWithInWindowAnimation() =
+ testScope.runTest {
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ "not_launcher"
+ )
+ runCurrent()
+
+ val values by collectValues(underTest.surfaceBehindModel)
+ runCurrent()
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(0f, values[values.size - 1]?.alpha)
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: FromLockscreenTransitionInteractor
+ val testScope: TestScope
+ val transitionRepository: FakeKeyguardTransitionRepository
+ val surfaceBehindRepository: FakeKeyguardSurfaceBehindRepository
+ val inWindowLauncherUnlockAnimationRepository: InWindowLauncherUnlockAnimationRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
new file mode 100644
index 0000000..7fb0dd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
+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.keyguard.util.mockTopActivityClassName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import dagger.BindsInstance
+import dagger.Component
+import junit.framework.Assert.assertEquals
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class InWindowLauncherUnlockAnimationInteractorTest : SysuiTestCase() {
+ private lateinit var underTest: InWindowLauncherUnlockAnimationInteractor
+
+ private lateinit var testComponent: TestComponent
+ private lateinit var testScope: TestScope
+ private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ @Mock private lateinit var activityManagerWrapper: ActivityManagerWrapper
+
+ private val launcherClassName = "launcher"
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testComponent =
+ DaggerInWindowLauncherUnlockAnimationInteractorTest_TestComponent.factory()
+ .create(
+ test = this,
+ mocks =
+ TestMocksModule(
+ activityManagerWrapper = activityManagerWrapper,
+ ),
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+ transitionRepository = testComponent.transitionRepository
+
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_trueIfTopActivityIsLauncher_andTransitioningToGone() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ runCurrent()
+
+ // Should still be false since we're not transitioning to GONE.
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // -> GONE + launcher is behind
+ ),
+ values
+ )
+
+ activityManagerWrapper.mockTopActivityClassName("not_launcher")
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.RUNNING,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // Top activity should be sampled, if it changes midway it should not
+ // matter.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true,
+ false, // False once we're not transitioning anymore.
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherPartwayThrough() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put not launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName("not_launcher")
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.RUNNING,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testTransitioningToGoneWithInWindowAnimation_falseIfTopActivityIsLauncherWhileNotTransitioningToGone() =
+ testScope.runTest {
+ val values by collectValues(underTest.transitioningToGoneWithInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put launcher on top
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_trueOnceSurfaceAvailable_falseWhenTransitionEnds() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+
+ testComponent.surfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true, // The surface is now available, so we should start the animation.
+ ),
+ values
+ )
+
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ true,
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_neverTrueIfSurfaceNotAvailable() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.FINISHED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @Test
+ fun testShouldStartInWindowAnimation_falseIfSurfaceAvailable_afterTransitionInterrupted() =
+ testScope.runTest {
+ val values by collectValues(underTest.shouldStartInWindowAnimation)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false, // False by default.
+ ),
+ values
+ )
+
+ // Put Launcher on top and begin transitioning to GONE.
+ testComponent.inWindowLauncherUnlockAnimationRepository.setLauncherActivityClass(
+ launcherClassName
+ )
+ activityManagerWrapper.mockTopActivityClassName(launcherClassName)
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ )
+ )
+ testComponent.surfaceBehindRepository.setSurfaceRemoteAnimationTargetAvailable(true)
+ runCurrent()
+
+ assertEquals(
+ listOf(
+ false,
+ ),
+ values
+ )
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: InWindowLauncherUnlockAnimationInteractor
+ val testScope: TestScope
+ val transitionRepository: FakeKeyguardTransitionRepository
+ val surfaceBehindRepository: FakeKeyguardSurfaceBehindRepository
+ val inWindowLauncherUnlockAnimationRepository: InWindowLauncherUnlockAnimationRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index 6cd7406..13f30f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -130,15 +130,6 @@
}
@Test
- fun dispatchKeyEvent_menuActionUp_awakeKeyguard_showsPrimaryBouncer() {
- powerInteractor.setAwakeForTest()
- whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
-
- verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU)
- }
-
- @Test
fun dispatchKeyEvent_menuActionUp_awakeShadeLocked_collapsesShade() {
powerInteractor.setAwakeForTest()
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
index 8db19ae..339fd22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTestCase.kt
@@ -26,7 +26,7 @@
open class KeyguardTransitionInteractorTestCase : SysuiTestCase() {
val testDispatcher = StandardTestDispatcher()
- val testScope = TestScope(testDispatcher)
+ var testScope = TestScope(testDispatcher)
lateinit var keyguardRepository: FakeKeyguardRepository
lateinit var transitionRepository: FakeKeyguardTransitionRepository
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 275ac80..c292102 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
@@ -27,7 +27,9 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
@@ -44,6 +46,7 @@
import com.android.systemui.shade.domain.model.ShadeModel
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
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.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
@@ -147,6 +150,15 @@
flags = featureFlags,
shadeRepository = shadeRepository,
powerInteractor = powerInteractor,
+ inWindowLauncherUnlockAnimationInteractor = {
+ InWindowLauncherUnlockAnimationInteractor(
+ InWindowLauncherUnlockAnimationRepository(),
+ testScope,
+ transitionInteractor,
+ { FakeKeyguardSurfaceBehindRepository() },
+ mock(),
+ )
+ },
)
.apply { start() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
new file mode 100644
index 0000000..570dfb3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.util.mockito.any
+import dagger.BindsInstance
+import dagger.Component
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class InWindowLauncherUnlockAnimationManagerTest : SysuiTestCase() {
+ private lateinit var underTest: InWindowLauncherUnlockAnimationManager
+
+ private lateinit var testComponent: TestComponent
+ private lateinit var testScope: TestScope
+
+ @Mock private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testComponent =
+ DaggerInWindowLauncherUnlockAnimationManagerTest_TestComponent.factory()
+ .create(
+ test = this,
+ )
+ underTest = testComponent.underTest
+ testScope = testComponent.testScope
+
+ underTest.setLauncherUnlockController("launcherClass", launcherUnlockAnimationController)
+ }
+
+ @Test
+ fun testPrepareForUnlock_calledOnlyOnce() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.prepareForUnlock()
+
+ verify(launcherUnlockAnimationController)
+ .prepareForUnlock(anyBoolean(), any(), anyInt())
+ }
+
+ @Test
+ fun testPlayUnlockAnimation_onlyCalledIfPrepared() =
+ testScope.runTest {
+ underTest.playUnlockAnimation(true, 200, 0)
+ verify(launcherUnlockAnimationController, never())
+ .playUnlockAnimation(any(), any(), any())
+ }
+
+ @Test
+ fun testForceUnlocked_ifPreparedButNeverStarted() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verify(launcherUnlockAnimationController).setUnlockAmount(1f, true)
+ }
+
+ @Test
+ fun testForceUnlocked_ifManualUnlockAmountLessThan1() =
+ testScope.runTest {
+ underTest.prepareForUnlock()
+ underTest.setUnlockAmount(0.5f, false)
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verify(launcherUnlockAnimationController).prepareForUnlock(any(), any(), any())
+ verify(launcherUnlockAnimationController).setUnlockAmount(0.5f, false)
+ verify(launcherUnlockAnimationController).setUnlockAmount(1f, true)
+ verifyNoMoreInteractions(launcherUnlockAnimationController)
+ }
+
+ @Test
+ fun testDoesNotForceUnlocked_ifNeverPrepared() =
+ testScope.runTest {
+ underTest.ensureUnlockedOrAnimatingUnlocked()
+
+ verifyNoMoreInteractions(launcherUnlockAnimationController)
+ }
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent {
+ val underTest: InWindowLauncherUnlockAnimationManager
+ val testScope: TestScope
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ ): TestComponent
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 8cfa87d..2831053 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
@@ -37,6 +38,7 @@
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import com.android.systemui.util.mockito.whenever
import org.junit.Before
@@ -67,6 +69,8 @@
@Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection
@Mock private lateinit var aodBurnInSection: AodBurnInSection
@Mock private lateinit var communalTutorialIndicatorSection: CommunalTutorialIndicatorSection
+ @Mock private lateinit var clockSection: ClockSection
+ @Mock private lateinit var smartspaceSection: SmartspaceSection
@Before
fun setup() {
@@ -86,6 +90,8 @@
aodNotificationIconsSection,
aodBurnInSection,
communalTutorialIndicatorSection,
+ clockSection,
+ smartspaceSection,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
new file mode 100644
index 0000000..6b85cf7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags.MIGRATE_CLOCKS_TO_BLUEPRINT
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.util.Utils
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+@SmallTest
+class ClockSectionTest : SysuiTestCase() {
+ @Mock private lateinit var keyguardClockInteractor: KeyguardClockInteractor
+ @Mock private lateinit var keyguardClockViewModel: KeyguardClockViewModel
+ @Mock private lateinit var smartspaceViewModel: KeyguardSmartspaceViewModel
+ @Mock private lateinit var splitShadeStateController: SplitShadeStateController
+ @Mock private lateinit var keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>
+ private var featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
+
+ private lateinit var underTest: ClockSection
+
+ // smartspaceViewModel.getDimen("date_weather_view_height")
+ private val SMART_SPACE_DATE_WEATHER_HEIGHT = 10
+
+ // smartspaceViewModel.getDimen("enhanced_smartspace_height")
+ private val ENHANCED_SMART_SPACE_HEIGHT = 11
+
+ private val SMALL_CLOCK_TOP_SPLIT_SHADE =
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
+
+ private val SMALL_CLOCK_TOP_NON_SPLIT_SHADE =
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
+ Utils.getStatusBarHeaderHeightKeyguard(context)
+
+ private val LARGE_CLOCK_TOP =
+ context.resources.getDimensionPixelSize(R.dimen.status_bar_height) +
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_padding_top
+ ) +
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
+ SMART_SPACE_DATE_WEATHER_HEIGHT +
+ ENHANCED_SMART_SPACE_HEIGHT
+
+ private val CLOCK_FADE_TRANSLATION_Y =
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
+ )
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ whenever(smartspaceViewModel.getDimen("date_weather_view_height"))
+ .thenReturn(SMART_SPACE_DATE_WEATHER_HEIGHT)
+ whenever(smartspaceViewModel.getDimen("enhanced_smartspace_height"))
+ .thenReturn(ENHANCED_SMART_SPACE_HEIGHT)
+ featureFlags.set(MIGRATE_CLOCKS_TO_BLUEPRINT, true)
+ underTest =
+ ClockSection(
+ keyguardClockInteractor,
+ keyguardClockViewModel,
+ smartspaceViewModel,
+ mContext,
+ splitShadeStateController,
+ keyguardBlueprintInteractor,
+ featureFlags
+ )
+ }
+
+ @Test
+ fun testApplyDefaultConstraints_LargeClock_SplitShade() {
+ setLargeClock(true)
+ setSplitShade(true)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+
+ val expectedLargeClockTopMargin = LARGE_CLOCK_TOP
+ assetLargeClockTop(cs, expectedLargeClockTopMargin)
+
+ val expectedSmallClockTopMargin = SMALL_CLOCK_TOP_SPLIT_SHADE - CLOCK_FADE_TRANSLATION_Y
+ assetSmallClockTop(cs, expectedSmallClockTopMargin)
+ }
+
+ @Test
+ fun testApplyDefaultConstraints_LargeClock_NonSplitShade() {
+ setLargeClock(true)
+ setSplitShade(false)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+
+ val expectedLargeClockTopMargin = LARGE_CLOCK_TOP
+ assetLargeClockTop(cs, expectedLargeClockTopMargin)
+
+ val expectedSmallClockTopMargin = SMALL_CLOCK_TOP_NON_SPLIT_SHADE - CLOCK_FADE_TRANSLATION_Y
+ assetSmallClockTop(cs, expectedSmallClockTopMargin)
+ }
+
+ @Test
+ fun testApplyDefaultConstraints_SmallClock_SplitShade() {
+ setLargeClock(false)
+ setSplitShade(true)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+
+ val expectedLargeClockTopMargin = LARGE_CLOCK_TOP - CLOCK_FADE_TRANSLATION_Y
+ assetLargeClockTop(cs, expectedLargeClockTopMargin)
+
+ val expectedSmallClockTopMargin = SMALL_CLOCK_TOP_SPLIT_SHADE
+ assetSmallClockTop(cs, expectedSmallClockTopMargin)
+ }
+
+ @Test
+ fun testApplyDefaultConstraints_SmallClock_NonSplitShade() {
+ setLargeClock(false)
+ setSplitShade(false)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+ val expectedLargeClockTopMargin = LARGE_CLOCK_TOP - CLOCK_FADE_TRANSLATION_Y
+ assetLargeClockTop(cs, expectedLargeClockTopMargin)
+
+ val expectedSmallClockTopMargin = SMALL_CLOCK_TOP_NON_SPLIT_SHADE
+ assetSmallClockTop(cs, expectedSmallClockTopMargin)
+ }
+
+ @Test
+ fun testLargeClockShouldBeCentered() {
+ underTest.setClockShouldBeCentered(true)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+ val constraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
+ assertThat(constraint.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID)
+ }
+
+ @Test
+ fun testLargeClockShouldNotBeCentered() {
+ underTest.setClockShouldBeCentered(false)
+ val cs = ConstraintSet()
+ underTest.applyDefaultConstraints(cs)
+ val constraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
+ assertThat(constraint.layout.endToEnd).isEqualTo(R.id.split_shade_guideline)
+ }
+
+ private fun setLargeClock(useLargeClock: Boolean) {
+ whenever(keyguardClockViewModel.useLargeClock).thenReturn(useLargeClock)
+ }
+
+ private fun setSplitShade(isInSplitShade: Boolean) {
+ whenever(splitShadeStateController.shouldUseSplitNotificationShade(context.resources))
+ .thenReturn(isInSplitShade)
+ }
+
+ private fun assetLargeClockTop(cs: ConstraintSet, expectedLargeClockTopMargin: Int) {
+ val largeClockConstraint = cs.getConstraint(R.id.lockscreen_clock_view_large)
+ assertThat(largeClockConstraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(largeClockConstraint.layout.topMargin).isEqualTo(expectedLargeClockTopMargin)
+ }
+
+ private fun assetSmallClockTop(cs: ConstraintSet, expectedSmallClockTopMargin: Int) {
+ val smallClockConstraint = cs.getConstraint(R.id.lockscreen_clock_view)
+ assertThat(smallClockConstraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(smallClockConstraint.layout.topMargin).isEqualTo(expectedSmallClockTopMargin)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
new file mode 100644
index 0000000..02bafd0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.GONE
+import androidx.constraintlayout.widget.ConstraintSet.VISIBLE
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags.MIGRATE_CLOCKS_TO_BLUEPRINT
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.StateFlow
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+@SmallTest
+class SmartspaceSectionTest : SysuiTestCase() {
+
+ private lateinit var underTest: SmartspaceSection
+ @Mock private lateinit var keyguardClockViewModel: KeyguardClockViewModel
+ @Mock private lateinit var keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel
+ @Mock private lateinit var lockscreenSmartspaceController: LockscreenSmartspaceController
+ @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock private lateinit var hasCustomWeatherDataDisplay: StateFlow<Boolean>
+ private lateinit var mFakeFeatureFlags: FakeFeatureFlagsClassic
+
+ private val smartspaceView = View(mContext).also { it.id = View.generateViewId() }
+ private val weatherView = View(mContext).also { it.id = View.generateViewId() }
+ private val dateView = View(mContext).also { it.id = View.generateViewId() }
+ private lateinit var constraintLayout: ConstraintLayout
+ private lateinit var constraintSet: ConstraintSet
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mFakeFeatureFlags = FakeFeatureFlagsClassic()
+ mFakeFeatureFlags.set(MIGRATE_CLOCKS_TO_BLUEPRINT, true)
+ underTest =
+ SmartspaceSection(
+ keyguardClockViewModel,
+ keyguardSmartspaceViewModel,
+ mContext,
+ lockscreenSmartspaceController,
+ keyguardUnlockAnimationController,
+ mFakeFeatureFlags
+ )
+ constraintLayout = ConstraintLayout(mContext)
+ whenever(lockscreenSmartspaceController.buildAndConnectView(constraintLayout))
+ .thenReturn(smartspaceView)
+ whenever(lockscreenSmartspaceController.buildAndConnectWeatherView(constraintLayout))
+ .thenReturn(weatherView)
+ whenever(lockscreenSmartspaceController.buildAndConnectDateView(constraintLayout))
+ .thenReturn(dateView)
+ whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay)
+ .thenReturn(hasCustomWeatherDataDisplay)
+ constraintSet = ConstraintSet()
+ }
+
+ @Test
+ fun testAddViews_notSmartspaceEnabled() {
+ whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(false)
+ val constraintLayout = ConstraintLayout(mContext)
+ underTest.addViews(constraintLayout)
+ assertThat(smartspaceView.parent).isNull()
+ assertThat(weatherView.parent).isNull()
+ assertThat(dateView.parent).isNull()
+ }
+
+ @Test
+ fun testAddViews_smartspaceEnabled_dateWeatherDecoupled() {
+ whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
+ whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)
+ underTest.addViews(constraintLayout)
+ assert(smartspaceView.parent == constraintLayout)
+ assert(weatherView.parent == constraintLayout)
+ assert(dateView.parent == constraintLayout)
+ }
+
+ @Test
+ fun testAddViews_smartspaceEnabled_notDateWeatherDecoupled() {
+ whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
+ whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(false)
+ underTest.addViews(constraintLayout)
+ assert(smartspaceView.parent == constraintLayout)
+ assert(weatherView.parent == null)
+ assert(dateView.parent == null)
+ }
+
+ @Test
+ fun testConstraintsWhenNotHasCustomWeatherDataDisplay() {
+ whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
+ whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)
+ whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay.value).thenReturn(false)
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+ assertWeatherSmartspaceConstrains(constraintSet)
+
+ val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id)
+ assertThat(smartspaceConstraints.layout.topToBottom).isEqualTo(dateView.id)
+
+ val dateConstraints = constraintSet.getConstraint(dateView.id)
+ assertThat(dateConstraints.layout.topToBottom).isEqualTo(R.id.lockscreen_clock_view)
+ }
+
+ @Test
+ fun testConstraintsWhenHasCustomWeatherDataDisplay() {
+ whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay.value).thenReturn(true)
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+ assertWeatherSmartspaceConstrains(constraintSet)
+
+ val dateConstraints = constraintSet.getConstraint(dateView.id)
+ assertThat(dateConstraints.layout.bottomToTop).isEqualTo(smartspaceView.id)
+ }
+
+ @Test
+ fun testNormalDateWeatherVisibility() {
+ whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay.value).thenReturn(false)
+ whenever(keyguardSmartspaceViewModel.isWeatherEnabled).thenReturn(true)
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+ assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(VISIBLE)
+
+ whenever(keyguardSmartspaceViewModel.isWeatherEnabled).thenReturn(false)
+ underTest.applyConstraints(constraintSet)
+ assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE)
+ assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(VISIBLE)
+ }
+ @Test
+ fun testCustomDateWeatherVisibility() {
+ whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay.value).thenReturn(true)
+ underTest.addViews(constraintLayout)
+ underTest.applyConstraints(constraintSet)
+
+ assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE)
+ assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(GONE)
+ }
+
+ private fun assertWeatherSmartspaceConstrains(cs: ConstraintSet) {
+ val weatherConstraints = cs.getConstraint(weatherView.id)
+ assertThat(weatherConstraints.layout.topToTop).isEqualTo(dateView.id)
+ assertThat(weatherConstraints.layout.bottomToBottom).isEqualTo(dateView.id)
+ assertThat(weatherConstraints.layout.startToEnd).isEqualTo(dateView.id)
+ assertThat(weatherConstraints.layout.startMargin).isEqualTo(4)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
new file mode 100644
index 0000000..46a7735
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.provider.Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK
+import androidx.test.filters.SmallTest
+import com.android.keyguard.ClockEventController
+import com.android.keyguard.KeyguardClockSwitch.LARGE
+import com.android.keyguard.KeyguardClockSwitch.SMALL
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardClockViewModelTest : SysuiTestCase() {
+ private lateinit var scheduler: TestCoroutineScheduler
+ private lateinit var dispatcher: CoroutineDispatcher
+ private lateinit var scope: TestScope
+
+ private lateinit var underTest: KeyguardClockViewModel
+ private lateinit var keyguardInteractor: KeyguardInteractor
+ private lateinit var keyguardRepository: KeyguardRepository
+ private lateinit var keyguardClockInteractor: KeyguardClockInteractor
+ private lateinit var keyguardClockRepository: KeyguardClockRepository
+ private lateinit var fakeSettings: FakeSettings
+ @Mock private lateinit var clockRegistry: ClockRegistry
+ @Mock private lateinit var eventController: ClockEventController
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ KeyguardInteractorFactory.create().let {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ }
+ fakeSettings = FakeSettings()
+ scheduler = TestCoroutineScheduler()
+ dispatcher = StandardTestDispatcher(scheduler)
+ scope = TestScope(dispatcher)
+ keyguardClockRepository = KeyguardClockRepository(fakeSettings, clockRegistry, dispatcher)
+ keyguardClockInteractor = KeyguardClockInteractor(eventController, keyguardClockRepository)
+ underTest =
+ KeyguardClockViewModel(
+ keyguardInteractor,
+ keyguardClockInteractor,
+ scope.backgroundScope
+ )
+ }
+
+ @Test
+ fun testClockSize_alwaysSmallClock() =
+ scope.runTest {
+ // When use double line clock is disabled,
+ // should always return small
+ fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 0)
+ keyguardRepository.setClockSize(LARGE)
+ val value = collectLastValue(underTest.clockSize)
+ assertThat(value()).isEqualTo(SMALL)
+ }
+
+ @Test
+ fun testClockSize_dynamicClockSize() =
+ scope.runTest {
+ fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1)
+ keyguardRepository.setClockSize(SMALL)
+ var value = collectLastValue(underTest.clockSize)
+ assertThat(value()).isEqualTo(SMALL)
+
+ keyguardRepository.setClockSize(LARGE)
+ value = collectLastValue(underTest.clockSize)
+ assertThat(value()).isEqualTo(LARGE)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 4a1386e..985b6fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -21,8 +21,12 @@
import android.view.View
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
@@ -319,12 +323,10 @@
@Component(modules = [SysUITestModule::class])
@SysUISingleton
- interface TestComponent {
- val underTest: KeyguardRootViewModel
+ interface TestComponent : SysUITestComponent<KeyguardRootViewModel> {
val deviceEntryRepository: FakeDeviceEntryRepository
val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
val repository: FakeKeyguardRepository
- val testScope: TestScope
val transitionRepository: FakeKeyguardTransitionRepository
@Component.Factory
@@ -356,28 +358,25 @@
TestMocksModule(
dozeParameters = dozeParams,
screenOffAnimationController = screenOffAnimController,
- )
+ ),
)
- .run {
+ .runTest {
reset(clockController)
underTest.clockControllerProvider = Provider { clockController }
- testScope.runTest {
- runCurrent()
- block()
- }
+ block()
}
@Test
fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
transitionRepository.sendTransitionSteps(
from = KeyguardState.OFF,
to = KeyguardState.GONE,
testScope,
)
whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isFalse()
assertThat(isVisible?.isAnimating).isFalse()
@@ -385,33 +384,33 @@
@Test
fun iconContainer_isVisible_bypassEnabled() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
deviceEntryRepository.setBypassEnabled(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isTrue()
}
@Test
fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(true)
deviceEntryRepository.setBypassEnabled(false)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isEqualTo(false)
}
@Test
fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(false)
deviceEntryRepository.setBypassEnabled(true)
notifsKeyguardRepository.setNotificationsFullyHidden(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isTrue()
assertThat(isVisible?.isAnimating).isTrue()
@@ -419,13 +418,13 @@
@Test
fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(false)
deviceEntryRepository.setBypassEnabled(false)
whenever(dozeParams.alwaysOn).thenReturn(false)
notifsKeyguardRepository.setNotificationsFullyHidden(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isTrue()
assertThat(isVisible?.isAnimating).isFalse()
@@ -433,14 +432,14 @@
@Test
fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(false)
deviceEntryRepository.setBypassEnabled(false)
whenever(dozeParams.alwaysOn).thenReturn(true)
whenever(dozeParams.displayNeedsBlanking).thenReturn(true)
notifsKeyguardRepository.setNotificationsFullyHidden(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isTrue()
assertThat(isVisible?.isAnimating).isFalse()
@@ -448,14 +447,14 @@
@Test
fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(false)
deviceEntryRepository.setBypassEnabled(false)
whenever(dozeParams.alwaysOn).thenReturn(true)
whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
notifsKeyguardRepository.setNotificationsFullyHidden(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.value).isTrue()
assertThat(isVisible?.isAnimating).isTrue()
@@ -463,18 +462,18 @@
@Test
fun isIconContainerVisible_stopAnimation() = runTest {
- val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
- testScope.runCurrent()
+ val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+ runCurrent()
notifsKeyguardRepository.setPulseExpanding(false)
deviceEntryRepository.setBypassEnabled(false)
whenever(dozeParams.alwaysOn).thenReturn(true)
whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
notifsKeyguardRepository.setNotificationsFullyHidden(true)
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.isAnimating).isEqualTo(true)
isVisible?.stopAnimating()
- testScope.runCurrent()
+ runCurrent()
assertThat(isVisible?.isAnimating).isEqualTo(false)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
new file mode 100644
index 0000000..2cb7e65
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.util
+
+import android.app.ActivityManager
+import android.content.ComponentName
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+/**
+ * Configures an ActivityManagerWrapper mock to return the given class name whenever we ask for the
+ * running task's top activity class name.
+ */
+fun ActivityManagerWrapper.mockTopActivityClassName(name: String) {
+ val topActivityMock = mock<ComponentName>().apply { whenever(className).thenReturn(name) }
+
+ whenever(runningTask)
+ .thenReturn(ActivityManager.RunningTaskInfo().apply { topActivity = topActivityMock })
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index 95ee3b7..bd1c310 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -41,7 +41,7 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- underTest = QSTileIntentUserInputHandler(activityStarted)
+ underTest = QSTileIntentUserInputHandlerImpl(activityStarted)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index 6d358db..70a48f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -30,8 +30,10 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
import com.android.systemui.model.SysUiState
import com.android.systemui.navigationbar.NavigationBarController
import com.android.systemui.navigationbar.NavigationModeController
@@ -100,6 +102,9 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock
+ private lateinit var inWindowLauncherUnlockAnimationManager:
+ InWindowLauncherUnlockAnimationManager
@Mock private lateinit var assistUtils: AssistUtils
@Mock
private lateinit var unfoldTransitionProgressForwarder:
@@ -126,6 +131,7 @@
whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
.thenReturn(mock(ResolveInfo::class.java))
+ featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
subject =
OverviewProxyService(
context,
@@ -144,6 +150,7 @@
uiEventLogger,
displayTracker,
sysuiUnlockAnimationController,
+ inWindowLauncherUnlockAnimationManager,
assistUtils,
featureFlags,
FakeSceneContainerFlags(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index d669006..ddeb05b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.sceneKeys
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -70,10 +71,8 @@
@Test(expected = IllegalStateException::class)
fun setDesiredScene_noSuchSceneInContainer_throws() {
- val underTest =
- utils.fakeSceneContainerRepository(
- utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
- )
+ utils.kosmos.sceneKeys = listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
+ val underTest = utils.fakeSceneContainerRepository(utils.fakeSceneContainerConfig())
underTest.setDesiredScene(SceneModel(SceneKey.Shade))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index c0b5861..f6362fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
import com.android.systemui.model.SysUiState
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
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 446a0b8..2f72704 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -133,7 +133,6 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.QsFrameTranslateController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
@@ -218,7 +217,6 @@
@Mock protected ViewPropertyAnimator mViewPropertyAnimator;
@Mock protected KeyguardBottomAreaView mQsFrame;
@Mock protected HeadsUpManager mHeadsUpManager;
- @Mock protected NotificationShelfController mNotificationShelfController;
@Mock protected NotificationGutsManager mGutsManager;
@Mock protected KeyguardStatusBarView mKeyguardStatusBar;
@Mock protected KeyguardUserSwitcherView mUserSwitcherView;
@@ -705,7 +703,6 @@
mCentralSurfaces,
null,
() -> {},
- mNotificationShelfController,
mHeadsUpManager);
mNotificationPanelViewController.setTrackingStartedListener(() -> {});
mNotificationPanelViewController.setOpenCloseListener(
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 0cc5716..ddfa9bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -202,7 +202,7 @@
/* indicationPadding= */ 0,
/* ambientPadding= */ 0);
- when(mNotificationShelfController.getIntrinsicHeight()).thenReturn(5);
+ when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5);
assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
.isEqualTo(5);
}
@@ -215,7 +215,7 @@
/* indicationPadding= */ 30,
/* ambientPadding= */ 0);
- when(mNotificationShelfController.getIntrinsicHeight()).thenReturn(5);
+ when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5);
assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
.isEqualTo(0);
}
@@ -228,7 +228,7 @@
/* indicationPadding= */ 0,
/* ambientPadding= */ 40);
- when(mNotificationShelfController.getIntrinsicHeight()).thenReturn(5);
+ when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5);
assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
.isEqualTo(0);
}
@@ -241,7 +241,7 @@
/* indicationPadding= */ 8,
/* ambientPadding= */ 0);
- when(mNotificationShelfController.getIntrinsicHeight()).thenReturn(5);
+ when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5);
assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
.isEqualTo(2);
}
@@ -254,7 +254,7 @@
/* indicationPadding= */ 8,
/* ambientPadding= */ 0);
- when(mNotificationShelfController.getIntrinsicHeight()).thenReturn(5);
+ when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5);
assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf())
.isEqualTo(0);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 8e0cf7d..a7e1e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -59,9 +59,12 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -76,6 +79,7 @@
import com.android.systemui.scene.shared.logger.SceneLogger;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
@@ -172,7 +176,7 @@
mTestScope.getBackgroundScope(),
new SceneContainerRepository(
mTestScope.getBackgroundScope(),
- mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+ mUtils.fakeSceneContainerConfig()),
powerRepository,
mock(SceneLogger.class));
@@ -207,7 +211,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 2f45b12..6d04887 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -45,9 +45,12 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -68,6 +71,7 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shade.transition.ShadeTransitionController;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -207,7 +211,7 @@
mTestScope.getBackgroundScope(),
new SceneContainerRepository(
mTestScope.getBackgroundScope(),
- mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+ mUtils.fakeSceneContainerConfig()),
powerRepository,
mock(SceneLogger.class));
@@ -241,7 +245,16 @@
keyguardInteractor,
featureFlags,
mShadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 8b8a625..ff7443f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -22,11 +22,14 @@
import android.content.pm.UserInfo
import android.os.UserManager
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -54,75 +57,70 @@
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
-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.mockito.Mock
-import org.mockito.MockitoAnnotations
@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
class ShadeInteractorTest : SysuiTestCase() {
- @Mock private lateinit var dozeParameters: DozeParameters
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<ShadeInteractor> {
- private lateinit var testComponent: TestComponent
+ val configurationRepository: FakeConfigurationRepository
+ val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+ val disableFlagsRepository: FakeDisableFlagsRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ val powerRepository: FakePowerRepository
+ val sceneInteractor: SceneInteractor
+ val shadeRepository: FakeShadeRepository
+ val userRepository: FakeUserRepository
+ val userSetupRepository: FakeUserSetupRepository
- private val configurationRepository
- get() = testComponent.configurationRepository
- private val deviceProvisioningRepository
- get() = testComponent.deviceProvisioningRepository
- private val disableFlagsRepository
- get() = testComponent.disableFlagsRepository
- private val keyguardRepository
- get() = testComponent.keyguardRepository
- private val keyguardTransitionRepository
- get() = testComponent.keygaurdTransitionRepository
- private val powerRepository
- get() = testComponent.powerRepository
- private val sceneInteractor
- get() = testComponent.sceneInteractor
- private val shadeRepository
- get() = testComponent.shadeRepository
- private val testScope
- get() = testComponent.testScope
- private val userRepository
- get() = testComponent.userRepository
- private val userSetupRepository
- get() = testComponent.userSetupRepository
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
+ }
- private lateinit var underTest: ShadeInteractor
+ private val dozeParameters: DozeParameters = mock()
+
+ private val testComponent: TestComponent =
+ DaggerShadeInteractorTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(Flags.FACE_AUTH_REFACTOR, false)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ },
+ mocks =
+ TestMocksModule(
+ dozeParameters = dozeParameters,
+ ),
+ )
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- testComponent =
- DaggerShadeInteractorTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParameters,
- ),
- )
- underTest = testComponent.underTest
-
runBlocking {
val userInfos =
listOf(
@@ -136,14 +134,16 @@
UserManager.USER_TYPE_FULL_SYSTEM,
),
)
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
+ testComponent.apply {
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ }
}
}
@Test
fun isShadeEnabled_matchesDisableFlagsRepo() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isShadeEnabled)
disableFlagsRepository.disableFlags.value =
@@ -157,7 +157,7 @@
@Test
fun isExpandToQsEnabled_deviceNotProvisioned_false() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(false)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -167,7 +167,7 @@
@Test
fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetup(false)
@@ -180,7 +180,7 @@
@Test
fun isExpandToQsEnabled_shadeNotEnabled_false() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetup(true)
@@ -196,7 +196,7 @@
@Test
fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetup(true)
@@ -211,7 +211,7 @@
@Test
fun isExpandToQsEnabled_dozing_false() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetup(true)
disableFlagsRepository.disableFlags.value =
@@ -228,7 +228,7 @@
@Test
fun isExpandToQsEnabled_userSetup_true() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -245,7 +245,7 @@
@Test
fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -262,7 +262,7 @@
@Test
fun isExpandToQsEnabled_respondsToDozingUpdates() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -290,7 +290,7 @@
@Test
fun isExpandToQsEnabled_respondsToDisableUpdates() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -322,7 +322,7 @@
@Test
fun isExpandToQsEnabled_respondsToUserUpdates() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -351,7 +351,7 @@
@Test
fun fullShadeExpansionWhenShadeLocked() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -362,7 +362,7 @@
@Test
fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -376,7 +376,7 @@
@Test
fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is enabled and QS is expanded
@@ -393,7 +393,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -409,7 +409,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
- testScope.runTest {
+ testComponent.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -423,7 +423,7 @@
@Test
fun anyExpansion_shadeGreater() =
- testScope.runTest() {
+ testComponent.runTest() {
// WHEN shade is more expanded than QS
shadeRepository.setLegacyShadeExpansion(.5f)
shadeRepository.setQsExpansion(0f)
@@ -435,7 +435,7 @@
@Test
fun anyExpansion_qsGreater() =
- testScope.runTest() {
+ testComponent.runTest() {
// WHEN qs is more expanded than shade
shadeRepository.setLegacyShadeExpansion(0f)
shadeRepository.setQsExpansion(.5f)
@@ -447,7 +447,7 @@
@Test
fun lockscreenShadeExpansion_idle_onScene() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.Shade
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -464,7 +464,7 @@
@Test
fun lockscreenShadeExpansion_idle_onDifferentScene() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an expansion flow based on transitions to and from a scene
val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
val expansionAmount by collectLastValue(expansion)
@@ -482,7 +482,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_toScene() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -520,7 +520,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_fromScene() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -558,7 +558,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an expansion flow based on transitions to and from a scene
val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
val expansionAmount by collectLastValue(expansion)
@@ -595,7 +595,7 @@
@Test
fun userInteractingWithShade_shadeDraggedUpAndDown() =
- testScope.runTest() {
+ testComponent.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -651,7 +651,7 @@
@Test
fun userInteractingWithShade_shadeExpanded() =
- testScope.runTest() {
+ testComponent.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -686,7 +686,7 @@
@Test
fun userInteractingWithShade_shadePartiallyExpanded() =
- testScope.runTest() {
+ testComponent.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -727,7 +727,7 @@
@Test
fun userInteractingWithShade_shadeCollapsed() =
- testScope.runTest() {
+ testComponent.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade expanded and not tracking input
shadeRepository.setLegacyShadeExpansion(1f)
@@ -762,7 +762,7 @@
@Test
fun userInteractingWithQs_qsDraggedUpAndDown() =
- testScope.runTest() {
+ testComponent.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithQs)
// GIVEN qs collapsed and not tracking input
shadeRepository.setQsExpansion(0f)
@@ -817,7 +817,7 @@
}
@Test
fun userInteracting_idle() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.Shade
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -834,7 +834,7 @@
@Test
fun userInteracting_transitioning_toScene_programmatic() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -872,7 +872,7 @@
@Test
fun userInteracting_transitioning_toScene_userInputDriven() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -910,7 +910,7 @@
@Test
fun userInteracting_transitioning_fromScene_programmatic() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -948,7 +948,7 @@
@Test
fun userInteracting_transitioning_fromScene_userInputDriven() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -986,7 +986,7 @@
@Test
fun userInteracting_transitioning_toAndFromDifferentScenes() =
- testScope.runTest() {
+ testComponent.runTest() {
// GIVEN an interacting flow based on transitions to and from a scene
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
val interacting by collectLastValue(interactingFlow)
@@ -1011,7 +1011,7 @@
@Test
fun isShadeTouchable_isFalse_whenFrpIsActive() =
- testScope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setFactoryResetProtectionActive(true)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -1025,7 +1025,7 @@
@Test
fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
- testScope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1052,7 +1052,7 @@
@Test
fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
- testScope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1079,7 +1079,7 @@
@Test
fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- testScope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1101,7 +1101,7 @@
@Test
fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
- testScope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1123,7 +1123,7 @@
@Test
fun isShadeTouchable_isTrue_whenNotAsleep() =
- testScope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1138,38 +1138,4 @@
runCurrent()
assertThat(isShadeTouchable).isTrue()
}
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent {
-
- val underTest: ShadeInteractor
-
- val configurationRepository: FakeConfigurationRepository
- val deviceProvisioningRepository: FakeDeviceProvisioningRepository
- val disableFlagsRepository: FakeDisableFlagsRepository
- val keyguardRepository: FakeKeyguardRepository
- val keygaurdTransitionRepository: FakeKeyguardTransitionRepository
- val powerRepository: FakePowerRepository
- val sceneInteractor: SceneInteractor
- val shadeRepository: FakeShadeRepository
- val testScope: TestScope
- val userRepository: FakeUserRepository
- val userSetupRepository: FakeUserSetupRepository
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index d6dfc5e..4b79a49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -29,9 +29,12 @@
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -131,7 +134,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor)
+ powerInteractor,
+ {
+ InWindowLauncherUnlockAnimationInteractor(
+ InWindowLauncherUnlockAnimationRepository(),
+ testScope,
+ keyguardTransitionInteractor,
+ { FakeKeyguardSurfaceBehindRepository() },
+ mock(),
+ )
+ })
fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
index 2f8f3bb..d479937 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
@@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.statusbar.notification.data.repository
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.util.mockito.whenever
@@ -28,69 +30,17 @@
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.mockito.Mockito.verify
@SmallTest
class NotificationsKeyguardViewStateRepositoryTest : SysuiTestCase() {
- private val testComponent: TestComponent =
- DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory()
- .create(test = this)
-
- @Test
- fun areNotifsFullyHidden_reflectsWakeUpCoordinator() =
- with(testComponent) {
- testScope.runTest {
- whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false)
- val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
- runCurrent()
-
- assertThat(notifsFullyHidden).isFalse()
-
- withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
- .onFullyHiddenChanged(true)
- runCurrent()
-
- assertThat(notifsFullyHidden).isTrue()
- }
- }
-
- @Test
- fun isPulseExpanding_reflectsWakeUpCoordinator() =
- with(testComponent) {
- testScope.runTest {
- whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false)
- val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
- runCurrent()
-
- assertThat(isPulseExpanding).isFalse()
-
- withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
- .onPulseExpansionChanged(true)
- runCurrent()
-
- assertThat(isPulseExpanding).isTrue()
- }
- }
-
@SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- ]
- )
- interface TestComponent {
-
- val underTest: NotificationsKeyguardViewStateRepositoryImpl
+ @Component(modules = [SysUITestModule::class])
+ interface TestComponent : SysUITestComponent<NotificationsKeyguardViewStateRepositoryImpl> {
val mockWakeUpCoordinator: NotificationWakeUpCoordinator
- val testScope: TestScope
@Component.Factory
interface Factory {
@@ -99,4 +49,40 @@
): TestComponent
}
}
+
+ private val testComponent: TestComponent =
+ DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory()
+ .create(test = this)
+
+ @Test
+ fun areNotifsFullyHidden_reflectsWakeUpCoordinator() =
+ testComponent.runTest {
+ whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false)
+ val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+ runCurrent()
+
+ assertThat(notifsFullyHidden).isFalse()
+
+ withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+ .onFullyHiddenChanged(true)
+ runCurrent()
+
+ assertThat(notifsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun isPulseExpanding_reflectsWakeUpCoordinator() =
+ testComponent.runTest {
+ whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false)
+ val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+ runCurrent()
+
+ assertThat(isPulseExpanding).isFalse()
+
+ withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+ .onPulseExpansionChanged(true)
+ runCurrent()
+
+ assertThat(isPulseExpanding).isTrue()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
index 683d0aa..707026e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
@@ -16,6 +16,7 @@
import android.app.StatusBarManager
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.SysUISingleton
@@ -31,8 +32,7 @@
@Component(modules = [SysUITestModule::class])
@SysUISingleton
- interface TestComponent {
- val underTest: NotificationAlertsInteractor
+ interface TestComponent : SysUITestComponent<NotificationAlertsInteractor> {
val disableFlags: FakeDisableFlagsRepository
@Component.Factory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
index 705a5a3..bb6f1b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
@@ -14,7 +14,11 @@
package com.android.systemui.statusbar.notification.domain.interactor
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
@@ -22,7 +26,6 @@
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -30,60 +33,48 @@
@SmallTest
class NotificationsKeyguardInteractorTest : SysuiTestCase() {
- private val testComponent: TestComponent =
- DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this)
-
- @Test
- fun areNotifsFullyHidden_reflectsRepository() =
- with(testComponent) {
- testScope.runTest {
- repository.setNotificationsFullyHidden(false)
- val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
- runCurrent()
-
- assertThat(notifsFullyHidden).isFalse()
-
- repository.setNotificationsFullyHidden(true)
- runCurrent()
-
- assertThat(notifsFullyHidden).isTrue()
- }
- }
-
- @Test
- fun isPulseExpanding_reflectsRepository() =
- with(testComponent) {
- testScope.runTest {
- repository.setPulseExpanding(false)
- val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
- runCurrent()
-
- assertThat(isPulseExpanding).isFalse()
-
- repository.setPulseExpanding(true)
- runCurrent()
-
- assertThat(isPulseExpanding).isTrue()
- }
- }
-
@SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- ]
- )
- interface TestComponent {
-
- val underTest: NotificationsKeyguardInteractor
+ @Component(modules = [SysUITestModule::class])
+ interface TestComponent : SysUITestComponent<NotificationsKeyguardInteractor> {
val repository: FakeNotificationsKeyguardViewStateRepository
- val testScope: TestScope
@Component.Factory
interface Factory {
fun create(@BindsInstance test: SysuiTestCase): TestComponent
}
}
+
+ private val testComponent: TestComponent =
+ DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this)
+
+ @Test
+ fun areNotifsFullyHidden_reflectsRepository() =
+ testComponent.runTest {
+ repository.setNotificationsFullyHidden(false)
+ val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+ runCurrent()
+
+ assertThat(notifsFullyHidden).isFalse()
+
+ repository.setNotificationsFullyHidden(true)
+ runCurrent()
+
+ assertThat(notifsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun isPulseExpanding_reflectsRepository() =
+ testComponent.runTest {
+ repository.setPulseExpanding(false)
+ val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+ runCurrent()
+
+ assertThat(isPulseExpanding).isFalse()
+
+ repository.setPulseExpanding(true)
+ runCurrent()
+
+ assertThat(isPulseExpanding).isTrue()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
index cc87d7c..a64ac67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
@@ -60,7 +60,7 @@
mView = (FooterView) LayoutInflater.from(mSpyContext).inflate(
R.layout.status_bar_notification_footer, null, false);
- mView.setDuration(0);
+ mView.setAnimationDuration(0);
}
@Test
@@ -107,10 +107,10 @@
@Test
public void testPerformSecondaryVisibilityAnimation() {
- mView.setSecondaryVisible(false /* visible */, false /* animate */);
- assertFalse(mView.isSecondaryVisible());
+ mView.setClearAllButtonVisible(false /* visible */, false /* animate */);
+ assertFalse(mView.isClearAllButtonVisible());
- mView.setSecondaryVisible(true /* visible */, true /* animate */);
+ mView.setClearAllButtonVisible(true /* visible */, true /* animate */);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index f8252a7..05deb1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -17,10 +17,12 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
@@ -43,8 +45,6 @@
import dagger.BindsInstance
import dagger.Component
import java.util.Optional
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,12 +57,10 @@
@Component(modules = [SysUITestModule::class])
@SysUISingleton
- interface TestComponent {
- val underTest: NotificationIconsInteractor
+ interface TestComponent : SysUITestComponent<NotificationIconsInteractor> {
val activeNotificationListRepository: ActiveNotificationListRepository
val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
- val testScope: TestScope
@Component.Factory
interface Factory {
@@ -75,97 +73,78 @@
.create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
@Before
- fun setup() =
- with(testComponent) {
+ fun setup() {
+ testComponent.apply {
activeNotificationListRepository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply { testIcons.forEach(::addIndividualNotif) }
.build()
}
+ }
@Test
fun filteredEntrySet() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.filteredNotifSet())
- assertThat(filteredSet).containsExactlyElementsIn(testIcons)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet())
+ assertThat(filteredSet).containsExactlyElementsIn(testIcons)
}
@Test
fun filteredEntrySet_noExpandedBubbles() =
- with(testComponent) {
- testScope.runTest {
- whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
- val filteredSet by collectLastValue(underTest.filteredNotifSet())
- assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
- }
+ testComponent.runTest {
+ whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+ val filteredSet by collectLastValue(underTest.filteredNotifSet())
+ assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
}
@Test
fun filteredEntrySet_noAmbient() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
- assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsSuppressedFromStatusBar)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
+ assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsSuppressedFromStatusBar)
+ .doesNotContain(true)
}
@Test
fun filteredEntrySet_noLowPriority() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by
- collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
- assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
+ assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
}
@Test
fun filteredEntrySet_noDismissed() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by
- collectLastValue(underTest.filteredNotifSet(showDismissed = false))
- assertThat(filteredSet)
- .comparingElementsUsing(byIsRowDismissed)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false))
+ assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
}
@Test
fun filteredEntrySet_noRepliedMessages() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by
- collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
- assertThat(filteredSet)
- .comparingElementsUsing(byIsLastMessageFromReply)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by
+ collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsLastMessageFromReply)
+ .doesNotContain(true)
}
@Test
fun filteredEntrySet_noPulsing_notifsNotFullyHidden() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
- keyguardViewStateRepository.setNotificationsFullyHidden(false)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+ keyguardViewStateRepository.setNotificationsFullyHidden(false)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
}
@Test
fun filteredEntrySet_noPulsing_notifsFullyHidden() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
- keyguardViewStateRepository.setNotificationsFullyHidden(true)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+ keyguardViewStateRepository.setNotificationsFullyHidden(true)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
}
}
@@ -177,13 +156,11 @@
@Component(modules = [SysUITestModule::class])
@SysUISingleton
- interface TestComponent {
- val underTest: AlwaysOnDisplayNotificationIconsInteractor
+ interface TestComponent : SysUITestComponent<AlwaysOnDisplayNotificationIconsInteractor> {
val activeNotificationListRepository: ActiveNotificationListRepository
val deviceEntryRepository: FakeDeviceEntryRepository
val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
- val testScope: TestScope
@Component.Factory
interface Factory {
@@ -191,105 +168,88 @@
}
}
- val testComponent: TestComponent =
+ private val testComponent: TestComponent =
DaggerAlwaysOnDisplayNotificationIconsInteractorTest_TestComponent.factory()
.create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
@Before
- fun setup() =
- with(testComponent) {
+ fun setup() {
+ testComponent.apply {
activeNotificationListRepository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply { testIcons.forEach(::addIndividualNotif) }
.build()
}
+ }
@Test
fun filteredEntrySet_noExpandedBubbles() =
- with(testComponent) {
- testScope.runTest {
- whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
- val filteredSet by collectLastValue(underTest.aodNotifs)
- assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
- }
+ testComponent.runTest {
+ whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
}
@Test
fun filteredEntrySet_noAmbient() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsSuppressedFromStatusBar)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsSuppressedFromStatusBar)
+ .doesNotContain(true)
}
@Test
fun filteredEntrySet_noDismissed() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsRowDismissed)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
}
@Test
fun filteredEntrySet_noRepliedMessages() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsLastMessageFromReply)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsLastMessageFromReply)
+ .doesNotContain(true)
}
@Test
fun filteredEntrySet_showPulsing_notifsNotFullyHidden_bypassDisabled() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- deviceEntryRepository.setBypassEnabled(false)
- keyguardViewStateRepository.setNotificationsFullyHidden(false)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ deviceEntryRepository.setBypassEnabled(false)
+ keyguardViewStateRepository.setNotificationsFullyHidden(false)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
}
@Test
fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassDisabled() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- deviceEntryRepository.setBypassEnabled(false)
- keyguardViewStateRepository.setNotificationsFullyHidden(true)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ deviceEntryRepository.setBypassEnabled(false)
+ keyguardViewStateRepository.setNotificationsFullyHidden(true)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
}
@Test
fun filteredEntrySet_noPulsing_notifsNotFullyHidden_bypassEnabled() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- deviceEntryRepository.setBypassEnabled(true)
- keyguardViewStateRepository.setNotificationsFullyHidden(false)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ deviceEntryRepository.setBypassEnabled(true)
+ keyguardViewStateRepository.setNotificationsFullyHidden(false)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
}
@Test
fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassEnabled() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.aodNotifs)
- deviceEntryRepository.setBypassEnabled(true)
- keyguardViewStateRepository.setNotificationsFullyHidden(true)
- assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.aodNotifs)
+ deviceEntryRepository.setBypassEnabled(true)
+ keyguardViewStateRepository.setNotificationsFullyHidden(true)
+ assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
}
}
@@ -301,13 +261,11 @@
@Component(modules = [SysUITestModule::class])
@SysUISingleton
- interface TestComponent {
- val underTest: StatusBarNotificationIconsInteractor
+ interface TestComponent : SysUITestComponent<StatusBarNotificationIconsInteractor> {
val activeNotificationListRepository: ActiveNotificationListRepository
val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
val notificationListenerSettingsRepository: NotificationListenerSettingsRepository
- val testScope: TestScope
@Component.Factory
interface Factory {
@@ -320,76 +278,63 @@
.create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
@Before
- fun setup() =
- with(testComponent) {
+ fun setup() {
+ testComponent.apply {
activeNotificationListRepository.activeNotifications.value =
ActiveNotificationsStore.Builder()
.apply { testIcons.forEach(::addIndividualNotif) }
.build()
}
+ }
@Test
fun filteredEntrySet_noExpandedBubbles() =
- with(testComponent) {
- testScope.runTest {
- whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
- }
+ testComponent.runTest {
+ whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
}
@Test
fun filteredEntrySet_noAmbient() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsSuppressedFromStatusBar)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsSuppressedFromStatusBar)
+ .doesNotContain(true)
}
@Test
fun filteredEntrySet_noLowPriority_whenDontShowSilentIcons() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- notificationListenerSettingsRepository.showSilentStatusIcons.value = false
- assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ notificationListenerSettingsRepository.showSilentStatusIcons.value = false
+ assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
}
@Test
fun filteredEntrySet_showLowPriority_whenShowSilentIcons() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- notificationListenerSettingsRepository.showSilentStatusIcons.value = true
- assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ notificationListenerSettingsRepository.showSilentStatusIcons.value = true
+ assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
}
@Test
fun filteredEntrySet_noDismissed() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsRowDismissed)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
}
@Test
fun filteredEntrySet_noRepliedMessages() =
- with(testComponent) {
- testScope.runTest {
- val filteredSet by collectLastValue(underTest.statusBarNotifs)
- assertThat(filteredSet)
- .comparingElementsUsing(byIsLastMessageFromReply)
- .doesNotContain(true)
- }
+ testComponent.runTest {
+ val filteredSet by collectLastValue(underTest.statusBarNotifs)
+ assertThat(filteredSet)
+ .comparingElementsUsing(byIsLastMessageFromReply)
+ .doesNotContain(true)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
index 49e1493..788cfbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -41,6 +43,7 @@
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.stopAnimating
@@ -48,71 +51,78 @@
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
- @Mock private lateinit var dozeParams: DozeParameters
- @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ BiometricsDomainLayerModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent :
+ SysUITestComponent<NotificationIconContainerAlwaysOnDisplayViewModel> {
- private lateinit var testComponent: TestComponent
- private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
- get() = testComponent.underTest
- private val deviceProvisioningRepository: FakeDeviceProvisioningRepository
- get() = testComponent.deviceProvisioningRepository
- private val keyguardRepository: FakeKeyguardRepository
- get() = testComponent.keyguardRepository
- private val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- get() = testComponent.keyguardTransitionRepository
- private val powerRepository: FakePowerRepository
- get() = testComponent.powerRepository
- private val scope: TestScope
- get() = testComponent.scope
+ val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ val powerRepository: FakePowerRepository
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ ): TestComponent
+ }
+ }
+
+ private val dozeParams: DozeParameters = mock()
+ private val screenOffAnimController: ScreenOffAnimationController = mock()
+
+ private val testComponent: TestComponent =
+ DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ setDefault(Flags.FACE_AUTH_REFACTOR)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+ setDefault(Flags.NEW_AOD_TRANSITION)
+ },
+ mocks =
+ TestMocksModule(
+ dozeParameters = dozeParams,
+ screenOffAnimationController = screenOffAnimController,
+ ),
+ )
@Before
fun setup() {
- MockitoAnnotations.initMocks(this)
-
- testComponent =
- DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule {
- setDefault(Flags.FACE_AUTH_REFACTOR)
- set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
- setDefault(Flags.NEW_AOD_TRANSITION)
- },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParams,
- screenOffAnimationController = screenOffAnimController,
- ),
- )
-
- keyguardRepository.setKeyguardShowing(true)
- keyguardRepository.setKeyguardOccluded(false)
- deviceProvisioningRepository.setFactoryResetProtectionActive(false)
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.OTHER,
- lastSleepReason = WakeSleepReason.OTHER,
- )
+ testComponent.apply {
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setKeyguardOccluded(false)
+ deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ }
}
@Test
fun animationsEnabled_isFalse_whenFrpIsActive() =
- scope.runTest {
+ testComponent.runTest {
deviceProvisioningRepository.setFactoryResetProtectionActive(true)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -126,7 +136,7 @@
@Test
fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
- scope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -149,7 +159,7 @@
@Test
fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
- scope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -172,7 +182,7 @@
@Test
fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- scope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -193,7 +203,7 @@
@Test
fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
- scope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -214,7 +224,7 @@
@Test
fun animationsEnabled_isTrue_whenNotAsleep() =
- scope.runTest {
+ testComponent.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -232,7 +242,7 @@
@Test
fun animationsEnabled_isTrue_whenKeyguardIsShowing() =
- scope.runTest {
+ testComponent.runTest {
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
@@ -261,7 +271,7 @@
@Test
fun isDozing_startAodTransition() =
- scope.runTest {
+ testComponent.runTest {
val isDozing by collectLastValue(underTest.isDozing)
runCurrent()
keyguardTransitionRepository.sendTransitionStep(
@@ -278,7 +288,7 @@
@Test
fun isDozing_startDozeTransition() =
- scope.runTest {
+ testComponent.runTest {
val isDozing by collectLastValue(underTest.isDozing)
runCurrent()
keyguardTransitionRepository.sendTransitionStep(
@@ -295,7 +305,7 @@
@Test
fun isDozing_startDozeToAodTransition() =
- scope.runTest {
+ testComponent.runTest {
val isDozing by collectLastValue(underTest.isDozing)
runCurrent()
keyguardTransitionRepository.sendTransitionStep(
@@ -312,7 +322,7 @@
@Test
fun isNotDozing_startAodToGoneTransition() =
- scope.runTest {
+ testComponent.runTest {
val isDozing by collectLastValue(underTest.isDozing)
runCurrent()
keyguardTransitionRepository.sendTransitionStep(
@@ -329,7 +339,7 @@
@Test
fun isDozing_stopAnimation() =
- scope.runTest {
+ testComponent.runTest {
val isDozing by collectLastValue(underTest.isDozing)
runCurrent()
keyguardTransitionRepository.sendTransitionStep(
@@ -347,33 +357,4 @@
assertThat(isDozing?.isAnimating).isEqualTo(false)
}
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- BiometricsDomainLayerModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent {
-
- val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
-
- val deviceProvisioningRepository: FakeDeviceProvisioningRepository
- val keyguardRepository: FakeKeyguardRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val powerRepository: FakePowerRepository
- val scope: TestScope
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- mocks: TestMocksModule,
- featureFlags: FakeFeatureFlagsClassicModule,
- ): TestComponent
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index 44acac8..1a04a3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.statusbar.notification.icon.ui.viewmodel
@@ -21,11 +20,14 @@
import android.graphics.drawable.Icon
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -57,343 +59,14 @@
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
- @Mock lateinit var dozeParams: DozeParameters
-
- private lateinit var testComponent: TestComponent
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
-
- testComponent =
- DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, value = false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
- },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParams,
- ),
- )
- .apply {
- keyguardRepository.setKeyguardShowing(false)
- deviceProvisioningRepository.setFactoryResetProtectionActive(false)
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.OTHER,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- }
- }
-
- @Test
- fun animationsEnabled_isFalse_whenFrpIsActive() =
- with(testComponent) {
- scope.runTest {
- deviceProvisioningRepository.setFactoryResetProtectionActive(true)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- )
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
- }
- }
-
- @Test
- fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
- with(testComponent) {
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.ASLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- )
- )
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(
- to = DozeStateModel.DOZE_AOD,
- )
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
- }
- }
-
- @Test
- fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
- with(testComponent) {
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.ASLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- )
- )
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(
- to = DozeStateModel.DOZE_PULSING,
- )
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
- }
- }
-
- @Test
- fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- with(testComponent) {
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.STARTING_TO_SLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- transitionState = TransitionState.STARTED,
- )
- )
- whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isFalse()
- }
- }
-
- @Test
- fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
- with(testComponent) {
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.STARTING_TO_SLEEP,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- transitionState = TransitionState.STARTED,
- )
- )
- whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
- }
- }
-
- @Test
- fun animationsEnabled_isTrue_whenNotAsleep() =
- with(testComponent) {
- scope.runTest {
- powerRepository.updateWakefulness(
- rawState = WakefulnessState.AWAKE,
- lastWakeReason = WakeSleepReason.POWER_BUTTON,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- )
- )
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
- runCurrent()
- assertThat(animationsEnabled).isTrue()
- }
- }
-
- @Test
- fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
- with(testComponent) {
- scope.runTest {
- val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- transitionState = TransitionState.STARTED,
- )
- )
- keyguardRepository.setKeyguardShowing(true)
- runCurrent()
-
- assertThat(animationsEnabled).isFalse()
-
- keyguardRepository.setKeyguardShowing(false)
- runCurrent()
-
- assertThat(animationsEnabled).isTrue()
- }
- }
-
- @Test
- fun iconColors_testsDarkBounds() =
- with(testComponent) {
- scope.runTest {
- darkIconRepository.darkState.value =
- SysuiDarkIconDispatcher.DarkChange(
- emptyList(),
- 0f,
- 0xAABBCC,
- )
- val iconColorsLookup by collectLastValue(underTest.iconColors)
- assertThat(iconColorsLookup).isNotNull()
-
- val iconColors = iconColorsLookup?.iconColors(Rect())
- assertThat(iconColors).isNotNull()
- iconColors!!
-
- assertThat(iconColors.tint).isEqualTo(0xAABBCC)
-
- val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true)
-
- assertThat(staticDrawableColor).isEqualTo(0xAABBCC)
- }
- }
-
- @Test
- fun iconColors_staticDrawableColor_nonColorized() =
- with(testComponent) {
- scope.runTest {
- darkIconRepository.darkState.value =
- SysuiDarkIconDispatcher.DarkChange(
- emptyList(),
- 0f,
- 0xAABBCC,
- )
- val iconColorsLookup by collectLastValue(underTest.iconColors)
- val iconColors = iconColorsLookup?.iconColors(Rect())
- val staticDrawableColor =
- iconColors?.staticDrawableColor(Rect(), isColorized = false)
- assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
- }
- }
-
- @Test
- fun iconColors_staticDrawableColor_isColorized_notInDarkTintArea() =
- with(testComponent) {
- scope.runTest {
- darkIconRepository.darkState.value =
- SysuiDarkIconDispatcher.DarkChange(
- listOf(Rect(0, 0, 5, 5)),
- 0f,
- 0xAABBCC,
- )
- val iconColorsLookup by collectLastValue(underTest.iconColors)
- val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4))
- val staticDrawableColor =
- iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true)
- assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
- }
- }
-
- @Test
- fun iconColors_notInDarkTintArea() =
- with(testComponent) {
- scope.runTest {
- darkIconRepository.darkState.value =
- SysuiDarkIconDispatcher.DarkChange(
- listOf(Rect(0, 0, 5, 5)),
- 0f,
- 0xAABBCC,
- )
- val iconColorsLookup by collectLastValue(underTest.iconColors)
- val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7))
- assertThat(iconColors).isNull()
- }
- }
-
- @Test
- fun isolatedIcon_animateOnAppear_shadeCollapsed() =
- with(testComponent) {
- scope.runTest {
- val icon: Icon = mock()
- shadeRepository.setLegacyShadeExpansion(0f)
- activeNotificationsRepository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- groupKey = "group",
- statusBarIcon = icon
- )
- )
- }
- .build()
- val isolatedIcon by collectLastValue(underTest.isolatedIcon)
- runCurrent()
-
- headsUpViewStateRepository.isolatedNotification.value = "notif1"
- runCurrent()
-
- assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
- assertThat(isolatedIcon?.isAnimating).isTrue()
- }
- }
-
- @Test
- fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
- with(testComponent) {
- scope.runTest {
- val icon: Icon = mock()
- shadeRepository.setLegacyShadeExpansion(.5f)
- activeNotificationsRepository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- groupKey = "group",
- statusBarIcon = icon
- )
- )
- }
- .build()
- val isolatedIcon by collectLastValue(underTest.isolatedIcon)
- runCurrent()
-
- headsUpViewStateRepository.isolatedNotification.value = "notif1"
- runCurrent()
-
- assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
- assertThat(isolatedIcon?.isAnimating).isFalse()
- }
- }
-
@SysUISingleton
@Component(
modules =
@@ -403,9 +76,7 @@
UserDomainLayerModule::class,
]
)
- interface TestComponent {
-
- val underTest: NotificationIconContainerStatusBarViewModel
+ interface TestComponent : SysUITestComponent<NotificationIconContainerStatusBarViewModel> {
val activeNotificationsRepository: ActiveNotificationListRepository
val darkIconRepository: FakeDarkIconRepository
@@ -415,7 +86,6 @@
val keyguardRepository: FakeKeyguardRepository
val powerRepository: FakePowerRepository
val shadeRepository: FakeShadeRepository
- val scope: TestScope
@Component.Factory
interface Factory {
@@ -426,4 +96,297 @@
): TestComponent
}
}
+
+ private val dozeParams: DozeParameters = mock()
+
+ private val testComponent: TestComponent =
+ DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ setDefault(Flags.FACE_AUTH_REFACTOR)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+ },
+ mocks =
+ TestMocksModule(
+ dozeParameters = dozeParams,
+ ),
+ )
+
+ @Before
+ fun setup() {
+ testComponent.apply {
+ keyguardRepository.setKeyguardShowing(false)
+ deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ }
+ }
+
+ @Test
+ fun animationsEnabled_isFalse_whenFrpIsActive() =
+ testComponent.runTest {
+ deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
+
+ @Test
+ fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
+ testComponent.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(
+ to = DozeStateModel.DOZE_AOD,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
+
+ @Test
+ fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
+ testComponent.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(
+ to = DozeStateModel.DOZE_PULSING,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
+
+ @Test
+ fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
+ testComponent.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isFalse()
+ }
+
+ @Test
+ fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
+ testComponent.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
+
+ @Test
+ fun animationsEnabled_isTrue_whenNotAsleep() =
+ testComponent.runTest {
+ powerRepository.updateWakefulness(
+ rawState = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+ runCurrent()
+ assertThat(animationsEnabled).isTrue()
+ }
+
+ @Test
+ fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
+ testComponent.runTest {
+ val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ transitionState = TransitionState.STARTED,
+ )
+ )
+ keyguardRepository.setKeyguardShowing(true)
+ runCurrent()
+
+ assertThat(animationsEnabled).isFalse()
+
+ keyguardRepository.setKeyguardShowing(false)
+ runCurrent()
+
+ assertThat(animationsEnabled).isTrue()
+ }
+
+ @Test
+ fun iconColors_testsDarkBounds() =
+ testComponent.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ emptyList(),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ assertThat(iconColorsLookup).isNotNull()
+
+ val iconColors = iconColorsLookup?.iconColors(Rect())
+ assertThat(iconColors).isNotNull()
+ iconColors!!
+
+ assertThat(iconColors.tint).isEqualTo(0xAABBCC)
+
+ val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true)
+
+ assertThat(staticDrawableColor).isEqualTo(0xAABBCC)
+ }
+
+ @Test
+ fun iconColors_staticDrawableColor_nonColorized() =
+ testComponent.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ emptyList(),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect())
+ val staticDrawableColor = iconColors?.staticDrawableColor(Rect(), isColorized = false)
+ assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
+ }
+
+ @Test
+ fun iconColors_staticDrawableColor_isColorized_notInDarkTintArea() =
+ testComponent.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ listOf(Rect(0, 0, 5, 5)),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4))
+ val staticDrawableColor =
+ iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true)
+ assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
+ }
+
+ @Test
+ fun iconColors_notInDarkTintArea() =
+ testComponent.runTest {
+ darkIconRepository.darkState.value =
+ SysuiDarkIconDispatcher.DarkChange(
+ listOf(Rect(0, 0, 5, 5)),
+ 0f,
+ 0xAABBCC,
+ )
+ val iconColorsLookup by collectLastValue(underTest.iconColors)
+ val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7))
+ assertThat(iconColors).isNull()
+ }
+
+ @Test
+ fun isolatedIcon_animateOnAppear_shadeCollapsed() =
+ testComponent.runTest {
+ val icon: Icon = mock()
+ shadeRepository.setLegacyShadeExpansion(0f)
+ activeNotificationsRepository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ groupKey = "group",
+ statusBarIcon = icon
+ )
+ )
+ }
+ .build()
+ val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+ runCurrent()
+
+ headsUpViewStateRepository.isolatedNotification.value = "notif1"
+ runCurrent()
+
+ assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+ assertThat(isolatedIcon?.isAnimating).isTrue()
+ }
+
+ @Test
+ fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
+ testComponent.runTest {
+ val icon: Icon = mock()
+ shadeRepository.setLegacyShadeExpansion(.5f)
+ activeNotificationsRepository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ groupKey = "group",
+ statusBarIcon = icon
+ )
+ )
+ }
+ .build()
+ val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+ runCurrent()
+
+ headsUpViewStateRepository.isolatedNotification.value = "notif1"
+ runCurrent()
+
+ assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+ assertThat(isolatedIcon?.isAnimating).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 02a67d0..7423c2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
import android.os.PowerManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -34,111 +34,105 @@
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-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.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
@RunWith(AndroidTestingRunner::class)
@SmallTest
class NotificationShelfViewModelTest : SysuiTestCase() {
- @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Component(modules = [SysUITestModule::class, ActivatableNotificationViewModelModule::class])
+ @SysUISingleton
+ interface TestComponent : SysUITestComponent<NotificationShelfViewModel> {
- @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
- @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
- @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ val deviceEntryFaceAuthRepository: FakeDeviceEntryFaceAuthRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val powerRepository: FakePowerRepository
- private lateinit var testComponent: TestComponent
-
- @Before
- fun setUp() {
- whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
- testComponent =
- DaggerNotificationShelfViewModelTest_TestComponent.factory()
- .create(
- test = this,
- mocks =
- TestMocksModule(
- lockscreenShadeTransitionController = keyguardTransitionController,
- screenOffAnimationController = screenOffAnimationController,
- statusBarStateController = statusBarStateController,
- )
- )
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
}
+ private val keyguardTransitionController: LockscreenShadeTransitionController = mock()
+ private val screenOffAnimationController: ScreenOffAnimationController = mock {
+ whenever(allowWakeUpIfDozing()).thenReturn(true)
+ }
+ private val statusBarStateController: SysuiStatusBarStateController = mock()
+
+ private val testComponent: TestComponent =
+ DaggerNotificationShelfViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ mocks =
+ TestMocksModule(
+ lockscreenShadeTransitionController = keyguardTransitionController,
+ screenOffAnimationController = screenOffAnimationController,
+ statusBarStateController = statusBarStateController,
+ )
+ )
+
@Test
fun canModifyColorOfNotifications_whenKeyguardNotShowing() =
- with(testComponent) {
- testScope.runTest {
- val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+ testComponent.runTest {
+ val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
- keyguardRepository.setKeyguardShowing(false)
+ keyguardRepository.setKeyguardShowing(false)
- assertThat(canModifyNotifColor).isTrue()
- }
+ assertThat(canModifyNotifColor).isTrue()
}
@Test
fun canModifyColorOfNotifications_whenKeyguardShowingAndNotBypass() =
- with(testComponent) {
- testScope.runTest {
- val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+ testComponent.runTest {
+ val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
- keyguardRepository.setKeyguardShowing(true)
- deviceEntryFaceAuthRepository.isBypassEnabled.value = false
+ keyguardRepository.setKeyguardShowing(true)
+ deviceEntryFaceAuthRepository.isBypassEnabled.value = false
- assertThat(canModifyNotifColor).isTrue()
- }
+ assertThat(canModifyNotifColor).isTrue()
}
@Test
fun cannotModifyColorOfNotifications_whenBypass() =
- with(testComponent) {
- testScope.runTest {
- val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+ testComponent.runTest {
+ val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
- keyguardRepository.setKeyguardShowing(true)
- deviceEntryFaceAuthRepository.isBypassEnabled.value = true
+ keyguardRepository.setKeyguardShowing(true)
+ deviceEntryFaceAuthRepository.isBypassEnabled.value = true
- assertThat(canModifyNotifColor).isFalse()
- }
+ assertThat(canModifyNotifColor).isFalse()
}
@Test
fun isClickable_whenKeyguardShowing() =
- with(testComponent) {
- testScope.runTest {
- val isClickable by collectLastValue(underTest.isClickable)
+ testComponent.runTest {
+ val isClickable by collectLastValue(underTest.isClickable)
- keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setKeyguardShowing(true)
- assertThat(isClickable).isTrue()
- }
+ assertThat(isClickable).isTrue()
}
@Test
fun isNotClickable_whenKeyguardNotShowing() =
- with(testComponent) {
- testScope.runTest {
- val isClickable by collectLastValue(underTest.isClickable)
+ testComponent.runTest {
+ val isClickable by collectLastValue(underTest.isClickable)
- keyguardRepository.setKeyguardShowing(false)
+ keyguardRepository.setKeyguardShowing(false)
- assertThat(isClickable).isFalse()
- }
+ assertThat(isClickable).isFalse()
}
@Test
@@ -152,23 +146,4 @@
assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
}
-
- @Component(modules = [SysUITestModule::class, ActivatableNotificationViewModelModule::class])
- @SysUISingleton
- interface TestComponent {
-
- val underTest: NotificationShelfViewModel
- val deviceEntryFaceAuthRepository: FakeDeviceEntryFaceAuthRepository
- val keyguardRepository: FakeKeyguardRepository
- val powerRepository: FakePowerRepository
- val testScope: TestScope
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 957cb88..c8dbdc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -6,12 +6,12 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.res.R
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.StatusBarIconView
@@ -28,31 +28,23 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
-/**
- * Tests for {@link NotificationShelf}.
- */
+/** Tests for {@link NotificationShelf}. */
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
open class NotificationShelfTest : SysuiTestCase() {
- open val useShelfRefactor: Boolean = false
open val useSensitiveReveal: Boolean = false
private val flags = FakeFeatureFlags()
- @Mock
- private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator
- @Mock
- private lateinit var ambientState: AmbientState
- @Mock
- private lateinit var hostLayoutController: NotificationStackScrollLayoutController
- @Mock
- private lateinit var hostLayout: NotificationStackScrollLayout
- @Mock
- private lateinit var roundnessManager: NotificationRoundnessManager
+ @Mock private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator
+ @Mock private lateinit var ambientState: AmbientState
+ @Mock private lateinit var hostLayoutController: NotificationStackScrollLayoutController
+ @Mock private lateinit var hostLayout: NotificationStackScrollLayout
+ @Mock private lateinit var roundnessManager: NotificationRoundnessManager
private lateinit var shelf: NotificationShelf
@@ -60,24 +52,22 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
mDependency.injectTestDependency(FeatureFlags::class.java, flags)
- flags.set(Flags.NOTIFICATION_SHELF_REFACTOR, useShelfRefactor)
flags.set(Flags.SENSITIVE_REVEAL_ANIM, useSensitiveReveal)
flags.setDefault(Flags.IMPROVED_HUN_ANIMATIONS)
val root = FrameLayout(context)
- shelf = LayoutInflater.from(root.context)
- .inflate(/* resource = */ R.layout.status_bar_notification_shelf,
- /* root = */root,
- /* attachToRoot = */false) as NotificationShelf
+ shelf =
+ LayoutInflater.from(root.context)
+ .inflate(
+ /* resource = */ R.layout.status_bar_notification_shelf,
+ /* root = */ root,
+ /* attachToRoot = */ false
+ ) as NotificationShelf
whenever(ambientState.largeScreenShadeInterpolator).thenReturn(largeScreenShadeInterpolator)
whenever(ambientState.isSmallScreen).thenReturn(true)
- if (useShelfRefactor) {
- shelf.bind(ambientState, hostLayout, roundnessManager)
- } else {
- shelf.bind(ambientState, hostLayoutController)
- }
- shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
+ shelf.bind(ambientState, hostLayout, roundnessManager)
+ shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */ 5)
}
@Test
@@ -106,89 +96,59 @@
@Test
fun testX_inViewForClick() {
- val isXInView = shelf.isXInView(
- /* localX */ 5f,
- /* slop */ 5f,
- /* left */ 0f,
- /* right */ 10f)
+ val isXInView =
+ shelf.isXInView(/* localX */ 5f, /* slop */ 5f, /* left */ 0f, /* right */ 10f)
assertTrue(isXInView)
}
@Test
fun testXSlop_inViewForClick() {
- val isLeftXSlopInView = shelf.isXInView(
- /* localX */ -3f,
- /* slop */ 5f,
- /* left */ 0f,
- /* right */ 10f)
+ val isLeftXSlopInView =
+ shelf.isXInView(/* localX */ -3f, /* slop */ 5f, /* left */ 0f, /* right */ 10f)
assertTrue(isLeftXSlopInView)
- val isRightXSlopInView = shelf.isXInView(
- /* localX */ 13f,
- /* slop */ 5f,
- /* left */ 0f,
- /* right */ 10f)
+ val isRightXSlopInView =
+ shelf.isXInView(/* localX */ 13f, /* slop */ 5f, /* left */ 0f, /* right */ 10f)
assertTrue(isRightXSlopInView)
}
@Test
fun testX_notInViewForClick() {
- val isXLeftOfShelfInView = shelf.isXInView(
- /* localX */ -10f,
- /* slop */ 5f,
- /* left */ 0f,
- /* right */ 10f)
+ val isXLeftOfShelfInView =
+ shelf.isXInView(/* localX */ -10f, /* slop */ 5f, /* left */ 0f, /* right */ 10f)
assertFalse(isXLeftOfShelfInView)
- val isXRightOfShelfInView = shelf.isXInView(
- /* localX */ 20f,
- /* slop */ 5f,
- /* left */ 0f,
- /* right */ 10f)
+ val isXRightOfShelfInView =
+ shelf.isXInView(/* localX */ 20f, /* slop */ 5f, /* left */ 0f, /* right */ 10f)
assertFalse(isXRightOfShelfInView)
}
@Test
fun testY_inViewForClick() {
- val isYInView = shelf.isYInView(
- /* localY */ 5f,
- /* slop */ 5f,
- /* top */ 0f,
- /* bottom */ 10f)
+ val isYInView =
+ shelf.isYInView(/* localY */ 5f, /* slop */ 5f, /* top */ 0f, /* bottom */ 10f)
assertTrue(isYInView)
}
@Test
fun testYSlop_inViewForClick() {
- val isTopYSlopInView = shelf.isYInView(
- /* localY */ -3f,
- /* slop */ 5f,
- /* top */ 0f,
- /* bottom */ 10f)
+ val isTopYSlopInView =
+ shelf.isYInView(/* localY */ -3f, /* slop */ 5f, /* top */ 0f, /* bottom */ 10f)
assertTrue(isTopYSlopInView)
- val isBottomYSlopInView = shelf.isYInView(
- /* localY */ 13f,
- /* slop */ 5f,
- /* top */ 0f,
- /* bottom */ 10f)
+ val isBottomYSlopInView =
+ shelf.isYInView(/* localY */ 13f, /* slop */ 5f, /* top */ 0f, /* bottom */ 10f)
assertTrue(isBottomYSlopInView)
}
@Test
fun testY_notInViewForClick() {
- val isYAboveShelfInView = shelf.isYInView(
- /* localY */ -10f,
- /* slop */ 5f,
- /* top */ 0f,
- /* bottom */ 5f)
+ val isYAboveShelfInView =
+ shelf.isYInView(/* localY */ -10f, /* slop */ 5f, /* top */ 0f, /* bottom */ 5f)
assertFalse(isYAboveShelfInView)
- val isYBelowShelfInView = shelf.isYInView(
- /* localY */ 15f,
- /* slop */ 5f,
- /* top */ 0f,
- /* bottom */ 5f)
+ val isYBelowShelfInView =
+ shelf.isYInView(/* localY */ 15f, /* slop */ 5f, /* top */ 0f, /* bottom */ 5f)
assertFalse(isYBelowShelfInView)
}
@@ -210,12 +170,15 @@
whenever(ambientState.isExpansionChanging).thenReturn(false)
whenever(ambientState.isShadeExpanded).thenReturn(true)
- val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ val amountInShelf =
+ shelf.getAmountInShelf(
+ /* i= */ 0,
/* view= */ expandableView,
/* scrollingFast= */ false,
/* expandingAnimated= */ false,
/* isLastChild= */ true,
- shelfClipStart)
+ shelfClipStart
+ )
assertEquals(1f, amountInShelf)
}
@@ -237,12 +200,15 @@
whenever(ambientState.isExpansionChanging).thenReturn(false)
whenever(ambientState.isShadeExpanded).thenReturn(true)
- val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ val amountInShelf =
+ shelf.getAmountInShelf(
+ /* i= */ 0,
/* view= */ expandableView,
/* scrollingFast= */ false,
/* expandingAnimated= */ false,
/* isLastChild= */ true,
- shelfClipStart)
+ shelfClipStart
+ )
assertEquals(1f, amountInShelf)
}
@@ -264,12 +230,15 @@
whenever(ambientState.isExpansionChanging).thenReturn(false)
whenever(ambientState.isShadeExpanded).thenReturn(true)
- val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ val amountInShelf =
+ shelf.getAmountInShelf(
+ /* i= */ 0,
/* view= */ expandableView,
/* scrollingFast= */ false,
/* expandingAnimated= */ false,
/* isLastChild= */ true,
- shelfClipStart)
+ shelfClipStart
+ )
assertEquals(0.5f, amountInShelf)
}
@@ -290,20 +259,23 @@
whenever(ambientState.isExpansionChanging).thenReturn(false)
whenever(ambientState.isOnKeyguard).thenReturn(true)
- val amountInShelf = shelf.getAmountInShelf(/* i= */ 0,
+ val amountInShelf =
+ shelf.getAmountInShelf(
+ /* i= */ 0,
/* view= */ expandableView,
/* scrollingFast= */ false,
/* expandingAnimated= */ false,
/* isLastChild= */ true,
- shelfClipStart)
+ shelfClipStart
+ )
assertEquals(0f, amountInShelf)
}
@Test
fun updateState_expansionChanging_shelfTransparent() {
updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = 0.25f,
- expectedAlpha = 0.0f
+ expansionFraction = 0.25f,
+ expectedAlpha = 0.0f
)
}
@@ -312,16 +284,16 @@
whenever(ambientState.isBouncerInTransit).thenReturn(true)
updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = 0.85f,
- expectedAlpha = 0.0f
+ expansionFraction = 0.85f,
+ expectedAlpha = 0.0f
)
}
@Test
fun updateState_expansionChanging_shelfAlphaUpdated() {
updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = 0.6f,
- expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f),
+ expansionFraction = 0.6f,
+ expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f),
)
}
@@ -343,8 +315,8 @@
whenever(ambientState.isBouncerInTransit).thenReturn(true)
updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = 0.95f,
- expectedAlpha = aboutToShowBouncerProgress(0.95f),
+ expansionFraction = 0.95f,
+ expectedAlpha = aboutToShowBouncerProgress(0.95f),
)
}
@@ -353,8 +325,8 @@
whenever(ambientState.isBouncerInTransit).thenReturn(true)
updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction = 0.95f,
- expectedAlpha = aboutToShowBouncerProgress(0.95f),
+ expansionFraction = 0.95f,
+ expectedAlpha = aboutToShowBouncerProgress(0.95f),
)
}
@@ -488,11 +460,11 @@
}
private fun updateState_expansionChanging_shelfAlphaUpdated(
- expansionFraction: Float,
- expectedAlpha: Float
+ expansionFraction: Float,
+ expectedAlpha: Float
) {
whenever(ambientState.lastVisibleBackgroundChild)
- .thenReturn(ExpandableNotificationRow(mContext, null))
+ .thenReturn(ExpandableNotificationRow(mContext, null))
whenever(ambientState.isExpansionChanging).thenReturn(true)
whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
whenever(hostLayoutController.speedBumpIndex).thenReturn(0)
@@ -506,21 +478,6 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
-class NotificationShelfWithRefactorTest : NotificationShelfTest() {
- override val useShelfRefactor: Boolean = true
-}
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
class NotificationShelfWithSensitiveRevealTest : NotificationShelfTest() {
override val useSensitiveReveal: Boolean = true
}
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
-class NotificationShelfWithBothFlagsTest : NotificationShelfTest() {
- override val useShelfRefactor: Boolean = true
- override val useSensitiveReveal: Boolean = true
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 39e3d5da3..5903890 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -91,6 +91,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -113,8 +114,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
/**
* Tests for {@link NotificationStackScrollLayoutController}.
*/
@@ -143,7 +142,6 @@
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
@Mock private DumpManager mDumpManager;
- @Mock private Resources mResources;
@Mock(answer = Answers.RETURNS_SELF)
private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@@ -151,7 +149,6 @@
@Mock private GroupExpansionManager mGroupExpansionManager;
@Mock private SectionHeaderController mSilentHeaderController;
@Mock private NotifPipeline mNotifPipeline;
- @Mock private NotifPipelineFlags mNotifPipelineFlags;
@Mock private NotifCollection mNotifCollection;
@Mock private UiEventLogger mUiEventLogger;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -166,9 +163,9 @@
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock private NotificationTargetsHelper mNotificationTargetsHelper;
@Mock private SecureSettings mSecureSettings;
- @Mock private NotificationIconAreaController mIconAreaController;
@Mock private ActivityStarter mActivityStarter;
@Mock private KeyguardTransitionRepository mKeyguardTransitionRepo;
+ @Mock private NotificationListViewBinder mViewBinder;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -669,6 +666,7 @@
ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
when(mNotificationStackScrollLayout.getViewTreeObserver())
.thenReturn(viewTreeObserver);
+ when(mNotificationStackScrollLayout.getContext()).thenReturn(getContext());
mController = new NotificationStackScrollLayoutController(
mNotificationStackScrollLayout,
true,
@@ -689,38 +687,33 @@
mKeyguardTransitionRepo,
mZenModeController,
mNotificationLockscreenUserManager,
- Optional.<NotificationListViewModel>empty(),
mMetricsLogger,
mDumpManager,
new FalsingCollectorFake(),
new FalsingManagerFake(),
- mResources,
mNotificationSwipeHelperBuilder,
mScrimController,
mGroupExpansionManager,
mSilentHeaderController,
mNotifPipeline,
- mNotifPipelineFlags,
mNotifCollection,
mLockscreenShadeTransitionController,
mUiEventLogger,
mRemoteInputManager,
mVisibilityLocationProviderDelegator,
mSeenNotificationsInteractor,
+ mViewBinder,
mShadeController,
mJankMonitor,
mStackLogger,
mLogger,
mNotificationStackSizeCalculator,
- mIconAreaController,
mFeatureFlags,
mNotificationTargetsHelper,
mSecureSettings,
mock(NotificationDismissibilityProvider.class),
mActivityStarter,
- new ResourcesSplitShadeStateController(),
- mock(ConfigurationState.class),
- mock(ShelfNotificationIconViewStore.class));
+ new ResourcesSplitShadeStateController());
}
static class LogMatcher implements ArgumentMatcher<LogMaker> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 4af7864..6203531 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -75,7 +75,6 @@
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -162,7 +161,6 @@
// in the constructor.
mFeatureFlags.setDefault(Flags.SENSITIVE_REVEAL_ANIM);
mFeatureFlags.setDefault(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS);
- mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX);
@@ -179,9 +177,6 @@
mDependency.injectTestDependency(
ScreenOffAnimationController.class, mScreenOffAnimationController);
- NotificationShelfController notificationShelfController =
- mock(NotificationShelfController.class);
- when(notificationShelfController.getView()).thenReturn(mNotificationShelf);
when(mNotificationSectionsManager.createSectionsForBuckets()).thenReturn(
new NotificationSection[]{
mNotificationSection
@@ -196,18 +191,13 @@
mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper,
mNotificationStackSizeCalculator);
mStackScroller = spy(mStackScrollerInternal);
- if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- mStackScroller.setShelfController(notificationShelfController);
- }
mStackScroller.setNotificationsController(mNotificationsController);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true);
when(mStackScrollLayoutController.getNotificationRoundnessManager())
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
- if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
- mStackScroller.setShelf(mNotificationShelf);
- }
+ mStackScroller.setShelf(mNotificationShelf);
doNothing().when(mGroupExpansionManager).collapseGroups();
doNothing().when(mExpandHelper).cancelImmediately();
@@ -405,7 +395,7 @@
mStackScroller.updateFooterView(true, false, true);
verify(view).setVisible(eq(true), anyBoolean());
- verify(view).setSecondaryVisible(eq(false), anyBoolean());
+ verify(view).setClearAllButtonVisible(eq(false), anyBoolean());
}
@Test
@@ -417,7 +407,7 @@
mStackScroller.updateFooterView(true, true, true);
verify(view).setVisible(eq(true), anyBoolean());
- verify(view).setSecondaryVisible(eq(true), anyBoolean());
+ verify(view).setClearAllButtonVisible(eq(true), anyBoolean());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 3a9d111..22553df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -19,12 +19,15 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
import com.android.SysUITestModule
import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -47,70 +50,64 @@
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerViewModelTest : SysuiTestCase() {
- private lateinit var testComponent: TestComponent
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<SharedNotificationContainerViewModel> {
- private val shadeRepository
- get() = testComponent.shadeRepository
- private val keyguardRepository
- get() = testComponent.keyguardRepository
- private val configurationRepository
- get() = testComponent.configurationRepository
- private val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
- get() = testComponent.sharedNotificationContainerInteractor
- private val underTest: SharedNotificationContainerViewModel
- get() = testComponent.underTest
- private val keyguardInteractor: KeyguardInteractor
- get() = testComponent.keyguardInteractor
- private val keyguardTransitionRepository
- get() = testComponent.keyguardTransitionRepository
- private val testScope
- get() = testComponent.testScope
+ val configurationRepository: FakeConfigurationRepository
+ val keyguardRepository: FakeKeyguardRepository
+ val keyguardInteractor: KeyguardInteractor
+ val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+ val shadeRepository: FakeShadeRepository
+ val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
- @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
- @Mock
- private lateinit var notificationStackScrollLayoutController:
- NotificationStackScrollLayoutController
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
- whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
-
- testComponent =
- DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
- mocks =
- TestMocksModule(
- notificationStackSizeCalculator = notificationStackSizeCalculator,
- notificationStackScrollLayoutController =
- notificationStackScrollLayoutController,
- )
- )
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ mocks: TestMocksModule,
+ ): TestComponent
+ }
}
+ private val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock()
+ private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController =
+ mock {
+ whenever(view).thenReturn(mock())
+ whenever(shelfHeight).thenReturn(0)
+ }
+
+ private val testComponent: TestComponent =
+ DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
+ mocks =
+ TestMocksModule(
+ notificationStackSizeCalculator = notificationStackSizeCalculator,
+ notificationStackScrollLayoutController =
+ notificationStackScrollLayoutController,
+ )
+ )
+
@Test
fun validateMarginStartInSplitShade() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.bool.config_use_split_notification_shade, true)
overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
@@ -123,7 +120,7 @@
@Test
fun validateMarginStart() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.bool.config_use_split_notification_shade, false)
overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
@@ -136,7 +133,7 @@
@Test
fun validateMarginEnd() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -148,7 +145,7 @@
@Test
fun validateMarginBottom() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.dimen.notification_panel_margin_bottom, 50)
val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -160,7 +157,7 @@
@Test
fun validateMarginTopWithLargeScreenHeader() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.bool.config_use_large_screen_shade_header, true)
overrideResource(R.dimen.large_screen_shade_header_height, 50)
overrideResource(R.dimen.notification_panel_margin_top, 0)
@@ -174,7 +171,7 @@
@Test
fun validateMarginTop() =
- testScope.runTest {
+ testComponent.runTest {
overrideResource(R.bool.config_use_large_screen_shade_header, false)
overrideResource(R.dimen.large_screen_shade_header_height, 50)
overrideResource(R.dimen.notification_panel_margin_top, 0)
@@ -188,7 +185,7 @@
@Test
fun isOnLockscreen() =
- testScope.runTest {
+ testComponent.runTest {
val isOnLockscreen by collectLastValue(underTest.isOnLockscreen)
keyguardTransitionRepository.sendTransitionSteps(
@@ -212,7 +209,7 @@
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
- this,
+ testScope,
)
assertThat(isOnLockscreen).isTrue()
@@ -226,7 +223,7 @@
@Test
fun isOnLockscreenWithoutShade() =
- testScope.runTest {
+ testComponent.runTest {
val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
// First on AOD
@@ -262,7 +259,7 @@
@Test
fun positionOnLockscreenNotInSplitShade() =
- testScope.runTest {
+ testComponent.runTest {
val position by collectLastValue(underTest.position)
// When not in split shade
@@ -282,7 +279,7 @@
@Test
fun positionOnLockscreenInSplitShade() =
- testScope.runTest {
+ testComponent.runTest {
val position by collectLastValue(underTest.position)
// When in split shade
@@ -304,7 +301,7 @@
@Test
fun positionOnShade() =
- testScope.runTest {
+ testComponent.runTest {
val position by collectLastValue(underTest.position)
// Start on lockscreen with shade expanded
@@ -321,7 +318,7 @@
@Test
fun positionOnQS() =
- testScope.runTest {
+ testComponent.runTest {
val position by collectLastValue(underTest.position)
// Start on lockscreen with shade expanded
@@ -338,7 +335,7 @@
@Test
fun maxNotificationsOnLockscreen() =
- testScope.runTest {
+ testComponent.runTest {
whenever(
notificationStackSizeCalculator.computeMaxKeyguardNotifications(
any(),
@@ -363,7 +360,7 @@
@Test
fun maxNotificationsOnShade() =
- testScope.runTest {
+ testComponent.runTest {
whenever(
notificationStackSizeCalculator.computeMaxKeyguardNotifications(
any(),
@@ -387,66 +384,36 @@
assertThat(maxNotifications).isEqualTo(-1)
}
- private suspend fun TestScope.showLockscreen() {
+ private suspend fun TestComponent.showLockscreen() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(0f)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
- this,
+ testScope,
)
}
- private suspend fun TestScope.showLockscreenWithShadeExpanded() {
+ private suspend fun TestComponent.showLockscreenWithShadeExpanded() {
shadeRepository.setLockscreenShadeExpansion(1f)
shadeRepository.setQsExpansion(0f)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
- this,
+ testScope,
)
}
- private suspend fun TestScope.showLockscreenWithQSExpanded() {
+ private suspend fun TestComponent.showLockscreenWithQSExpanded() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(1f)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
- this,
+ testScope,
)
}
-
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent {
-
- val underTest: SharedNotificationContainerViewModel
-
- val configurationRepository: FakeConfigurationRepository
- val keyguardRepository: FakeKeyguardRepository
- val keyguardInteractor: KeyguardInteractor
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val shadeRepository: FakeShadeRepository
- val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
- val testScope: TestScope
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
}
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 4a20f83..86a5c52 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
@@ -143,7 +143,6 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
@@ -278,7 +277,6 @@
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@Mock private Lazy<NotificationShadeWindowViewController>
mNotificationShadeWindowViewControllerLazy;
- @Mock private NotificationShelfController mNotificationShelfController;
@Mock private DozeParameters mDozeParameters;
@Mock private DozeServiceHost mDozeServiceHost;
@Mock private BackActionInteractor mBackActionInteractor;
@@ -504,7 +502,6 @@
configurationController,
mNotificationShadeWindowController,
mNotificationShadeWindowViewControllerLazy,
- mNotificationShelfController,
mStackScrollerController,
(Lazy<NotificationPresenter>) () -> mNotificationPresenter,
(Lazy<NotificationActivityStarter>) () -> mNotificationActivityStarter,
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 8309b85..4f19742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -102,9 +102,12 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.repository.FakeCommandQueue;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
+import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository;
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.model.SysUiState;
@@ -126,6 +129,7 @@
import com.android.systemui.shade.ShadeWindowLogger;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.NotificationEntryHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -395,7 +399,7 @@
mTestScope.getBackgroundScope(),
new SceneContainerRepository(
mTestScope.getBackgroundScope(),
- mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())),
+ mUtils.fakeSceneContainerConfig()),
powerRepository,
mock(SceneLogger.class));
@@ -429,7 +433,16 @@
keyguardInteractor,
featureFlags,
shadeRepository,
- powerInteractor);
+ powerInteractor,
+ () ->
+ new InWindowLauncherUnlockAnimationInteractor(
+ new InWindowLauncherUnlockAnimationRepository(),
+ mTestScope.getBackgroundScope(),
+ keyguardTransitionInteractor,
+ () -> new FakeKeyguardSurfaceBehindRepository(),
+ mock(ActivityManagerWrapper.class)
+ )
+ );
mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor(
keyguardTransitionRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
index 08adda3..8a2ff50 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
@@ -1,6 +1,5 @@
package com.android.systemui.communal.data.repository
-import com.android.systemui.communal.data.model.CommunalWidgetMetadata
import com.android.systemui.communal.shared.model.CommunalAppWidgetInfo
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import kotlinx.coroutines.flow.Flow
@@ -10,7 +9,6 @@
class FakeCommunalWidgetRepository : CommunalWidgetRepository {
private val _stopwatchAppWidgetInfo = MutableStateFlow<CommunalAppWidgetInfo?>(null)
override val stopwatchAppWidgetInfo: Flow<CommunalAppWidgetInfo?> = _stopwatchAppWidgetInfo
- override var communalWidgetAllowlist: List<CommunalWidgetMetadata> = emptyList()
private val _communalWidgets = MutableStateFlow<List<CommunalWidgetContentModel>>(emptyList())
override val communalWidgets: Flow<List<CommunalWidgetContentModel>> = _communalWidgets
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
index abf72af..6838e76 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
@@ -17,6 +17,7 @@
import com.android.systemui.keyguard.data.repository.FakeCommandQueueModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepositoryModule
+import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepositoryModule
import dagger.Module
@@ -26,6 +27,7 @@
FakeCommandQueueModule::class,
FakeKeyguardRepositoryModule::class,
FakeKeyguardTransitionRepositoryModule::class,
+ FakeKeyguardSurfaceBehindRepositoryModule::class,
]
)
object FakeKeyguardDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 88a88c7..d3744d55 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.repository
import android.graphics.Point
+import com.android.keyguard.KeyguardClockSwitch.LARGE
import com.android.systemui.common.shared.model.Position
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
@@ -41,6 +42,11 @@
class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
+ private val _clockSize = MutableStateFlow<Int>(LARGE)
+ override val clockSize: Flow<Int> = _clockSize
+
+ private val _clockShouldBeCentered = MutableStateFlow<Boolean>(true)
+ override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered
private val _dismissAction = MutableStateFlow<DismissAction>(DismissAction.None)
override val dismissAction: StateFlow<DismissAction> = _dismissAction
@@ -177,6 +183,14 @@
_deferKeyguardDone.emit(timing)
}
+ override fun setClockSize(size: Int) {
+ _clockSize.value = size
+ }
+
+ override fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
+ _clockShouldBeCentered.value = shouldBeCentered
+ }
+
fun dozeTimeTick(millis: Long) {
_dozeTimeTick.value = millis
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
index 823f29a..70de05f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardSurfaceBehindRepository.kt
@@ -16,14 +16,31 @@
package com.android.systemui.keyguard.data.repository
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeKeyguardSurfaceBehindRepository : KeyguardSurfaceBehindRepository {
+@SysUISingleton
+class FakeKeyguardSurfaceBehindRepository @Inject constructor() : KeyguardSurfaceBehindRepository {
private val _isAnimatingSurface = MutableStateFlow(false)
override val isAnimatingSurface = _isAnimatingSurface.asStateFlow()
+ private val _isSurfaceAvailable = MutableStateFlow(false)
+ override val isSurfaceRemoteAnimationTargetAvailable = _isSurfaceAvailable.asStateFlow()
+
override fun setAnimatingSurface(animating: Boolean) {
_isAnimatingSurface.value = animating
}
+
+ override fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
+ _isSurfaceAvailable.value = available
+ }
+}
+
+@Module
+interface FakeKeyguardSurfaceBehindRepositoryModule {
+ @Binds fun bindFake(fake: FakeKeyguardSurfaceBehindRepository): KeyguardSurfaceBehindRepository
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
new file mode 100644
index 0000000..cc843b5
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.kosmos
+
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+
+val Kosmos.testDispatcher by Fixture { StandardTestDispatcher() }
+val Kosmos.testScope by Fixture { TestScope(testDispatcher) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/Kosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/Kosmos.kt
new file mode 100644
index 0000000..c74cdd4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/Kosmos.kt
@@ -0,0 +1,69 @@
+package com.android.systemui.kosmos
+
+import kotlin.reflect.KProperty
+
+// (Historical note: The name Kosmos is meant to invoke "Kotlin", the "Object Mother" pattern
+// (https://martinfowler.com/bliki/ObjectMother.html), and of course the Greek word "kosmos" for
+// the "order of the world" (https://en.wiktionary.org/wiki/%CE%BA%CF%8C%CF%83%CE%BC%CE%BF%CF%82)
+/**
+ * Each Kosmos is its own self-contained set of fixtures, which may reference each other. Fixtures
+ * can be defined through extension properties in any file:
+ * ```
+ * // fixture that must be set:
+ * var Kosmos.context by Fixture<Context>()
+ *
+ * // fixture with overrideable default.
+ * var Kosmos.landscapeMode by Fixture { false }
+ *
+ * // fixture forbidding override (note `val`, and referencing context fixture from above)
+ * val Kosmos.lifecycleScope by Fixture { context.lifecycleScope }
+ * ```
+ *
+ * To use the fixtures, create an instance of Kosmos and retrieve the values you need:
+ * ```
+ * val k = Kosmos()
+ * k.context = mContext
+ * val underTest = YourInteractor(
+ * context = k.context,
+ * landscapeMode = k.landscapeMode,
+ * )
+ * ```
+ */
+class Kosmos {
+ private val map: MutableMap<String, Any?> = mutableMapOf()
+ private val gotten: MutableSet<String> = mutableSetOf()
+
+ /**
+ * A value in the kosmos that has a single value once it's read. It can be overridden before
+ * first use only; all objects that are dependent on this fixture will get the same value.
+ *
+ * Example classic uses would be a clock, filesystem, or singleton controller.
+ *
+ * If no [creator] parameter is provided, the fixture must be set before use.
+ */
+ class Fixture<T>(private val creator: (Kosmos.() -> T)? = null) {
+ operator fun getValue(thisRef: Kosmos, property: KProperty<*>): T {
+ thisRef.gotten.add(property.name)
+ @Suppress("UNCHECKED_CAST")
+ if (!thisRef.map.contains(property.name)) {
+ if (creator == null) {
+ throw IllegalStateException(
+ "Fixture ${property.name} has no default, and is read before set."
+ )
+ } else {
+ val nonNullCreator = creator
+ // The Kotlin compiler seems to need this odd workaround
+ thisRef.map[property.name] = thisRef.nonNullCreator()
+ }
+ }
+ return thisRef.map[property.name] as T
+ }
+
+ operator fun setValue(thisRef: Kosmos, property: KProperty<*>, value: T) {
+ check(!thisRef.gotten.contains(property.name)) {
+ "Tried to set fixture '${property.name}' after it's already been read."
+ }
+ thisRef.map[property.name] = value
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
new file mode 100644
index 0000000..1185f2e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.actions
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.view.View
+
+/**
+ * Fake implementation of [QSTileIntentUserInputHandler] interface. Consider using this alongside
+ * [QSTileIntentUserInputHandlerSubject].
+ */
+class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler {
+
+ val handledInputs: List<Input>
+ get() = mutableInputs
+
+ private val mutableInputs = mutableListOf<Input>()
+
+ override fun handle(view: View?, intent: Intent) {
+ mutableInputs.add(Input.Intent(view, intent))
+ }
+
+ override fun handle(view: View?, pendingIntent: PendingIntent) {
+ mutableInputs.add(Input.PendingIntent(view, pendingIntent))
+ }
+
+ sealed interface Input {
+ data class Intent(val view: View?, val intent: android.content.Intent) : Input
+ data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) :
+ Input
+ }
+}
+
+val FakeQSTileIntentUserInputHandler.intentInputs
+ get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.Intent }
+val FakeQSTileIntentUserInputHandler.pendingIntentInputs
+ get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.PendingIntent }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
new file mode 100644
index 0000000..e09f280
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.actions
+
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Subject
+import com.google.common.truth.Truth
+
+/** [Truth] [Subject] to assert inputs handled by [FakeQSTileIntentUserInputHandler] */
+class QSTileIntentUserInputHandlerSubject
+private constructor(
+ failureMetadata: FailureMetadata,
+ private val subject: FakeQSTileIntentUserInputHandler
+) : Subject(failureMetadata, subject) {
+
+ fun handledOneIntentInput(
+ intentAssertions: (FakeQSTileIntentUserInputHandler.Input.Intent) -> Unit = {},
+ ) {
+ // check that there are no other inputs
+ check("handledInputs").that(subject.handledInputs).hasSize(1)
+ // check there is an intent input
+ check("intentInputs").that(subject.intentInputs).hasSize(1)
+
+ intentAssertions(subject.intentInputs.first())
+ }
+
+ fun handledOnePendingIntentInput(
+ intentAssertions: (FakeQSTileIntentUserInputHandler.Input.PendingIntent) -> Unit = {},
+ ) {
+ // check that there are no other inputs
+ check("handledInputs").that(subject.handledInputs).hasSize(1)
+ // check there is a pending intent input
+ check("intentInputs").that(subject.pendingIntentInputs).hasSize(1)
+
+ intentAssertions(subject.pendingIntentInputs.first())
+ }
+
+ fun handledNoInputs() {
+ check("handledInputs").that(subject.handledInputs).isEmpty()
+ }
+
+ companion object {
+
+ /**
+ * [Truth.assertThat]-like factory to initialize the assertion. Example:
+ * ```
+ * assertThat(inputHandler).handledOneIntentInput {
+ * assertThat(it.intent.action).isEqualTo("action.Test")
+ * }
+ * ```
+ */
+ fun assertThat(
+ handler: FakeQSTileIntentUserInputHandler
+ ): QSTileIntentUserInputHandlerSubject =
+ Truth.assertAbout {
+ failureMetadata: FailureMetadata,
+ subject: FakeQSTileIntentUserInputHandler ->
+ QSTileIntentUserInputHandlerSubject(failureMetadata, subject)
+ }
+ .that(handler)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt
new file mode 100644
index 0000000..832b07a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.base.interactor
+
+import android.os.UserHandle
+import android.view.View
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+
+object QSTileInputTestKtx {
+
+ fun <T> click(
+ data: T,
+ user: UserHandle = UserHandle.CURRENT,
+ view: View? = null,
+ ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.Click(view), data)
+
+ fun <T> longClick(
+ data: T,
+ user: UserHandle = UserHandle.CURRENT,
+ view: View? = null,
+ ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.LongClick(view), data)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
new file mode 100644
index 0000000..8fc419c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -0,0 +1,20 @@
+package com.android.systemui.scene
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+
+var Kosmos.sceneKeys by Fixture {
+ listOf(
+ SceneKey.QuickSettings,
+ SceneKey.Shade,
+ SceneKey.Lockscreen,
+ SceneKey.Bouncer,
+ SceneKey.Gone,
+ SceneKey.Communal,
+ )
+}
+
+val Kosmos.initialSceneKey by Fixture { SceneKey.Lockscreen }
+val Kosmos.sceneContainerConfig by Fixture { SceneContainerConfig(sceneKeys, initialSceneKey) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 6beb513..f97d6b3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene
+import android.content.Context
import android.content.pm.UserInfo
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
@@ -50,6 +51,9 @@
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.scene.data.repository.SceneContainerRepository
@@ -70,8 +74,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.currentTime
/**
@@ -80,10 +82,13 @@
*/
@OptIn(ExperimentalCoroutinesApi::class)
class SceneTestUtils(
- test: SysuiTestCase,
+ private val context: Context,
) {
- val testDispatcher = StandardTestDispatcher()
- val testScope = TestScope(testDispatcher)
+ constructor(test: SysuiTestCase) : this(context = test.context)
+
+ val kosmos = Kosmos()
+ val testDispatcher = kosmos.testDispatcher
+ val testScope = kosmos.testScope
val featureFlags =
FakeFeatureFlagsClassic().apply {
set(Flags.FACE_AUTH_REFACTOR, false)
@@ -113,8 +118,6 @@
}
}
- private val context = test.context
-
private val falsingCollectorFake: FalsingCollector by lazy { FalsingCollectorFake() }
private var falsingInteractor: FalsingInteractor? = null
@@ -125,23 +128,11 @@
}
fun fakeSceneKeys(): List<SceneKey> {
- return listOf(
- SceneKey.QuickSettings,
- SceneKey.Shade,
- SceneKey.Lockscreen,
- SceneKey.Bouncer,
- SceneKey.Gone,
- SceneKey.Communal,
- )
+ return kosmos.sceneKeys
}
- fun fakeSceneContainerConfig(
- sceneKeys: List<SceneKey> = fakeSceneKeys(),
- ): SceneContainerConfig {
- return SceneContainerConfig(
- sceneKeys = sceneKeys,
- initialSceneKey = SceneKey.Lockscreen,
- )
+ fun fakeSceneContainerConfig(): SceneContainerConfig {
+ return kosmos.sceneContainerConfig
}
@JvmOverloads
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
index 46b4628..9c6dfc6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
@@ -31,7 +31,7 @@
* This class matches multi-finger multi-tap gestures. The number of fingers and the number of taps
* for each instance is specified in the constructor.
*/
-class MultiFingerMultiTap extends GestureMatcher {
+public class MultiFingerMultiTap extends GestureMatcher {
// The target number of taps.
final int mTargetTapCount;
@@ -56,7 +56,7 @@
* @throws IllegalArgumentException if <code>fingers<code/> is less than 2
* or <code>taps<code/> is not positive.
*/
- MultiFingerMultiTap(
+ public MultiFingerMultiTap(
Context context,
int fingers,
int taps,
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java
index 9c54100..f586036f 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTapAndHold.java
@@ -23,9 +23,9 @@
* This class matches gestures of the form multi-finger multi-tap and hold. The number of fingers
* and taps for each instance is specified in the constructor.
*/
-class MultiFingerMultiTapAndHold extends MultiFingerMultiTap {
+public class MultiFingerMultiTapAndHold extends MultiFingerMultiTap {
- MultiFingerMultiTapAndHold(
+ public MultiFingerMultiTapAndHold(
Context context,
int fingers,
int taps,
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 5953d0d..36e75118 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -41,6 +41,8 @@
import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.Flags;
import com.android.server.accessibility.gestures.GestureMatcher;
+import com.android.server.accessibility.gestures.MultiFingerMultiTap;
+import com.android.server.accessibility.gestures.MultiFingerMultiTapAndHold;
import com.android.server.accessibility.gestures.MultiTap;
import com.android.server.accessibility.gestures.MultiTapAndHold;
@@ -476,6 +478,15 @@
null));
mGestureMatchers.add(new TwoFingersDownOrSwipe(context));
+ if (mDetectTwoFingerTripleTap) {
+ mGestureMatchers.add(new MultiFingerMultiTap(context, /* fingers= */ 2,
+ /* taps= */ 3, MagnificationGestureMatcher.GESTURE_TRIPLE_TAP,
+ null));
+ mGestureMatchers.add(new MultiFingerMultiTapAndHold(context, /* fingers= */ 2,
+ /* taps= */ 3, MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD,
+ null));
+ }
+
mGesturesObserver = new MagnificationGesturesObserver(this,
mGestureMatchers.toArray(new GestureMatcher[mGestureMatchers.size()]));
} else {
@@ -512,7 +523,9 @@
@Override
public boolean shouldStopDetection(MotionEvent motionEvent) {
return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)
- && !mDetectSingleFingerTripleTap;
+ && !mDetectSingleFingerTripleTap
+ && !(mDetectTwoFingerTripleTap
+ && Flags.enableMagnificationMultipleFingerMultipleTapGesture());
}
@Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index b2ff3c3..d4ff699 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -33,7 +33,6 @@
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
-import static android.view.contentprotection.flags.Flags.parseGroupsConfigEnabled;
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ACCEPT_DATA_SHARE_REQUEST;
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL;
@@ -1037,9 +1036,6 @@
if (verbose) {
Slog.v(TAG, "parseContentProtectionGroupsConfig: " + config);
}
- if (!parseGroupsConfigEnabled()) {
- return Collections.emptyList();
- }
if (config == null) {
return Collections.emptyList();
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
index bfb3a38..3aec5e9 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
@@ -16,8 +16,6 @@
package com.android.server.contentprotection;
-import static android.view.contentprotection.flags.Flags.blocklistUpdateEnabled;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
@@ -130,10 +128,6 @@
}
private void handlePackagesChanged() {
- if (!blocklistUpdateEnabled()) {
- return;
- }
-
/**
* PackageMonitor callback can be invoked more than once in a matter of milliseconds on the
* same monitor instance for the same package (eg: b/295969873). This check acts both as a
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 26421b7..9f279b1 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -62,6 +62,7 @@
import java.nio.file.attribute.PosixFilePermissions;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -333,9 +334,11 @@
* @param tombstone path to the tombstone
* @param proto whether the tombstone is stored as proto
* @param processName the name of the process corresponding to the tombstone
+ * @param tmpFileLock the lock for reading/writing tmp files
*/
public static void addTombstoneToDropBox(
- Context ctx, File tombstone, boolean proto, String processName) {
+ Context ctx, File tombstone, boolean proto, String processName,
+ ReentrantLock tmpFileLock) {
final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
if (db == null) {
Slog.e(TAG, "Can't log tombstone: DropBoxManager not available");
@@ -356,39 +359,11 @@
// due to rate limiting. Do this by enclosing the proto tombsstone in a
// container proto that has the dropped entry count and the proto tombstone as
// bytes (to avoid the complexity of reading and writing nested protos).
-
- // Read the proto tombstone file as bytes.
- final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());
-
- final File tombstoneProtoWithHeaders = File.createTempFile(
- tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
- Files.setPosixFilePermissions(
- tombstoneProtoWithHeaders.toPath(),
- PosixFilePermissions.fromString("rw-rw----"));
-
- // Write the new proto container proto with headers.
- try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- tombstoneProtoWithHeaders, MODE_READ_WRITE)) {
- ProtoOutputStream protoStream = new ProtoOutputStream(
- pfd.getFileDescriptor());
- protoStream.write(TombstoneWithHeadersProto.TOMBSTONE, tombstoneBytes);
- protoStream.write(
- TombstoneWithHeadersProto.DROPPED_COUNT,
- rateLimitResult.droppedCountSinceRateLimitActivated());
- protoStream.flush();
-
- // Add the proto to dropbox.
- db.addFile(TAG_TOMBSTONE_PROTO_WITH_HEADERS, tombstoneProtoWithHeaders, 0);
- } catch (FileNotFoundException ex) {
- Slog.e(TAG, "failed to open for write: " + tombstoneProtoWithHeaders, ex);
- throw ex;
- } catch (IOException ex) {
- Slog.e(TAG, "IO exception during write: " + tombstoneProtoWithHeaders, ex);
+ tmpFileLock.lock();
+ try {
+ addAugmentedProtoToDropbox(tombstone, db, rateLimitResult);
} finally {
- // Remove the temporary file.
- if (tombstoneProtoWithHeaders != null) {
- tombstoneProtoWithHeaders.delete();
- }
+ tmpFileLock.unlock();
}
}
} else {
@@ -404,6 +379,44 @@
writeTimestamps(timestamps);
}
+ private static void addAugmentedProtoToDropbox(
+ File tombstone, DropBoxManager db,
+ DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException {
+ // Read the proto tombstone file as bytes.
+ final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());
+
+ final File tombstoneProtoWithHeaders = File.createTempFile(
+ tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
+ Files.setPosixFilePermissions(
+ tombstoneProtoWithHeaders.toPath(),
+ PosixFilePermissions.fromString("rw-rw----"));
+
+ // Write the new proto container proto with headers.
+ try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ tombstoneProtoWithHeaders, MODE_READ_WRITE)) {
+ ProtoOutputStream protoStream =
+ new ProtoOutputStream(pfd.getFileDescriptor());
+ protoStream.write(TombstoneWithHeadersProto.TOMBSTONE, tombstoneBytes);
+ protoStream.write(
+ TombstoneWithHeadersProto.DROPPED_COUNT,
+ rateLimitResult.droppedCountSinceRateLimitActivated());
+ protoStream.flush();
+
+ // Add the proto to dropbox.
+ db.addFile(TAG_TOMBSTONE_PROTO_WITH_HEADERS, tombstoneProtoWithHeaders, 0);
+ } catch (FileNotFoundException ex) {
+ Slog.e(TAG, "failed to open for write: " + tombstoneProtoWithHeaders, ex);
+ throw ex;
+ } catch (IOException ex) {
+ Slog.e(TAG, "IO exception during write: " + tombstoneProtoWithHeaders, ex);
+ } finally {
+ // Remove the temporary file and unlock the lock.
+ if (tombstoneProtoWithHeaders != null) {
+ tombstoneProtoWithHeaders.delete();
+ }
+ }
+ }
+
private static void addLastkToDropBox(
DropBoxManager db, HashMap<String, Long> timestamps,
String headers, String footers, String filename, int maxSize,
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index c4cb816..256f2b3 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -180,14 +180,7 @@
# Snapshot rebuild instance
3131 pm_snapshot_rebuild (build_time|1|3),(lifetime|1|3)
# Caller information to clear application data
-1003160 pm_clear_app_data_caller (pid|1),(uid|1),(package|3)
-# ---------------------------
-# Installer.java
-# ---------------------------
-# Caller Information to clear application data
-1003200 installer_clear_app_data_caller (pid|1),(uid|1),(package|3),(flags|1)
-# Call stack to clear application data
-1003201 installer_clear_app_data_call_stack (method|3),(class|3),(file|3),(line|1)
+3132 pm_clear_app_data_caller (pid|1),(uid|1),(package|3)
# ---------------------------
# InputMethodManagerService.java
@@ -227,6 +220,14 @@
35000 auto_brightness_adj (old_lux|5),(old_brightness|5),(new_lux|5),(new_brightness|5)
# ---------------------------
+# Installer.java
+# ---------------------------
+# Caller Information to clear application data
+39000 installer_clear_app_data_caller (pid|1),(uid|1),(package|3),(flags|1)
+# Call stack to clear application data
+39001 installer_clear_app_data_call_stack (method|3),(class|3),(file|3),(line|1)
+
+# ---------------------------
# ConnectivityService.java
# ---------------------------
# Connectivity state changed
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index dc0f901..66a10e4 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -80,6 +80,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Secure;
+import android.service.dreams.DreamManagerInternal;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -142,10 +143,10 @@
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
private boolean mPowerSave = false;
- // Do not change configuration now. wait until screen turns off.
+ // Do not change configuration now. wait until the device is inactive (eg screen off, dreaming)
// This prevents jank and activity restart when the user
// is actively using the device
- private boolean mWaitForScreenOff = false;
+ private boolean mWaitForDeviceInactive = false;
private int mDefaultUiModeType;
private boolean mCarModeKeepsScreenOn;
private boolean mDeskModeKeepsScreenOn;
@@ -199,6 +200,7 @@
private final LocalService mLocalService = new LocalService();
private PowerManagerInternal mLocalPowerManager;
+ private DreamManagerInternal mDreamManagerInternal;
private final IUiModeManager.Stub mService;
@@ -295,7 +297,7 @@
if (shouldApplyAutomaticChangesImmediately()) {
updateLocked(0, 0);
} else {
- registerScreenOffEventLocked();
+ registerDeviceInactiveListenerLocked();
}
}
}
@@ -306,12 +308,12 @@
* DO NOT USE DIRECTLY
* see register registerScreenOffEvent and unregisterScreenOffEvent
*/
- private final BroadcastReceiver mOnScreenOffHandler = new BroadcastReceiver() {
+ private final BroadcastReceiver mDeviceInactiveListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
// must unregister first before updating
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
updateLocked(0, 0);
}
}
@@ -432,6 +434,7 @@
if (twilightManager != null) mTwilightManager = twilightManager;
mLocalPowerManager =
LocalServices.getService(PowerManagerInternal.class);
+ mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
initPowerSave();
mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
registerVrStateListener();
@@ -582,7 +585,7 @@
if (shouldApplyAutomaticChangesImmediately()) {
updateLocked(0, 0);
} else {
- registerScreenOffEventLocked();
+ registerDeviceInactiveListenerLocked();
}
scheduleNextCustomTimeListener();
}
@@ -631,22 +634,23 @@
return LocalTime.ofNanoOfDay(t * 1000);
}
- private void registerScreenOffEventLocked() {
+ private void registerDeviceInactiveListenerLocked() {
if (mPowerSave) return;
- mWaitForScreenOff = true;
+ mWaitForDeviceInactive = true;
final IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_SCREEN_OFF);
- getContext().registerReceiver(mOnScreenOffHandler, intentFilter);
+ intentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
+ getContext().registerReceiver(mDeviceInactiveListener, intentFilter);
}
private void cancelCustomAlarm() {
mAlarmManager.cancel(mCustomTimeListener);
}
- private void unregisterScreenOffEventLocked() {
- mWaitForScreenOff = false;
+ private void unregisterDeviceInactiveListenerLocked() {
+ mWaitForDeviceInactive = false;
try {
- getContext().unregisterReceiver(mOnScreenOffHandler);
+ getContext().unregisterReceiver(mDeviceInactiveListener);
} catch (IllegalArgumentException e) {
// we ignore this exception if the receiver is unregistered already.
}
@@ -828,7 +832,7 @@
synchronized (mLock) {
if (mNightMode != mode || mNightModeCustomType != customModeType) {
if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
cancelCustomAlarm();
}
mNightModeCustomType = mode == MODE_NIGHT_CUSTOM
@@ -840,10 +844,10 @@
// on screen off will update configuration instead
if ((mNightMode != MODE_NIGHT_AUTO && mNightMode != MODE_NIGHT_CUSTOM)
|| shouldApplyAutomaticChangesImmediately()) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
updateLocked(0, 0);
} else {
- registerScreenOffEventLocked();
+ registerDeviceInactiveListenerLocked();
}
}
}
@@ -967,7 +971,7 @@
final long ident = Binder.clearCallingIdentity();
try {
if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
mOverrideNightModeOff = !active;
mOverrideNightModeOn = active;
mOverrideNightModeUser = mCurrentUser;
@@ -1011,7 +1015,7 @@
persistNightMode(user);
onCustomTimeUpdated(user);
} catch (DateTimeException e) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1038,7 +1042,7 @@
mCustomAutoNightModeEndMilliseconds = newTime;
onCustomTimeUpdated(user);
} catch (DateTimeException e) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1383,10 +1387,10 @@
persistNightMode(user);
if (mNightMode != MODE_NIGHT_CUSTOM) return;
if (shouldApplyAutomaticChangesImmediately()) {
- unregisterScreenOffEventLocked();
+ unregisterDeviceInactiveListenerLocked();
updateLocked(0, 0);
} else {
- registerScreenOffEventLocked();
+ registerDeviceInactiveListenerLocked();
}
}
@@ -1414,7 +1418,7 @@
pw.print(" ");
}
pw.println("");
- pw.print(" waitScreenOff="); pw.print(mWaitForScreenOff);
+ pw.print(" mWaitForDeviceInactive="); pw.print(mWaitForDeviceInactive);
pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
pw.print(" customStart="); pw.print(mCustomAutoNightModeStartMilliseconds);
pw.print(" customEnd"); pw.print(mCustomAutoNightModeEndMilliseconds);
@@ -1675,7 +1679,7 @@
}
mCurUiMode = uiMode;
- if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) {
+ if (!mHoldingConfiguration && (!mWaitForDeviceInactive || mPowerSave)) {
mConfiguration.uiMode = uiMode;
}
}
@@ -1712,7 +1716,8 @@
private boolean shouldApplyAutomaticChangesImmediately() {
return mCar || !mPowerManager.isInteractive()
- || mNightModeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
+ || mNightModeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME
+ || mDreamManagerInternal.isDreaming();
}
private void scheduleNextCustomTimeListener() {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 8a801d8..85abf87 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -191,7 +191,7 @@
final MessageHandler mHandler;
- private static final int TIMEOUT_DELAY_MS = 1000 * 60;
+ private static final int TIMEOUT_DELAY_MS = 1000 * 60 * 15;
// Messages that can be sent on mHandler
private static final int MESSAGE_TIMED_OUT = 3;
private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1566113..514be15 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -79,6 +79,7 @@
import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerExemptionManager.REASON_DENIED;
import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.REASON_PROC_STATE_BTOP;
@@ -7715,14 +7716,100 @@
"getUidProcessState", callingPackage); // Ignore return value
synchronized (mProcLock) {
- if (mPendingStartActivityUids.isPendingTopUid(uid)) {
- return PROCESS_STATE_TOP;
- }
- return mProcessList.getUidProcStateLOSP(uid);
+ return getUidProcessStateInnerLOSP(uid);
}
}
@Override
+ public int getBindingUidProcessState(int targetUid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.GET_BINDING_UID_IMPORTANCE,
+ "getBindingUidProcessState");
+ }
+ // We don't need to do a cross-user check here (unlike getUidProcessState),
+ // because we only allow to see UIDs that are actively communicating with the caller.
+
+ final int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final boolean allowed = (callingUid == targetUid)
+ || hasServiceBindingOrProviderUseLocked(callingUid, targetUid);
+ if (!allowed) {
+ return PROCESS_STATE_NONEXISTENT;
+ }
+ return getUidProcessStateInnerLOSP(targetUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @GuardedBy(anyOf = {"this", "mProcLock"})
+ private int getUidProcessStateInnerLOSP(int uid) {
+ if (mPendingStartActivityUids.isPendingTopUid(uid)) {
+ return PROCESS_STATE_TOP;
+ }
+ return mProcessList.getUidProcStateLOSP(uid);
+ }
+
+ /**
+ * Ensure that {@code clientUid} has a bound service client to {@code callingUid}
+ */
+ @GuardedBy("this")
+ private boolean hasServiceBindingOrProviderUseLocked(int callingUid, int clientUid) {
+ // See if there's a service binding
+ final Boolean hasBinding = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessServiceRecord psr = pr.mServices;
+ final int serviceCount = psr.mServices.size();
+ for (int svc = 0; svc < serviceCount; svc++) {
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ psr.mServices.valueAt(svc).getConnections();
+ final int size = conns.size();
+ for (int conni = 0; conni < size; conni++) {
+ final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+ for (int con = 0; con < crs.size(); con++) {
+ final ConnectionRecord cr = crs.get(con);
+ final ProcessRecord clientPr = cr.binding.client;
+
+ if (clientPr.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ });
+ if (Boolean.TRUE.equals(hasBinding)) {
+ return true;
+ }
+
+ final Boolean hasProviderClient = mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessProviderRecord ppr = pr.mProviders;
+ for (int provi = ppr.numberOfProviders() - 1; provi >= 0; provi--) {
+ ContentProviderRecord cpr = ppr.getProviderAt(provi);
+
+ for (int i = cpr.connections.size() - 1; i >= 0; i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ if (client.uid == clientUid) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ }
+ return null;
+ });
+
+ return Boolean.TRUE.equals(hasProviderClient);
+ }
+
+ @Override
public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index e07c2bc..e41b6ae 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -350,6 +350,13 @@
final BroadcastRecord testRecord = (BroadcastRecord) args.arg1;
final int testRecordIndex = args.argi1;
final Object testReceiver = testRecord.receivers.get(testRecordIndex);
+ // If we come across the record that's being enqueued in the queue, then that means
+ // we already enqueued it for a receiver in this process and trying to insert a new
+ // one past this could create priority inversion in the queue, so bail out.
+ if (record == testRecord && record.blockedUntilBeyondCount[recordIndex]
+ > testRecord.blockedUntilBeyondCount[testRecordIndex]) {
+ break;
+ }
if ((record.callingUid == testRecord.callingUid)
&& (record.userId == testRecord.userId)
&& record.intent.filterEquals(testRecord.intent)
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 68af626..a0a7b2b 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -2583,7 +2583,7 @@
// Do nothing if the binder error callback is not enabled.
// That means the frozen apps in a wrong state will be killed when they are unfrozen later.
- if (!mFreezerBinderCallbackEnabled) {
+ if (!mUseFreezer || !mFreezerBinderCallbackEnabled) {
return;
}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 931914f..2aed847 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -131,4 +131,4 @@
30110 am_intent_sender_redirect_user (userId|1|5)
# Caller information to clear application data
-1030002 am_clear_app_data_caller (pid|1),(uid|1),(package|3)
+30120 am_clear_app_data_caller (pid|1),(uid|1),(package|3)
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 70a1c91..0fba739 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -246,7 +246,9 @@
int getFgsAllowStart() {
return mAllowStartForegroundNoBinding != REASON_DENIED
? mAllowStartForegroundNoBinding
- : mAllowStartInBindService;
+ : (mAllowStartByBindings != REASON_DENIED
+ ? mAllowStartByBindings
+ : mAllowStartInBindService);
}
boolean isFgsAllowedStart() {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2897075..5d4f711 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -70,7 +70,6 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
-import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -172,7 +171,7 @@
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
- mBtHelper = new BtHelper(this);
+ mBtHelper = new BtHelper(this, context);
mDeviceInventory = new AudioDeviceInventory(this);
mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext);
mAudioSystem = audioSystem;
@@ -188,7 +187,7 @@
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
- mBtHelper = new BtHelper(this);
+ mBtHelper = new BtHelper(this, context);
mDeviceInventory = mockDeviceInventory;
mSystemServer = mockSystemServer;
mAudioSystem = audioSystem;
@@ -1392,6 +1391,10 @@
return mAudioService.hasAudioFocusUsers();
}
+ /*package*/ void postInitSpatializerHeadTrackingSensors() {
+ mAudioService.postInitSpatializerHeadTrackingSensors();
+ }
+
//---------------------------------------------------------------------
// Message handling on behalf of helper classes.
// Each of these methods posts a message to mBrokerHandler message queue.
@@ -1475,6 +1478,15 @@
sendLMsgNoDelay(MSG_L_RECEIVED_BT_EVENT, SENDMSG_QUEUE, intent);
}
+ /*package*/ void postUpdateLeAudioGroupAddresses(int groupId) {
+ sendIMsgNoDelay(
+ MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES, SENDMSG_QUEUE, groupId);
+ }
+
+ /*package*/ void postSynchronizeLeDevicesInInventory(AdiDeviceState deviceState) {
+ sendLMsgNoDelay(MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY, SENDMSG_QUEUE, deviceState);
+ }
+
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mUid; // Requester UID
@@ -1604,6 +1616,14 @@
}
}
+ /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
+ return mBtHelper.getLeAudioDeviceGroupId(device);
+ }
+
+ /*package*/ List<String> getLeAudioGroupAddresses(int groupId) {
+ return mBtHelper.getLeAudioGroupAddresses(groupId);
+ }
+
/*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
}
@@ -1976,6 +1996,22 @@
onCheckCommunicationRouteClientState(msg.arg1, msg.arg2 == 1);
}
} break;
+
+ case MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onUpdateLeAudioGroupAddresses(msg.arg1);
+ }
+ } break;
+
+ case MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.onSynchronizeLeDevicesInInventory(
+ (AdiDeviceState) msg.obj);
+ }
+ } break;
+
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -2058,6 +2094,10 @@
private static final int MSG_L_RECEIVED_BT_EVENT = 55;
private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56;
+ private static final int MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES = 57;
+ private static final int MSG_L_SYNCHRONIZE_LE_DEVICES_IN_INVENTORY = 58;
+
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -2582,9 +2622,9 @@
}
}
- @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.getDeviceSensorUuid(device);
+ return mDeviceInventory.getDeviceAddresses(device);
}
}
@@ -2605,15 +2645,19 @@
* in order to be mocked by a test a the same package
* (see https://code.google.com/archive/p/mockito/issues/127)
*/
- public void persistAudioDeviceSettings() {
+ public void postPersistAudioDeviceSettings() {
sendMsg(MSG_PERSIST_AUDIO_DEVICE_SETTINGS, SENDMSG_REPLACE, /*delay*/ 1000);
}
void onPersistAudioDeviceSettings() {
final String deviceSettings = mDeviceInventory.getDeviceSettings();
- Log.v(TAG, "saving AdiDeviceState: " + deviceSettings);
- final SettingsAdapter settings = mAudioService.getSettings();
- boolean res = settings.putSecureStringForUser(mAudioService.getContentResolver(),
+ Log.v(TAG, "onPersistAudioDeviceSettings AdiDeviceState: " + deviceSettings);
+ String currentSettings = readDeviceSettings();
+ if (deviceSettings.equals(currentSettings)) {
+ return;
+ }
+ final SettingsAdapter settingsAdapter = mAudioService.getSettings();
+ boolean res = settingsAdapter.putSecureStringForUser(mAudioService.getContentResolver(),
Settings.Secure.AUDIO_DEVICE_INVENTORY,
deviceSettings, UserHandle.USER_CURRENT);
if (!res) {
@@ -2621,11 +2665,17 @@
}
}
+ private String readDeviceSettings() {
+ final SettingsAdapter settingsAdapter = mAudioService.getSettings();
+ final ContentResolver contentResolver = mAudioService.getContentResolver();
+ return settingsAdapter.getSecureStringForUser(contentResolver,
+ Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT);
+ }
+
void onReadAudioDeviceSettings() {
final SettingsAdapter settingsAdapter = mAudioService.getSettings();
final ContentResolver contentResolver = mAudioService.getContentResolver();
- String settings = settingsAdapter.getSecureStringForUser(contentResolver,
- Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT);
+ String settings = readDeviceSettings();
if (settings == null) {
Log.i(TAG, "reading AdiDeviceState from legacy key"
+ Settings.Secure.SPATIAL_AUDIO_ENABLED);
@@ -2688,8 +2738,8 @@
}
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
- return mDeviceInventory.findBtDeviceStateForAddress(address, isBle);
+ AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ return mDeviceInventory.findBtDeviceStateForAddress(address, deviceType);
}
//------------------------------------------------
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index e59fd77..7ba0827 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -15,14 +15,23 @@
*/
package com.android.server.audio;
+import static android.media.AudioSystem.DEVICE_IN_ALL_SCO_SET;
import static android.media.AudioSystem.DEVICE_OUT_ALL_A2DP_SET;
import static android.media.AudioSystem.DEVICE_OUT_ALL_BLE_SET;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO_SET;
+import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
+import static android.media.AudioSystem.isBluetoothA2dpOutDevice;
import static android.media.AudioSystem.isBluetoothDevice;
+import static android.media.AudioSystem.isBluetoothLeOutDevice;
+import static android.media.AudioSystem.isBluetoothOutDevice;
+import static android.media.AudioSystem.isBluetoothScoOutDevice;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -72,7 +81,6 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.UUID;
import java.util.stream.Stream;
/**
@@ -118,6 +126,7 @@
return oldState;
});
}
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(deviceState);
}
/**
@@ -125,23 +134,28 @@
* Bluetooth device and no corresponding entry already exists.
* @param ada the device to add if needed
*/
- void addAudioDeviceInInventoryIfNeeded(AudioDeviceAttributes ada) {
- if (!AudioSystem.isBluetoothOutDevice(ada.getInternalType())) {
+ void addAudioDeviceInInventoryIfNeeded(int deviceType, String address, String peerAddres) {
+ if (!isBluetoothOutDevice(deviceType)) {
return;
}
synchronized (mDeviceInventoryLock) {
- if (findDeviceStateForAudioDeviceAttributes(ada, ada.getType()) != null) {
+ AdiDeviceState ads = findBtDeviceStateForAddress(address, deviceType);
+ if (ads == null) {
+ ads = findBtDeviceStateForAddress(peerAddres, deviceType);
+ }
+ if (ads != null) {
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(ads);
return;
}
- AdiDeviceState ads = new AdiDeviceState(
- ada.getType(), ada.getInternalType(), ada.getAddress());
+ ads = new AdiDeviceState(AudioDeviceInfo.convertInternalDeviceToDeviceType(deviceType),
+ deviceType, address);
mDeviceInventory.put(ads.getDeviceId(), ads);
+ mDeviceBroker.postPersistAudioDeviceSettings();
}
- mDeviceBroker.persistAudioDeviceSettings();
}
/**
- * Adds a new AdiDeviceState or updates the audio device cateogory of the matching
+ * Adds a new AdiDeviceState or updates the audio device category of the matching
* AdiDeviceState in the {@link AudioDeviceInventory#mDeviceInventory} list.
* @param deviceState the device to update
*/
@@ -152,6 +166,63 @@
return oldState;
});
}
+ mDeviceBroker.postSynchronizeLeDevicesInInventory(deviceState);
+ }
+
+ /**
+ * synchronize AdiDeviceState for LE devices in the same group
+ */
+ void onSynchronizeLeDevicesInInventory(AdiDeviceState updatedDevice) {
+ synchronized (mDevicesLock) {
+ synchronized (mDeviceInventoryLock) {
+ boolean found = false;
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mDeviceType != updatedDevice.getInternalDeviceType()) {
+ continue;
+ }
+ if (di.mDeviceAddress.equals(updatedDevice.getDeviceAddress())) {
+ for (AdiDeviceState ads2 : mDeviceInventory.values()) {
+ if (!(di.mDeviceType == ads2.getInternalDeviceType()
+ && di.mPeerDeviceAddress.equals(ads2.getDeviceAddress()))) {
+ continue;
+ }
+ ads2.setHasHeadTracker(updatedDevice.hasHeadTracker());
+ ads2.setHeadTrackerEnabled(updatedDevice.isHeadTrackerEnabled());
+ ads2.setSAEnabled(updatedDevice.isSAEnabled());
+ ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory());
+ found = true;
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "onSynchronizeLeDevicesInInventory synced device pair ads1="
+ + updatedDevice + " ads2=" + ads2).printLog(TAG));
+ break;
+ }
+ }
+ if (di.mPeerDeviceAddress.equals(updatedDevice.getDeviceAddress())) {
+ for (AdiDeviceState ads2 : mDeviceInventory.values()) {
+ if (!(di.mDeviceType == ads2.getInternalDeviceType()
+ && di.mDeviceAddress.equals(ads2.getDeviceAddress()))) {
+ continue;
+ }
+ ads2.setHasHeadTracker(updatedDevice.hasHeadTracker());
+ ads2.setHeadTrackerEnabled(updatedDevice.isHeadTrackerEnabled());
+ ads2.setSAEnabled(updatedDevice.isSAEnabled());
+ ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory());
+ found = true;
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "onSynchronizeLeDevicesInInventory synced device pair ads1="
+ + updatedDevice + " peer ads2=" + ads2).printLog(TAG));
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ mDeviceBroker.postPersistAudioDeviceSettings();
+ }
+ }
+ }
}
/**
@@ -163,9 +234,21 @@
* @return the found {@link AdiDeviceState} or {@code null} otherwise.
*/
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
+ AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ Set<Integer> deviceSet;
+ if (isBluetoothA2dpOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_A2DP_SET;
+ } else if (isBluetoothLeOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_BLE_SET;
+ } else if (isBluetoothScoOutDevice(deviceType)) {
+ deviceSet = DEVICE_OUT_ALL_SCO_SET;
+ } else if (deviceType == DEVICE_OUT_HEARING_AID) {
+ deviceSet = new HashSet<>();
+ deviceSet.add(DEVICE_OUT_HEARING_AID);
+ } else {
+ return null;
+ }
synchronized (mDeviceInventoryLock) {
- final Set<Integer> deviceSet = isBle ? DEVICE_OUT_ALL_BLE_SET : DEVICE_OUT_ALL_A2DP_SET;
for (Integer internalType : deviceSet) {
AdiDeviceState deviceState = mDeviceInventory.get(
new Pair<>(internalType, address));
@@ -345,7 +428,8 @@
final @NonNull String mDeviceName;
final @NonNull String mDeviceAddress;
int mDeviceCodecFormat;
- final UUID mSensorUuid;
+ @NonNull String mPeerDeviceAddress;
+ final int mGroupId;
/** Disabled operating modes for this device. Use a negative logic so that by default
* an empty list means all modes are allowed.
@@ -353,12 +437,13 @@
@NonNull ArraySet<String> mDisabledModes = new ArraySet(0);
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
- int deviceCodecFormat, @Nullable UUID sensorUuid) {
+ int deviceCodecFormat, String peerDeviceAddress, int groupId) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
mDeviceCodecFormat = deviceCodecFormat;
- mSensorUuid = sensorUuid;
+ mPeerDeviceAddress = peerDeviceAddress == null ? "" : peerDeviceAddress;
+ mGroupId = groupId;
}
void setModeDisabled(String mode) {
@@ -379,7 +464,8 @@
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
- this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
+ this(deviceType, deviceName, deviceAddress, deviceCodecFormat,
+ null, BluetoothLeAudio.GROUP_ID_INVALID);
}
DeviceInfo(int deviceType, String deviceName, String deviceAddress) {
@@ -393,7 +479,8 @@
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
- + " sensorUuid: " + Objects.toString(mSensorUuid)
+ + " peer addr:" + mPeerDeviceAddress
+ + " group:" + mGroupId
+ " disabled modes: " + mDisabledModes + "]";
}
@@ -714,6 +801,27 @@
}
}
+
+ /*package*/ void onUpdateLeAudioGroupAddresses(int groupId) {
+ synchronized (mDevicesLock) {
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mGroupId == groupId) {
+ List<String> addresses = mDeviceBroker.getLeAudioGroupAddresses(groupId);
+ if (di.mPeerDeviceAddress.equals("")) {
+ for (String addr : addresses) {
+ if (!addr.equals(di.mDeviceAddress)) {
+ di.mPeerDeviceAddress = addr;
+ break;
+ }
+ }
+ } else if (!addresses.contains(di.mPeerDeviceAddress)) {
+ di.mPeerDeviceAddress = "";
+ }
+ }
+ }
+ }
+ }
+
/*package*/ void onReportNewRoutes() {
int n = mRoutesObservers.beginBroadcast();
if (n > 0) {
@@ -1419,7 +1527,7 @@
if (!connect) {
purgeDevicesRoles_l();
} else {
- addAudioDeviceInInventoryIfNeeded(attributes);
+ addAudioDeviceInInventoryIfNeeded(device, address, "");
}
}
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -1477,7 +1585,7 @@
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_HEARING_AID devices
mConnectedDevices.values().forEach(deviceInfo -> {
- if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ if (deviceInfo.mDeviceType == DEVICE_OUT_HEARING_AID) {
toRemove.add(deviceInfo.mDeviceAddress);
}
});
@@ -1485,8 +1593,8 @@
.set(MediaMetrics.Property.EVENT, "disconnectHearingAid")
.record();
if (toRemove.size() > 0) {
- final int delay = checkSendBecomingNoisyIntentInt(
- AudioSystem.DEVICE_OUT_HEARING_AID, 0, AudioSystem.DEVICE_NONE);
+ final int delay = checkSendBecomingNoisyIntentInt(DEVICE_OUT_HEARING_AID,
+ AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE);
toRemove.stream().forEach(deviceAddress ->
// TODO delay not used?
makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/)
@@ -1687,12 +1795,8 @@
// Reset A2DP suspend state each time a new sink is connected
mDeviceBroker.clearA2dpSuspended(true /* internalOnly */);
- // The convention for head tracking sensors associated with A2DP devices is to
- // use a UUID derived from the MAC address as follows:
- // time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
- address, codec, sensorUuid);
+ address, codec);
final String diKey = di.getKey();
mConnectedDevices.put(diKey, di);
// on a connection always overwrite the device seen by AudioPolicy, see comment above when
@@ -1703,7 +1807,7 @@
setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, "");
}
static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
@@ -1723,15 +1827,15 @@
return;
}
DeviceInfo leOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_BLE_SET);
DeviceInfo leInDevice =
getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET);
DeviceInfo a2dpDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_A2DP_SET);
DeviceInfo scoOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_SCO_SET);
DeviceInfo scoInDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET);
+ getFirstConnectedDeviceOfTypes(DEVICE_IN_ALL_SCO_SET);
boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled());
boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled())
|| (leInDevice != null && leInDevice.isDuplexModeEnabled());
@@ -1765,7 +1869,7 @@
continue;
}
- if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) {
+ if (isBluetoothOutDevice(di.mDeviceType)) {
for (AudioProductStrategy strategy : mStrategies) {
boolean disable = false;
if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) {
@@ -1832,23 +1936,20 @@
int checkProfileIsConnected(int profile) {
switch (profile) {
case BluetoothProfile.HEADSET:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null
- || getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) {
+ if (getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_SCO_SET) != null
+ || getFirstConnectedDeviceOfTypes(DEVICE_IN_ALL_SCO_SET) != null) {
return profile;
}
break;
case BluetoothProfile.A2DP:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) {
+ if (getFirstConnectedDeviceOfTypes(DEVICE_OUT_ALL_A2DP_SET) != null) {
return profile;
}
break;
case BluetoothProfile.LE_AUDIO:
case BluetoothProfile.LE_AUDIO_BROADCAST:
if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null
+ DEVICE_OUT_ALL_BLE_SET) != null
|| getFirstConnectedDeviceOfTypes(
AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) {
return profile;
@@ -2006,28 +2107,28 @@
private void makeHearingAidDeviceAvailable(
String address, String name, int streamType, String eventSource) {
final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
- AudioSystem.DEVICE_OUT_HEARING_AID);
+ DEVICE_OUT_HEARING_AID);
mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
AudioDeviceAttributes ada = new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
+ DEVICE_OUT_HEARING_AID, address, name);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
- DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
- new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address));
- mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
+ DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address),
+ new DeviceInfo(DEVICE_OUT_HEARING_AID, name, address));
+ mDeviceBroker.postAccessoryPlugMediaUnmute(DEVICE_OUT_HEARING_AID);
mDeviceBroker.postApplyVolumeOnDevice(streamType,
- AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
+ DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
setCurrentAudioRouteNameIfPossible(name, false /*fromA2dp*/);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(DEVICE_OUT_HEARING_AID, address, "");
new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceAvailable")
.set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
.set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
+ AudioSystem.getDeviceName(DEVICE_OUT_HEARING_AID))
.set(MediaMetrics.Property.NAME, name)
.set(MediaMetrics.Property.STREAM_TYPE,
AudioSystem.streamToString(streamType))
@@ -2037,18 +2138,18 @@
@GuardedBy("mDevicesLock")
private void makeHearingAidDeviceUnavailable(String address) {
AudioDeviceAttributes ada = new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_HEARING_AID, address);
+ DEVICE_OUT_HEARING_AID, address);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
- DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
+ DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address));
// Remove Hearing Aid routes as well
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceUnavailable")
.set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
.set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
+ AudioSystem.getDeviceName(DEVICE_OUT_HEARING_AID))
.record();
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
}
@@ -2060,7 +2161,7 @@
*/
boolean isHearingAidConnected() {
return getFirstConnectedDeviceOfTypes(
- Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null;
+ Sets.newHashSet(DEVICE_OUT_HEARING_AID)) != null;
}
/**
@@ -2102,6 +2203,20 @@
final String address = btInfo.mDevice.getAddress();
String name = BtHelper.getName(btInfo.mDevice);
+ // Find LE Group ID and peer headset address if available
+ final int groupId = mDeviceBroker.getLeAudioDeviceGroupId(btInfo.mDevice);
+ String peerAddress = "";
+ if (groupId != BluetoothLeAudio.GROUP_ID_INVALID) {
+ List<String> addresses = mDeviceBroker.getLeAudioGroupAddresses(groupId);
+ if (addresses.size() > 1) {
+ for (String addr : addresses) {
+ if (!addr.equals(address)) {
+ peerAddress = addr;
+ break;
+ }
+ }
+ }
+ }
// The BT Stack does not provide a name for LE Broadcast devices
if (device == AudioSystem.DEVICE_OUT_BLE_BROADCAST && name.equals("")) {
name = "Broadcast";
@@ -2127,14 +2242,12 @@
}
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended(true /* internalOnly */);
-
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
- sensorUuid));
+ peerAddress, groupId));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
- addAudioDeviceInInventoryIfNeeded(ada);
+ addAudioDeviceInInventoryIfNeeded(device, address, peerAddress);
}
if (streamType == AudioSystem.STREAM_DEFAULT) {
@@ -2226,12 +2339,12 @@
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
- BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(DEVICE_OUT_HEARING_AID);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
- BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(DEVICE_OUT_ALL_A2DP_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
- BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(DEVICE_OUT_ALL_BLE_SET);
}
// must be called before removing the device from mConnectedDevices
@@ -2512,16 +2625,22 @@
mDevRoleCapturePresetDispatchers.finishBroadcast();
}
- @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
+ List<String> addresses = new ArrayList<String>();
final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(),
device.getAddress());
synchronized (mDevicesLock) {
DeviceInfo di = mConnectedDevices.get(key);
- if (di == null) {
- return null;
+ if (di != null) {
+ if (!di.mDeviceAddress.isEmpty()) {
+ addresses.add(di.mDeviceAddress);
+ }
+ if (!di.mPeerDeviceAddress.isEmpty()) {
+ addresses.add(di.mPeerDeviceAddress);
+ }
}
- return di.mSensorUuid;
}
+ return addresses;
}
/*package*/ String getDeviceSettings() {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b209fb0..99321c4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -38,6 +38,7 @@
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
import static com.android.media.audio.Flags.bluetoothMacAddressAnonymization;
+import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
import static com.android.server.audio.SoundDoseHelper.ACTION_CHECK_MUSIC_ACTIVE;
import static com.android.server.utils.EventLogger.Event.ALOGE;
import static com.android.server.utils.EventLogger.Event.ALOGI;
@@ -236,7 +237,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
-import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -1371,19 +1371,21 @@
sRingerAndZenModeMutedStreams, "onInitStreamsAndVolumes"));
setRingerModeInt(getRingerModeInternal(), false);
- final float[] preScale = new float[3];
- preScale[0] = mContext.getResources().getFraction(
- com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
- 1, 1);
- preScale[1] = mContext.getResources().getFraction(
- com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
- 1, 1);
- preScale[2] = mContext.getResources().getFraction(
- com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
- 1, 1);
- for (int i = 0; i < preScale.length; i++) {
- if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
- mPrescaleAbsoluteVolume[i] = preScale[i];
+ if (!disablePrescaleAbsoluteVolume()) {
+ final float[] preScale = new float[3];
+ preScale[0] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+ 1, 1);
+ preScale[1] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+ 1, 1);
+ preScale[2] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+ 1, 1);
+ for (int i = 0; i < preScale.length; i++) {
+ if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
+ mPrescaleAbsoluteVolume[i] = preScale[i];
+ }
}
}
@@ -8618,7 +8620,7 @@
if (index == 0) {
// 0% for volume 0
index = 0;
- } else if (index > 0 && index <= 3) {
+ } else if (!disablePrescaleAbsoluteVolume() && index > 0 && index <= 3) {
// Pre-scale for volume steps 1 2 and 3
index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10;
} else {
@@ -11051,7 +11053,9 @@
final String addr = Objects.requireNonNull(address);
- AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(addr, isBle);
+ AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(addr,
+ (isBle ? AudioSystem.DEVICE_OUT_BLE_HEADSET
+ : AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
int internalType = !isBle ? DEVICE_OUT_BLUETOOTH_A2DP
: ((btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES)
@@ -11067,7 +11071,7 @@
deviceState.setAudioDeviceCategory(btAudioDeviceCategory);
mDeviceBroker.addOrUpdateBtAudioDeviceCategoryInInventory(deviceState);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes());
mSoundDoseHelper.setAudioDeviceCategory(addr, internalType,
@@ -11081,7 +11085,8 @@
super.getBluetoothAudioDeviceCategory_enforcePermission();
final AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(
- Objects.requireNonNull(address), isBle);
+ Objects.requireNonNull(address), (isBle ? AudioSystem.DEVICE_OUT_BLE_HEADSET
+ : AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
if (deviceState == null) {
return AUDIO_DEVICE_CATEGORY_UNKNOWN;
}
@@ -11448,6 +11453,14 @@
pw.print(" adjust-only absolute volume devices="); pw.println(dumpDeviceTypes(
getAbsoluteVolumeDevicesWithBehavior(
AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)));
+ pw.print(" pre-scale for bluetooth absolute volume ");
+ if (disablePrescaleAbsoluteVolume()) {
+ pw.println("= disabled");
+ } else {
+ pw.println("=" + mPrescaleAbsoluteVolume[0]
+ + ", " + mPrescaleAbsoluteVolume[1]
+ + ", " + mPrescaleAbsoluteVolume[2]);
+ }
pw.print(" mExtVolumeController="); pw.println(mExtVolumeController);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
@@ -13585,8 +13598,8 @@
return activeAssistantUids;
}
- UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
- return mDeviceBroker.getDeviceSensorUuid(device);
+ List<String> getDeviceAddresses(AudioDeviceAttributes device) {
+ return mDeviceBroker.getDeviceAddresses(device);
}
//======================
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index cce6bd2..7b96215 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -26,7 +26,9 @@
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecStatus;
import android.bluetooth.BluetoothProfile;
+import android.content.Context;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
@@ -43,6 +45,7 @@
import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -57,9 +60,11 @@
private static final String TAG = "AS.BtHelper";
private final @NonNull AudioDeviceBroker mDeviceBroker;
+ private final @NonNull Context mContext;
- BtHelper(@NonNull AudioDeviceBroker broker) {
+ BtHelper(@NonNull AudioDeviceBroker broker, Context context) {
mDeviceBroker = broker;
+ mContext = context;
}
// BluetoothHeadset API to control SCO connection
@@ -498,6 +503,32 @@
}
}
+ // BluetoothLeAudio callback used to update the list of addresses in the same group as a
+ // connected LE Audio device
+ MyLeAudioCallback mLeAudioCallback = null;
+
+ class MyLeAudioCallback implements BluetoothLeAudio.Callback {
+ @Override
+ public void onCodecConfigChanged(int groupId,
+ @NonNull BluetoothLeAudioCodecStatus status) {
+ // Do nothing
+ }
+
+ @Override
+ public void onGroupNodeAdded(@NonNull BluetoothDevice device, int groupId) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+
+ @Override
+ public void onGroupNodeRemoved(@NonNull BluetoothDevice device, int groupId) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+ @Override
+ public void onGroupStatusChanged(int groupId, int groupStatus) {
+ mDeviceBroker.postUpdateLeAudioGroupAddresses(groupId);
+ }
+ }
+
// @GuardedBy("mDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
@@ -519,6 +550,11 @@
mHearingAid = (BluetoothHearingAid) proxy;
break;
case BluetoothProfile.LE_AUDIO:
+ if (mLeAudio == null) {
+ mLeAudioCallback = new MyLeAudioCallback();
+ ((BluetoothLeAudio) proxy).registerCallback(
+ mContext.getMainExecutor(), mLeAudioCallback);
+ }
mLeAudio = (BluetoothLeAudio) proxy;
break;
case BluetoothProfile.A2DP_SINK:
@@ -977,6 +1013,28 @@
return result;
}
+ /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
+ if (mLeAudio == null || device == null) {
+ return BluetoothLeAudio.GROUP_ID_INVALID;
+ }
+ return mLeAudio.getGroupId(device);
+ }
+
+ /*package*/ List<String> getLeAudioGroupAddresses(int groupId) {
+ List<String> addresses = new ArrayList<String>();
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null || mLeAudio == null) {
+ return addresses;
+ }
+ List<BluetoothDevice> activeDevices = adapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
+ for (BluetoothDevice device : activeDevices) {
+ if (device != null && mLeAudio.getGroupId(device) == groupId) {
+ addresses.add(device.getAddress());
+ }
+ }
+ return addresses;
+ }
+
/**
* Returns the String equivalent of the btCodecType.
*
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 7abd9c7..ea92154 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -564,7 +564,7 @@
}
if (updatedDevice != null) {
onRoutingUpdated();
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(updatedDevice, "addCompatibleAudioDevice");
}
}
@@ -614,7 +614,7 @@
if (deviceState != null && deviceState.isSAEnabled()) {
deviceState.setSAEnabled(false);
onRoutingUpdated();
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "removeCompatibleAudioDevice");
}
}
@@ -716,7 +716,7 @@
ada.getAddress());
initSAState(deviceState);
mDeviceBroker.addOrUpdateDeviceSAStateInInventory(deviceState);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later.
}
}
@@ -1206,7 +1206,7 @@
}
Log.i(TAG, "setHeadTrackerEnabled enabled:" + enabled + " device:" + ada);
deviceState.setHeadTrackerEnabled(enabled);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "setHeadTrackerEnabled");
// check current routing to see if it affects the headtracking mode
@@ -1248,7 +1248,7 @@
if (deviceState != null) {
if (!deviceState.hasHeadTracker()) {
deviceState.setHasHeadTracker(true);
- mDeviceBroker.persistAudioDeviceSettings();
+ mDeviceBroker.postPersistAudioDeviceSettings();
logDeviceState(deviceState, "setHasHeadTracker");
}
return deviceState.isHeadTrackerEnabled();
@@ -1631,25 +1631,33 @@
return headHandle;
}
final AudioDeviceAttributes currentDevice = sRoutingDevices.get(0);
- UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(currentDevice);
+ List<String> deviceAddresses = mAudioService.getDeviceAddresses(currentDevice);
+
// We limit only to Sensor.TYPE_HEAD_TRACKER here to avoid confusion
// with gaming sensors. (Note that Sensor.TYPE_ROTATION_VECTOR
// and Sensor.TYPE_GAME_ROTATION_VECTOR are supported internally by
// SensorPoseProvider).
// Note: this is a dynamic sensor list right now.
List<Sensor> sensors = mSensorManager.getDynamicSensorList(Sensor.TYPE_HEAD_TRACKER);
- for (Sensor sensor : sensors) {
- final UUID uuid = sensor.getUuid();
- if (uuid.equals(routingDeviceUuid)) {
- headHandle = sensor.getHandle();
- if (!setHasHeadTracker(currentDevice)) {
- headHandle = -1;
+ for (String address : deviceAddresses) {
+ UUID routingDeviceUuid = UuidUtils.uuidFromAudioDeviceAttributes(
+ new AudioDeviceAttributes(currentDevice.getInternalType(), address));
+ for (Sensor sensor : sensors) {
+ final UUID uuid = sensor.getUuid();
+ if (uuid.equals(routingDeviceUuid)) {
+ headHandle = sensor.getHandle();
+ if (!setHasHeadTracker(currentDevice)) {
+ headHandle = -1;
+ }
+ break;
}
- break;
+ if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
+ headHandle = sensor.getHandle();
+ // we do not break, perhaps we find a head tracker on device.
+ }
}
- if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
- headHandle = sensor.getHandle();
- // we do not break, perhaps we find a head tracker on device.
+ if (headHandle != -1) {
+ break;
}
}
return headHandle;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ff12ca2..36fc4aa 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -3225,6 +3225,10 @@
if (mSmallAreaDetectionController != null) {
mSmallAreaDetectionController.dump(pw);
}
+
+ pw.println();
+ mFlags.dump(pw);
+
}
private static float[] getFloatArray(TypedArray array) {
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 0d3e0bc..b1c0762 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -18,11 +18,13 @@
import android.os.Build;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.server.display.feature.flags.Flags;
import com.android.server.display.utils.DebugUtils;
+import java.io.PrintWriter;
import java.util.function.Supplier;
/**
@@ -160,6 +162,25 @@
return mSmallAreaDetectionFlagState.isEnabled();
}
+ /**
+ * dumps all flagstates
+ * @param pw printWriter
+ */
+ public void dump(PrintWriter pw) {
+ pw.println("DisplayManagerFlags:");
+ pw.println(" " + mAdaptiveToneImprovements1);
+ pw.println(" " + mAdaptiveToneImprovements2);
+ pw.println(" " + mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState);
+ pw.println(" " + mConnectedDisplayErrorHandlingFlagState);
+ pw.println(" " + mConnectedDisplayManagementFlagState);
+ pw.println(" " + mDisplayOffloadFlagState);
+ pw.println(" " + mExternalDisplayLimitModeState);
+ pw.println(" " + mHdrClamperFlagState);
+ pw.println(" " + mNbmControllerFlagState);
+ pw.println(" " + mPowerThrottlingClamperFlagState);
+ pw.println(" " + mSmallAreaDetectionFlagState);
+ }
+
private static class FlagState {
private final String mName;
@@ -197,5 +218,16 @@
}
return flagValue;
}
+
+ @Override
+ public String toString() {
+ // remove com.android.server.display.feature.flags. from the beginning of the name.
+ // align all isEnabled() values.
+ // Adjust lengths if we end up with longer names
+ final int nameLength = mName.length();
+ return TextUtils.substring(mName, 41, nameLength) + ": "
+ + TextUtils.formatSimple("%" + (93 - nameLength) + "s%s", " " , isEnabled())
+ + " (def:" + mFlagFunction.get() + ")";
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java
index 9172dc0..8278600 100644
--- a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java
@@ -32,10 +32,6 @@
private int mInitialAudioStatusRetriesLeft = 2;
- // Flag to notify AudioService of the next audio status reported,
- // regardless of whether the audio status changed.
- private boolean mForceNextAudioStatusUpdate = false;
-
private static final int STATE_WAIT_FOR_INITIAL_AUDIO_STATUS = 1;
private static final int STATE_MONITOR_AUDIO_STATUS = 2;
@@ -74,13 +70,11 @@
return false;
}
-
/**
* If AVB has been enabled, send <Give Audio Status> and notify AudioService of the response.
*/
void requestAndUpdateAudioStatus() {
if (mState == STATE_MONITOR_AUDIO_STATUS) {
- mForceNextAudioStatusUpdate = true;
sendGiveAudioStatus();
}
}
@@ -104,15 +98,20 @@
localDevice().getService().enableAbsoluteVolumeBehavior(audioStatus);
mState = STATE_MONITOR_AUDIO_STATUS;
} else if (mState == STATE_MONITOR_AUDIO_STATUS) {
- if (mForceNextAudioStatusUpdate
- || audioStatus.getVolume() != mLastAudioStatus.getVolume()) {
+ // On TV panels, we notify AudioService even if neither volume nor mute state changed.
+ // This ensures that the user sees volume UI if they tried to adjust the AVR's volume,
+ // even if the new volume level is the same as the previous one.
+ boolean notifyAvbVolumeToShowUi = localDevice().getService().isTvDevice()
+ && audioStatus.equals(mLastAudioStatus);
+
+ if (audioStatus.getVolume() != mLastAudioStatus.getVolume()
+ || notifyAvbVolumeToShowUi) {
localDevice().getService().notifyAvbVolumeChange(audioStatus.getVolume());
}
- if (mForceNextAudioStatusUpdate
- || audioStatus.getMute() != mLastAudioStatus.getMute()) {
+
+ if (audioStatus.getMute() != mLastAudioStatus.getMute()) {
localDevice().getService().notifyAvbMuteChange(audioStatus.getMute());
}
- mForceNextAudioStatusUpdate = false;
}
mLastAudioStatus = audioStatus;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index d6580df..d3eedd7 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1326,7 +1326,10 @@
removeAction(NewDeviceAction.class);
removeAction(AbsoluteVolumeAudioStatusAction.class);
- disableSystemAudioIfExist();
+ // Keep SAM enabled if eARC is enabled, unless we're going to Standby.
+ if (initiatedByCec || !mService.isEarcEnabled()){
+ disableSystemAudioIfExist();
+ }
disableArcIfExist();
super.disableDevice(initiatedByCec, callback);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c28a68b..b3926fd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3610,7 +3610,7 @@
}
}
- private boolean isEarcEnabled() {
+ public boolean isEarcEnabled() {
synchronized (mLock) {
return mEarcEnabled;
}
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index 79c1346..f6e7ef3 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -61,6 +61,7 @@
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
/**
* A class to manage native tombstones.
@@ -74,6 +75,8 @@
private final Handler mHandler;
private final TombstoneWatcher mWatcher;
+ private final ReentrantLock mTmpFileLock = new ReentrantLock();
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -114,7 +117,12 @@
// Clean up temporary files if they made it this far (e.g. if system server crashes).
if (filename.endsWith(".tmp")) {
- path.delete();
+ mTmpFileLock.lock();
+ try {
+ path.delete();
+ } finally {
+ mTmpFileLock.unlock();
+ }
return;
}
@@ -130,7 +138,7 @@
if (parsedTombstone.isPresent()) {
processName = parsedTombstone.get().getProcessName();
}
- BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName);
+ BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock);
}
private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a52870e..f8d27f1 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -476,20 +476,30 @@
pkgSetting.setLoadingProgress(1f);
}
+ // TODO: passes the package name as an argument in a message to the handler for V+
+ // so we don't need to rely on creating lambda objects so frequently.
+ if (UpdateOwnershipHelper.hasValidOwnershipDenyList(pkgSetting)) {
+ mPm.mHandler.post(() -> handleUpdateOwnerDenyList(pkgSetting));
+ }
+ return pkg;
+ }
+
+ private void handleUpdateOwnerDenyList(PackageSetting pkgSetting) {
ArraySet<String> listItems = mUpdateOwnershipHelper.readUpdateOwnerDenyList(pkgSetting);
if (listItems != null && !listItems.isEmpty()) {
- mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(), listItems);
- for (String unownedPackage : listItems) {
- PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage);
- SystemConfig config = SystemConfig.getInstance();
- if (unownedSetting != null
- && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) {
- unownedSetting.setUpdateOwnerPackage(null);
+ mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(),
+ listItems);
+ SystemConfig config = SystemConfig.getInstance();
+ synchronized (mPm.mLock) {
+ for (String unownedPackage : listItems) {
+ PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage);
+ if (unownedSetting != null
+ && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) {
+ unownedSetting.setUpdateOwnerPackage(null);
+ }
}
}
}
-
- return pkg;
}
/**
diff --git a/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java
index 43752f3..adac68b 100644
--- a/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java
+++ b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java
@@ -48,7 +48,7 @@
private final Object mLock = new Object();
- private static boolean hasValidOwnershipDenyList(PackageSetting pkgSetting) {
+ static boolean hasValidOwnershipDenyList(PackageSetting pkgSetting) {
AndroidPackage pkg = pkgSetting.getPkg();
// we're checking for uses-permission for these priv permissions instead of grant as we're
// only considering system apps to begin with, so presumed to be granted.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 4a4214f..8ce0c72 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -32,6 +32,7 @@
import static android.os.PowerManagerInternal.wakefulnessToString;
import static com.android.internal.util.LatencyTracker.ACTION_TURN_ON_SCREEN;
+import static com.android.server.deviceidle.Flags.disableWakelocksInLightIdle;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -644,9 +645,11 @@
private boolean mBatteryLevelLow;
// True if we are currently in device idle mode.
+ @GuardedBy("mLock")
private boolean mDeviceIdleMode;
// True if we are currently in light device idle mode.
+ @GuardedBy("mLock")
private boolean mLightDeviceIdleMode;
// Set of app ids that we will respect the wake locks for while in device idle mode.
@@ -4035,6 +4038,9 @@
synchronized (mLock) {
if (mLightDeviceIdleMode != enabled) {
mLightDeviceIdleMode = enabled;
+ if (!mDeviceIdleMode && disableWakelocksInLightIdle()) {
+ updateWakeLockDisabledStatesLocked();
+ }
setPowerModeInternal(MODE_DEVICE_IDLE, mDeviceIdleMode || mLightDeviceIdleMode);
return true;
}
@@ -4045,7 +4051,7 @@
void setDeviceIdleWhitelistInternal(int[] appids) {
synchronized (mLock) {
mDeviceIdleWhitelist = appids;
- if (mDeviceIdleMode) {
+ if (doesIdleStateBlockWakeLocksLocked()) {
updateWakeLockDisabledStatesLocked();
}
}
@@ -4054,7 +4060,7 @@
void setDeviceIdleTempWhitelistInternal(int[] appids) {
synchronized (mLock) {
mDeviceIdleTempWhitelist = appids;
- if (mDeviceIdleMode) {
+ if (doesIdleStateBlockWakeLocksLocked()) {
updateWakeLockDisabledStatesLocked();
}
}
@@ -4114,7 +4120,7 @@
<= ActivityManager.PROCESS_STATE_RECEIVER;
state.mProcState = procState;
if (state.mNumWakeLocks > 0) {
- if (mDeviceIdleMode || mLowPowerStandbyActive) {
+ if (doesIdleStateBlockWakeLocksLocked() || mLowPowerStandbyActive) {
handleUidStateChangeLocked();
} else if (!state.mActive && oldShouldAllow !=
(procState <= ActivityManager.PROCESS_STATE_RECEIVER)) {
@@ -4134,7 +4140,8 @@
state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
state.mActive = false;
mUidState.removeAt(index);
- if ((mDeviceIdleMode || mLowPowerStandbyActive) && state.mNumWakeLocks > 0) {
+ if ((doesIdleStateBlockWakeLocksLocked() || mLowPowerStandbyActive)
+ && state.mNumWakeLocks > 0) {
handleUidStateChangeLocked();
}
}
@@ -4169,6 +4176,11 @@
}
@GuardedBy("mLock")
+ private boolean doesIdleStateBlockWakeLocksLocked() {
+ return mDeviceIdleMode || (mLightDeviceIdleMode && disableWakelocksInLightIdle());
+ }
+
+ @GuardedBy("mLock")
private void updateWakeLockDisabledStatesLocked() {
boolean changed = false;
final int numWakeLocks = mWakeLocks.size();
@@ -4207,7 +4219,7 @@
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
}
- if (mDeviceIdleMode) {
+ if (doesIdleStateBlockWakeLocksLocked()) {
// If we are in idle mode, we will also ignore all partial wake locks that are
// for application uids that are not allowlisted.
final UidState state = wakeLock.mUidState;
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 97420d0..c1da589 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1281,12 +1281,19 @@
private void addBytesTransferByTagAndMeteredAtoms(@NonNull NetworkStatsExt statsExt,
@NonNull List<StatsEvent> pulledData) {
+ // Workaround for 5G NSA mode, see {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}.
+ // 5G NSA mode means the primary cell is LTE with a secondary connection to an
+ // NR cell. To mitigate risk, NetworkStats is currently storing this state as
+ // a fake RAT type rather than storing the boolean separately.
+ final boolean is5GNsa = statsExt.ratType == NetworkStatsManager.NETWORK_TYPE_5G_NSA;
+
for (NetworkStats.Entry entry : statsExt.stats) {
pulledData.add(FrameworkStatsLog.buildStatsEvent(
FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED, entry.getUid(),
entry.getMetered() == NetworkStats.METERED_YES, entry.getTag(),
entry.getRxBytes(), entry.getRxPackets(), entry.getTxBytes(),
- entry.getTxPackets()));
+ entry.getTxPackets(),
+ is5GNsa ? TelephonyManager.NETWORK_TYPE_LTE : statsExt.ratType));
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a6d5c19..7b20529 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -4,6 +4,10 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.processStateAmToProto;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.app.WaitResult.INVALID_DELAY;
import static android.app.WaitResult.LAUNCH_STATE_COLD;
import static android.app.WaitResult.LAUNCH_STATE_HOT;
@@ -84,8 +88,7 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityOptions.SourceInfo;
-import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
import android.content.ComponentName;
@@ -1602,17 +1605,17 @@
void logCameraCompatControlAppearedEventReported(@CameraCompatControlState int state,
int packageUid) {
switch (state) {
- case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+ case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
logCameraCompatControlEventReported(
CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT,
packageUid);
break;
- case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+ case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
logCameraCompatControlEventReported(
CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT,
packageUid);
break;
- case TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN:
+ case CAMERA_COMPAT_CONTROL_HIDDEN:
// Nothing to log.
break;
default:
@@ -1629,17 +1632,17 @@
void logCameraCompatControlClickedEventReported(@CameraCompatControlState int state,
int packageUid) {
switch (state) {
- case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+ case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
logCameraCompatControlEventReported(
CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT,
packageUid);
break;
- case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+ case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
logCameraCompatControlEventReported(
CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT,
packageUid);
break;
- case TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED:
+ case CAMERA_COMPAT_CONTROL_DISMISSED:
logCameraCompatControlEventReported(
CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS,
packageUid);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d6637e1..eeeca10 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -31,6 +31,10 @@
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.ActivityOptions.ANIM_UNDEFINED;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
import static android.app.WaitResult.INVALID_DELAY;
@@ -258,13 +262,13 @@
import android.app.Activity;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
+import android.app.AppCompatTaskInfo;
+import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.ICompatCameraControlCallback;
import android.app.IScreenCaptureObserver;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.ResultInfo;
-import android.app.TaskInfo;
-import android.app.TaskInfo.CameraCompatControlState;
import android.app.WaitResult;
import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyManager;
@@ -810,7 +814,7 @@
// State of the Camera app compat control which is used to correct stretched viewfinder
// in apps that don't handle all possible configurations and changes between them correctly.
@CameraCompatControlState
- private int mCameraCompatControlState = TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+ private int mCameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN;
// The callback that allows to ask the calling View to apply the treatment for stretched
@@ -1323,7 +1327,7 @@
mLetterboxUiController.dump(pw, prefix);
pw.println(prefix + "mCameraCompatControlState="
- + TaskInfo.cameraCompatControlStateToString(mCameraCompatControlState));
+ + AppCompatTaskInfo.cameraCompatControlStateToString(mCameraCompatControlState));
pw.println(prefix + "mCameraCompatControlEnabled=" + mCameraCompatControlEnabled);
}
@@ -1861,24 +1865,24 @@
return;
}
if (mCameraCompatControlClickedByUser && (showControl
- || mCameraCompatControlState == TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED)) {
+ || mCameraCompatControlState == CAMERA_COMPAT_CONTROL_DISMISSED)) {
// The user already applied treatment on this activity or dismissed control.
// Respecting their choice.
return;
}
mCompatCameraControlCallback = callback;
int newCameraCompatControlState = !showControl
- ? TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN
+ ? CAMERA_COMPAT_CONTROL_HIDDEN
: transformationApplied
- ? TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED
- : TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+ ? CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED
+ : CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
boolean changed = setCameraCompatControlState(newCameraCompatControlState);
if (!changed) {
return;
}
mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlAppearedEventReported(
newCameraCompatControlState, info.applicationInfo.uid);
- if (newCameraCompatControlState == TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN) {
+ if (newCameraCompatControlState == CAMERA_COMPAT_CONTROL_HIDDEN) {
mCameraCompatControlClickedByUser = false;
mCompatCameraControlCallback = null;
}
@@ -1896,7 +1900,7 @@
// Feature is disabled by config_isCameraCompatControlForStretchedIssuesEnabled.
return;
}
- if (state == TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN) {
+ if (state == CAMERA_COMPAT_CONTROL_HIDDEN) {
Slog.w(TAG, "Unexpected hidden state in updateCameraCompatState");
return;
}
@@ -1907,7 +1911,7 @@
}
mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlClickedEventReported(
state, info.applicationInfo.uid);
- if (state == TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED) {
+ if (state == CAMERA_COMPAT_CONTROL_DISMISSED) {
mCompatCameraControlCallback = null;
return;
}
@@ -1916,7 +1920,7 @@
return;
}
try {
- if (state == TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED) {
+ if (state == CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED) {
mCompatCameraControlCallback.applyCameraCompatTreatment();
} else {
mCompatCameraControlCallback.revertCameraCompatTreatment();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0698be..f462efc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -125,7 +125,6 @@
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import android.Manifest;
import android.annotation.IntDef;
@@ -166,7 +165,6 @@
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.compat.CompatChanges;
-import android.app.sdksandbox.sandboxactivity.SdkSandboxActivityAuthority;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -1260,13 +1258,6 @@
true /*validateIncomingUser*/);
}
- static boolean isSdkSandboxActivity(Context context, Intent intent) {
- return intent != null
- && (sandboxActivitySdkBasedContext()
- ? SdkSandboxActivityAuthority.isSdkSandboxActivity(context, intent)
- : intent.isSandboxActivity(context));
- }
-
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
@@ -1277,7 +1268,7 @@
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
- if (isSdkSandboxActivity(mContext, intent)) {
+ if (intent != null && intent.isSandboxActivity(mContext)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index e5eb303..777b5cd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1089,7 +1089,7 @@
// Remove the process record so it won't be considered as alive.
mService.mProcessNames.remove(wpc.mName, wpc.mUid);
mService.mProcessMap.remove(wpc.getPid());
- } else if (ActivityTaskManagerService.isSdkSandboxActivity(mService.mContext, r.intent)) {
+ } else if (r.intent.isSandboxActivity(mService.mContext)) {
Slog.e(TAG, "Abort sandbox activity launching as no sandbox process to host it.");
r.finishIfPossible("No sandbox process for the activity", false /* oomAdj */);
r.launchFailed = true;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 2d37b9b..87ae045 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -78,8 +78,6 @@
private @BackNavigationInfo.BackTargetType int mLastBackType;
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
-
- private boolean mBackAnimationRunning;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
private AnimationHandler mAnimationHandler;
@@ -248,12 +246,13 @@
// - We have an application callback.
// - We don't have any ActivityRecord or Task to animate.
// - The IME is opened, and we just need to close it.
- // - The home activity is the focused activity.
+ // - The home activity is the focused activity & it's not TYPE_BASE_APPLICATION
// - The current activity will do shared element transition when exiting.
if (backType == BackNavigationInfo.TYPE_CALLBACK
|| currentActivity == null
|| currentTask == null
- || currentActivity.isActivityTypeHome()
+ || (currentActivity.isActivityTypeHome()
+ && window.mAttrs.type == TYPE_BASE_APPLICATION)
|| currentActivity.mHasSceneTransition) {
infoBuilder.setType(BackNavigationInfo.TYPE_CALLBACK);
infoBuilder.setOnBackNavigationDone(new RemoteCallback(result ->
@@ -363,14 +362,21 @@
// For now, we only animate when going home, cross task or cross-activity.
boolean prepareAnimation =
(backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
- || backType == BackNavigationInfo.TYPE_CROSS_TASK
- || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY)
- && adapter != null;
+ || backType == BackNavigationInfo.TYPE_CROSS_TASK
+ || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY
+ || backType == BackNavigationInfo.TYPE_DIALOG_CLOSE)
+ && adapter != null;
if (prepareAnimation) {
final AnimationHandler.ScheduleAnimationBuilder builder =
- mAnimationHandler.prepareAnimation(backType, adapter,
- currentTask, prevTask, currentActivity, prevActivities);
+ mAnimationHandler.prepareAnimation(
+ backType,
+ adapter,
+ currentTask,
+ prevTask,
+ currentActivity,
+ prevActivities,
+ removedWindowContainer);
mBackAnimationInProgress = builder != null;
if (mBackAnimationInProgress) {
if (removedWindowContainer.hasCommittedReparentToAnimationLeash()
@@ -739,7 +745,6 @@
mAnimationHandler.clearBackAnimateTarget();
mNavigationMonitor.stopMonitorTransition();
mWaitTransitionFinish = null;
- mBackAnimationRunning = false;
}
/**
@@ -836,6 +841,7 @@
private static final int UNKNOWN = 0;
private static final int TASK_SWITCH = 1;
private static final int ACTIVITY_SWITCH = 2;
+ private static final int DIALOG_CLOSE = 3;
private static boolean isActivitySwitch(@NonNull WindowContainer close,
@NonNull WindowContainer[] open) {
@@ -860,12 +866,18 @@
return open[0].asTask() != null && (close.asTask() != open[0].asTask());
}
+ private static boolean isDialogClose(WindowContainer close) {
+ return close.asWindowState() != null;
+ }
+
private void initiate(@NonNull WindowContainer close, @NonNull WindowContainer[] open,
@NonNull ActivityRecord[] openingActivities) {
if (isActivitySwitch(close, open)) {
mSwitchType = ACTIVITY_SWITCH;
} else if (isTaskSwitch(close, open)) {
mSwitchType = TASK_SWITCH;
+ } else if (isDialogClose(close)) {
+ mSwitchType = DIALOG_CLOSE;
} else {
mSwitchType = UNKNOWN;
return;
@@ -1173,6 +1185,7 @@
mIsOpen = isOpen;
mSwitchType = switchType;
}
+
@Override
public boolean getShowWallpaper() {
return false;
@@ -1182,7 +1195,14 @@
public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
mCapturedLeash = animationLeash;
- createRemoteAnimationTarget(mIsOpen);
+ createRemoteAnimationTarget();
+ final WindowState win = mTarget.asWindowState();
+ if (win != null && mSwitchType == DIALOG_CLOSE) {
+ final Rect frame = win.getFrame();
+ final Point position = new Point();
+ win.transformFrameToSurfacePosition(frame.left, frame.top, position);
+ t.setPosition(mCapturedLeash, position.x, position.y);
+ }
}
@Override
@@ -1216,12 +1236,14 @@
}
- RemoteAnimationTarget createRemoteAnimationTarget(boolean isOpen) {
+ RemoteAnimationTarget createRemoteAnimationTarget() {
if (mAnimationTarget != null) {
return mAnimationTarget;
}
- Task t = mTarget.asTask();
- ActivityRecord r = null;
+
+ WindowState w = mTarget.asWindowState();
+ ActivityRecord r = w != null ? w.getActivityRecord() : null;
+ Task t = r != null ? r.getTask() : mTarget.asTask();
if (t == null && mTarget.asTaskFragment() != null) {
t = mTarget.asTaskFragment().getTask();
r = mTarget.asTaskFragment().getTopNonFinishingActivity();
@@ -1247,7 +1269,7 @@
} else {
insets = new Rect();
}
- final int mode = isOpen ? MODE_OPENING : MODE_CLOSING;
+ final int mode = mIsOpen ? MODE_OPENING : MODE_CLOSING;
mAnimationTarget = new RemoteAnimationTarget(t.mTaskId, mode, mCapturedLeash,
!r.fillsParent(), new Rect(),
insets, r.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
@@ -1261,6 +1283,9 @@
if (!mIsOpen) {
return;
}
+ if (mSwitchType == DIALOG_CLOSE) {
+ return;
+ }
final Task openTask = mSwitchType == TASK_SWITCH
? mTarget.asTask() : mSwitchType == ACTIVITY_SWITCH
? mTarget.asActivityRecord().getTask() : null;
@@ -1332,9 +1357,14 @@
}
}
- ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter,
- Task currentTask, Task previousTask, ActivityRecord currentActivity,
- ArrayList<ActivityRecord> previousActivity) {
+ ScheduleAnimationBuilder prepareAnimation(
+ int backType,
+ BackAnimationAdapter adapter,
+ Task currentTask,
+ Task previousTask,
+ ActivityRecord currentActivity,
+ ArrayList<ActivityRecord> previousActivity,
+ WindowContainer removedWindowContainer) {
switch (backType) {
case BackNavigationInfo.TYPE_RETURN_TO_HOME:
return new ScheduleAnimationBuilder(backType, adapter)
@@ -1350,6 +1380,10 @@
return new ScheduleAnimationBuilder(backType, adapter)
.setComposeTarget(currentTask, previousTask)
.setIsLaunchBehind(false);
+ case BackNavigationInfo.TYPE_DIALOG_CLOSE:
+ return new ScheduleAnimationBuilder(backType, adapter)
+ .setComposeTarget(removedWindowContainer, currentActivity)
+ .setIsLaunchBehind(false);
}
return null;
}
@@ -1574,7 +1608,6 @@
if (mPendingAnimation != null) {
mPendingAnimation.run();
mPendingAnimation = null;
- mBackAnimationRunning = true;
}
}
@@ -1629,7 +1662,9 @@
} else {
proto.write(MAIN_OPEN_ACTIVITY, "");
}
- proto.write(ANIMATION_RUNNING, mBackAnimationRunning);
+ // TODO (b/268563842) Only meaningful after new test added
+ proto.write(ANIMATION_RUNNING, mAnimationHandler.mComposed
+ || mAnimationHandler.mWaitTransition);
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 68082df..2f9ef50 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -29,6 +30,7 @@
import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import static com.android.server.wm.ActivityTaskSupervisor.getApplicationLabel;
import static com.android.window.flags.Flags.balShowToasts;
+import static com.android.window.flags.Flags.balShowToastsBlocked;
import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -53,6 +55,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.Preconditions;
import com.android.server.UiThread;
import com.android.server.am.PendingIntentRecord;
@@ -261,7 +264,13 @@
mIsCallingUidPersistentSystemProcess =
mCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
mCallingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
- if (callingUid == realCallingUid) {
+ if (realCallingUid == NO_PROCESS_UID) {
+ // no process provided
+ mRealCallingUidProcState = PROCESS_STATE_NONEXISTENT;
+ mRealCallingUidHasAnyVisibleWindow = false;
+ mRealCallerApp = null;
+ mIsRealCallingUidPersistentSystemProcess = false;
+ } else if (callingUid == realCallingUid) {
mRealCallingUidProcState = mCallingUidProcState;
mRealCallingUidHasAnyVisibleWindow = mCallingUidHasAnyVisibleWindow;
// In the PendingIntent case callerApp is not passed in, so resolve it ourselves.
@@ -293,43 +302,67 @@
return name + "[debugOnly]";
}
+ private boolean isPendingIntent() {
+ return mRealCallingUid != NO_PROCESS_UID;
+ }
+
+ private String dump(BalVerdict resultIfPiCreatorAllowsBal) {
+ Preconditions.checkState(!isPendingIntent());
+ return dump(resultIfPiCreatorAllowsBal, null);
+ }
+
private boolean callerIsRealCaller() {
return mCallingUid == mRealCallingUid;
}
private String dump(BalVerdict resultIfPiCreatorAllowsBal,
- BalVerdict resultIfPiSenderAllowsBal) {
- return " [callingPackage: " + getDebugPackageName(mCallingPackage, mCallingUid)
- + "; callingUid: " + mCallingUid
- + "; appSwitchState: " + mAppSwitchState
- + "; callingUidHasAnyVisibleWindow: " + mCallingUidHasAnyVisibleWindow
- + "; callingUidProcState: " + DebugUtils.valueToString(
- ActivityManager.class, "PROCESS_STATE_", mCallingUidProcState)
- + "; isCallingUidPersistentSystemProcess: "
- + mIsCallingUidPersistentSystemProcess
- + "; balAllowedByPiCreator: " + mBalAllowedByPiCreator
- + "; balAllowedByPiSender: " + mBalAllowedByPiSender
- + "; realCallingPackage: "
- + getDebugPackageName(mRealCallingPackage, mRealCallingUid)
- + "; realCallingUid: " + mRealCallingUid
- + "; realCallingPid: " + mRealCallingPid
- + "; realCallingUidHasAnyVisibleWindow: " + mRealCallingUidHasAnyVisibleWindow
- + "; realCallingUidProcState: " + DebugUtils.valueToString(
- ActivityManager.class, "PROCESS_STATE_", mRealCallingUidProcState)
- + "; isRealCallingUidPersistentSystemProcess: "
- + mIsRealCallingUidPersistentSystemProcess
- + "; originatingPendingIntent: " + mOriginatingPendingIntent
- + "; backgroundStartPrivileges: " + mBackgroundStartPrivileges
- + "; intent: " + mIntent
- + "; callerApp: " + mCallerApp
- + "; realCallerApp: " + mRealCallerApp
- + "; inVisibleTask: "
- + (mCallerApp != null && mCallerApp.hasActivityInVisibleTask())
- + "; realInVisibleTask: "
- + (mRealCallerApp != null && mRealCallerApp.hasActivityInVisibleTask())
- + "; resultIfPiSenderAllowsBal: " + resultIfPiSenderAllowsBal
- + "; resultIfPiCreatorAllowsBal: " + resultIfPiCreatorAllowsBal
- + "]";
+ BalVerdict resultIfPiSenderAllowsBal) {
+ StringBuilder sb = new StringBuilder(2048);
+ sb.append("[callingPackage: ")
+ .append(getDebugPackageName(mCallingPackage, mCallingUid));
+ sb.append("; callingUid: ").append(mCallingUid);
+ sb.append("; callingPid: ").append(mCallingPid);
+ sb.append("; isPendingIntent: ").append(isPendingIntent());
+ sb.append("; appSwitchState: ").append(mAppSwitchState);
+ sb.append("; callingUidHasAnyVisibleWindow: ").append(mCallingUidHasAnyVisibleWindow);
+ sb.append("; callingUidProcState: ").append(DebugUtils.valueToString(
+ ActivityManager.class, "PROCESS_STATE_", mCallingUidProcState));
+ sb.append("; isCallingUidPersistentSystemProcess: ")
+ .append(mIsCallingUidPersistentSystemProcess);
+ sb.append("; balAllowedByPiCreator: ").append(mBalAllowedByPiCreator);
+ if (isPendingIntent()) {
+ sb.append("; balAllowedByPiSender: ").append(mBalAllowedByPiSender);
+ sb.append("; realCallingPackage: ")
+ .append(getDebugPackageName(mRealCallingPackage, mRealCallingUid));
+ sb.append("; realCallingUid: ").append(mRealCallingUid);
+ sb.append("; realCallingPid: ").append(mRealCallingPid);
+ sb.append("; realCallingUidHasAnyVisibleWindow: ")
+ .append(mRealCallingUidHasAnyVisibleWindow);
+ sb.append("; realCallingUidProcState: ").append(DebugUtils.valueToString(
+ ActivityManager.class, "PROCESS_STATE_", mRealCallingUidProcState));
+ sb.append("; isRealCallingUidPersistentSystemProcess: ")
+ .append(mIsRealCallingUidPersistentSystemProcess);
+ sb.append("; originatingPendingIntent: ").append(mOriginatingPendingIntent);
+ }
+ sb.append("; backgroundStartPrivileges: ").append(mBackgroundStartPrivileges);
+ sb.append("; intent: ").append(mIntent);
+ sb.append("; callerApp: ").append(mCallerApp);
+ if (isPendingIntent()) {
+ sb.append("; realCallerApp: ").append(mRealCallerApp);
+ }
+ if (mCallerApp != null) {
+ sb.append("; inVisibleTask: ").append(mCallerApp.hasActivityInVisibleTask());
+ }
+ if (isPendingIntent()) {
+ if (mRealCallerApp != null) {
+ sb.append("; realInVisibleTask: ")
+ .append(mRealCallerApp.hasActivityInVisibleTask());
+ }
+ sb.append("; resultIfPiSenderAllowsBal: ").append(resultIfPiSenderAllowsBal);
+ }
+ sb.append("; resultIfPiCreatorAllowsBal: ").append(resultIfPiCreatorAllowsBal);
+ sb.append("]");
+ return sb.toString();
}
}
@@ -428,9 +461,31 @@
}
BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state);
+
+ if (!state.isPendingIntent()) {
+ if (resultForCaller.allows()) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "Background activity start allowed. "
+ + state.dump(resultForCaller));
+ }
+ return statsLog(resultForCaller, state);
+ }
+ // anything that has fallen through would currently be aborted
+ Slog.w(TAG, "Background activity launch blocked! "
+ + state.dump(resultForCaller));
+ showBalBlockedToast("BAL blocked", state);
+ return statsLog(BalVerdict.BLOCK, state);
+ }
+
+ // The realCaller result is only calculated for PendingIntents (indicated by a valid
+ // realCallingUid). If caller and realCaller are same UID and we are already allowed based
+ // on the caller (i.e. creator of the PendingIntent) there is no need to calculate this
+ // again, but if the result is block it is possible that there are additional exceptions
+ // that allow based on the realCaller (i.e. sender of the PendingIntent), e.g. if the
+ // realCallerApp process is allowed to start (in the creator path the callerApp for
+ // PendingIntents is null).
BalVerdict resultForRealCaller = state.callerIsRealCaller() && resultForCaller.allows()
- ? resultForCaller // no need to calculate again
- // otherwise we might need to recalculate because the logic is not the same
+ ? resultForCaller
: checkBackgroundActivityStartAllowedBySender(state, checkedOptions);
if (resultForCaller.allows()
@@ -458,10 +513,12 @@
== ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) {
// Both caller and real caller allow with system defined behavior
Slog.wtf(TAG,
- "With Android 15 BAL hardening this activity start would be blocked"
+ "With Android 15 BAL hardening this activity start may be blocked"
+ + " if the PI creator upgrades target_sdk to 35+"
+ + " AND the PI sender upgrades target_sdk to 34+! "
+ " (missing opt in by PI creator)! "
+ state.dump(resultForCaller, resultForRealCaller));
- showBalToast("BAL would be blocked", state);
+ showBalRiskToast("BAL would be blocked", state);
// return the realCaller result for backwards compatibility
return statsLog(resultForRealCaller, state);
}
@@ -470,10 +527,11 @@
== ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) {
// Allowed before V by creator
Slog.wtf(TAG,
- "With Android 15 BAL hardening this activity start would be blocked"
+ "With Android 15 BAL hardening this activity start may be blocked"
+ + " if the PI creator upgrades target_sdk to 35+! "
+ " (missing opt in by PI creator)! "
+ state.dump(resultForCaller, resultForRealCaller));
- showBalToast("BAL would be blocked", state);
+ showBalRiskToast("BAL would be blocked", state);
return statsLog(resultForCaller, state);
}
if (resultForRealCaller.allows()
@@ -482,10 +540,11 @@
// Allowed before U by sender
if (state.mBalAllowedByPiSender.allowsBackgroundActivityStarts()) {
Slog.wtf(TAG,
- "With Android 14 BAL hardening this activity start would be blocked"
+ "With Android 14 BAL hardening this activity start will be blocked"
+ + " if the PI sender upgrades target_sdk to 34+! "
+ " (missing opt in by PI sender)! "
+ state.dump(resultForCaller, resultForRealCaller));
- showBalToast("BAL would be blocked", state);
+ showBalBlockedToast("BAL would be blocked", state);
return statsLog(resultForRealCaller, state);
}
Slog.wtf(TAG, "Without Android 14 BAL hardening this activity start would be allowed"
@@ -493,26 +552,10 @@
+ state.dump(resultForCaller, resultForRealCaller));
// fall through
}
- showBalToast("BAL blocked", state);
// anything that has fallen through would currently be aborted
- Slog.w(TAG, "Background activity launch blocked"
+ Slog.w(TAG, "Background activity launch blocked! "
+ state.dump(resultForCaller, resultForRealCaller));
- // log aborted activity start to TRON
- if (mService.isActivityStartsLoggingEnabled()) {
- mSupervisor
- .getActivityMetricsLogger()
- .logAbortedBgActivityStart(
- intent,
- callerApp,
- callingUid,
- callingPackage,
- state.mCallingUidProcState,
- state.mCallingUidHasAnyVisibleWindow,
- realCallingUid,
- state.mRealCallingUidProcState,
- state.mRealCallingUidHasAnyVisibleWindow,
- (originatingPendingIntent != null));
- }
+ showBalBlockedToast("BAL blocked", state);
return statsLog(BalVerdict.BLOCK, state);
}
@@ -887,7 +930,15 @@
return true;
}
- private void showBalToast(String toastText, BalState state) {
+ private void showBalBlockedToast(String toastText, BalState state) {
+ if (balShowToastsBlocked()) {
+ showToast(toastText
+ + " caller:" + state.mCallingPackage
+ + " realCaller:" + state.mRealCallingPackage);
+ }
+ }
+
+ private void showBalRiskToast(String toastText, BalState state) {
if (balShowToasts()) {
showToast(toastText
+ " caller:" + state.mCallingPackage
@@ -1239,7 +1290,24 @@
/* defaultValue= */ true);
}
- private static BalVerdict statsLog(BalVerdict finalVerdict, BalState state) {
+ private BalVerdict statsLog(BalVerdict finalVerdict, BalState state) {
+ if (finalVerdict.blocks() && mService.isActivityStartsLoggingEnabled()) {
+ // log aborted activity start to TRON
+ mSupervisor
+ .getActivityMetricsLogger()
+ .logAbortedBgActivityStart(
+ state.mIntent,
+ state.mCallerApp,
+ state.mCallingUid,
+ state.mCallingPackage,
+ state.mCallingUidProcState,
+ state.mCallingUidHasAnyVisibleWindow,
+ state.mRealCallingUid,
+ state.mRealCallingUidProcState,
+ state.mRealCallingUidHasAnyVisibleWindow,
+ (state.mOriginatingPendingIntent != null));
+ }
+
@BalCode int code = finalVerdict.getCode();
int callingUid = state.mCallingUid;
int realCallingUid = state.mRealCallingUid;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c716879..7f80807 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2436,13 +2436,14 @@
// AppBounds at the root level should mirror the app screen size.
outConfig.windowConfiguration.setAppBounds(info.mNonDecorFrame);
outConfig.windowConfiguration.setRotation(rotation);
- outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
final float density = mDisplayMetrics.density;
outConfig.screenWidthDp = (int) (info.mConfigFrame.width() / density + 0.5f);
outConfig.screenHeightDp = (int) (info.mConfigFrame.height() / density + 0.5f);
outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
+ outConfig.orientation = (outConfig.screenWidthDp <= outConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
outConfig.screenLayout = computeScreenLayout(
Configuration.resetScreenLayout(outConfig.screenLayout),
outConfig.screenWidthDp, outConfig.screenHeightDp);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5c5a1e1..6f19425 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -137,6 +137,7 @@
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
+import android.app.AppCompatTaskInfo;
import android.app.AppGlobals;
import android.app.IActivityController;
import android.app.PictureInPictureParams;
@@ -3462,20 +3463,21 @@
&& top.getOrganizedTask() == this && top.isState(RESUMED);
final boolean isTopActivityVisible = top != null
&& top.getOrganizedTask() == this && top.isVisible();
+ final AppCompatTaskInfo appCompatTaskInfo = info.appCompatTaskInfo;
// Whether the direct top activity is in size compat mode
- info.topActivityInSizeCompat = isTopActivityVisible && top.inSizeCompatMode();
- if (info.topActivityInSizeCompat
+ appCompatTaskInfo.topActivityInSizeCompat = isTopActivityVisible && top.inSizeCompatMode();
+ if (appCompatTaskInfo.topActivityInSizeCompat
&& mWmService.mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) {
// We hide the restart button in case of transparent activities.
- info.topActivityInSizeCompat = top.fillsParent();
+ appCompatTaskInfo.topActivityInSizeCompat = top.fillsParent();
}
// Whether the direct top activity is eligible for letterbox education.
- info.topActivityEligibleForLetterboxEducation = isTopActivityResumed
+ appCompatTaskInfo.topActivityEligibleForLetterboxEducation = isTopActivityResumed
&& top.isEligibleForLetterboxEducation();
// Whether the direct top activity requested showing camera compat control.
- info.cameraCompatControlState = isTopActivityResumed
+ appCompatTaskInfo.cameraCompatControlState = isTopActivityResumed
? top.getCameraCompatControlState()
- : TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+ : AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
final Task parentTask = getParent() != null ? getParent().asTask() : null;
info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer
@@ -3485,34 +3487,34 @@
info.isVisible = hasVisibleChildren();
info.isVisibleRequested = isVisibleRequested();
info.isSleeping = shouldSleepActivities();
- info.isLetterboxDoubleTapEnabled = top != null
- && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
- info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
- info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
- info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
- info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
- info.isUserFullscreenOverrideEnabled = top != null
- && top.mLetterboxUiController.shouldApplyUserFullscreenOverride();
info.isTopActivityTransparent = top != null && !top.fillsParent();
- info.isFromLetterboxDoubleTap = top != null && top.mLetterboxUiController.isFromDoubleTap();
- if (info.isLetterboxDoubleTapEnabled) {
- info.topActivityLetterboxWidth = top.getBounds().width();
- info.topActivityLetterboxHeight = top.getBounds().height();
- if (info.topActivityLetterboxWidth < info.topActivityLetterboxHeight) {
+ appCompatTaskInfo.isLetterboxDoubleTapEnabled = top != null
+ && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
+ appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
+ appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
+ appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
+ appCompatTaskInfo.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
+ appCompatTaskInfo.isUserFullscreenOverrideEnabled = top != null
+ && top.mLetterboxUiController.shouldApplyUserFullscreenOverride();
+ appCompatTaskInfo.isFromLetterboxDoubleTap = top != null
+ && top.mLetterboxUiController.isFromDoubleTap();
+ if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) {
+ appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width();
+ appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height();
+ if (appCompatTaskInfo.isTopActivityPillarboxed()) {
// Pillarboxed
- info.topActivityLetterboxHorizontalPosition =
+ appCompatTaskInfo.topActivityLetterboxHorizontalPosition =
top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability();
} else {
// Letterboxed
- info.topActivityLetterboxVerticalPosition =
+ appCompatTaskInfo.topActivityLetterboxVerticalPosition =
top.mLetterboxUiController.getLetterboxPositionForVerticalReachability();
}
}
- // User Aspect Ratio Settings is enabled if the app is not in SCM
- info.topActivityEligibleForUserAspectRatioButton = top != null
- && !info.topActivityInSizeCompat
+ appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton = top != null
+ && !appCompatTaskInfo.topActivityInSizeCompat
&& top.mLetterboxUiController.shouldEnableUserAspectRatioSettings();
- info.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
+ appCompatTaskInfo.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 12392a6..f148176 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.TaskInfo.cameraCompatControlStateToString;
+import static android.app.AppCompatTaskInfo.cameraCompatControlStateToString;
import static android.window.StartingWindowRemovalInfo.DEFER_MODE_NONE;
import static android.window.StartingWindowRemovalInfo.DEFER_MODE_NORMAL;
import static android.window.StartingWindowRemovalInfo.DEFER_MODE_ROTATION;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 93dc219..34d6755 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2008,6 +2008,10 @@
DeviceManagementResourcesProvider getDeviceManagementResourcesProvider() {
return new DeviceManagementResourcesProvider();
}
+
+ boolean isAdminInstalledCaCertAutoApproved() {
+ return false;
+ }
}
/**
@@ -6158,6 +6162,18 @@
.setAdmin(caller.getPackageName())
.setBoolean(/* isDelegate */ admin == null)
.write();
+
+ if (mInjector.isAdminInstalledCaCertAutoApproved()
+ && installedAlias != null
+ && admin != null) {
+ // If device admin called this, approve cert to avoid notifications
+ Slogf.i(LOG_TAG, "Approving admin installed cert");
+ approveCaCert(
+ installedAlias,
+ caller.getUserId(),
+ /* approved */ true);
+ }
+
return installedAlias;
});
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 c7b1abf..3035258 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -2440,7 +2440,7 @@
callback.waitForExpectedEvent();
callback.clear();
- callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
+ callback.expectsEvent(EVENT_DISPLAY_ADDED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 367e14b..1c8e949 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -2008,6 +2008,33 @@
}
@Test
+ public void testReplacePending_sameProcess_diffReceivers() throws Exception {
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+ final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
+ final BroadcastFilter receiverGreenA = makeRegisteredReceiver(receiverGreenApp);
+ final BroadcastFilter receiverGreenB = makeRegisteredReceiver(receiverGreenApp);
+
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
+ .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
+ withPriority(receiverGreenA, 5))));
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
+ withPriority(receiverGreenB, 10),
+ withPriority(receiverGreenA, 5))));
+
+ waitForIdle();
+ if (mImpl == Impl.DEFAULT) {
+ verifyScheduleRegisteredReceiver(times(2), receiverGreenApp, airplane);
+ } else {
+ // In the modern queue, we don't end up replacing the old broadcast to
+ // avoid creating priority inversion and so the process will receive
+ // both the old and new broadcasts.
+ verifyScheduleRegisteredReceiver(times(3), receiverGreenApp, airplane);
+ }
+ }
+
+ @Test
public void testIdleAndBarrier() throws Exception {
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java
index 09935f2..0a56c45 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/idle/DeviceIdlenessTrackerTest.java
@@ -163,6 +163,77 @@
}
@Test
+ public void testAlarmSkippedIfAlreadyIdle() {
+ setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, MINUTE_IN_MILLIS);
+ setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 5 * MINUTE_IN_MILLIS);
+ setBatteryState(false, false);
+
+ Intent dockIdleIntent = new Intent(Intent.ACTION_DOCK_IDLE);
+ mBroadcastReceiver.onReceive(mContext, dockIdleIntent);
+
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ long expectedAlarmElapsed = nowElapsed + MINUTE_IN_MILLIS;
+
+ ArgumentCaptor<AlarmManager.OnAlarmListener> onAlarmListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+
+ InOrder inOrder = inOrder(mAlarmManager);
+ inOrder.verify(mAlarmManager)
+ .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(),
+ eq(AppSchedulingModuleThread.getExecutor()),
+ onAlarmListenerCaptor.capture());
+
+ AlarmManager.OnAlarmListener onAlarmListener = onAlarmListenerCaptor.getValue();
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+
+ onAlarmListener.onAlarm();
+
+ // Now in idle.
+
+ // Trigger SCREEN_OFF. Make sure alarm isn't set again.
+ Intent screenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
+ mBroadcastReceiver.onReceive(mContext, screenOffIntent);
+
+ inOrder.verify(mAlarmManager, never())
+ .setWindow(anyInt(), anyLong(), anyLong(), anyString(),
+ eq(AppSchedulingModuleThread.getExecutor()), any());
+ }
+
+ @Test
+ public void testAlarmSkippedIfNoThresholdChange() {
+ setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS);
+ setBatteryState(false, false);
+
+ Intent screenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
+ mBroadcastReceiver.onReceive(mContext, screenOffIntent);
+
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ long expectedAlarmElapsed = nowElapsed + 10 * MINUTE_IN_MILLIS;
+
+ InOrder inOrder = inOrder(mAlarmManager);
+ inOrder.verify(mAlarmManager)
+ .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(),
+ eq(AppSchedulingModuleThread.getExecutor()), any());
+
+ // Advanced the clock a little to make sure the tracker continues to use the original time.
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+
+ // Now on stable power. Thresholds are the same, so alarm doesn't need to be rescheduled.
+ setBatteryState(true, true);
+ inOrder.verify(mAlarmManager, never())
+ .setWindow(anyInt(), eq(expectedAlarmElapsed), anyLong(), anyString(),
+ eq(AppSchedulingModuleThread.getExecutor()), any());
+
+ // Not on stable power. Thresholds are the same, so alarm doesn't need to be rescheduled.
+ setBatteryState(false, false);
+ inOrder.verify(mAlarmManager, never())
+ .setWindow(anyInt(), anyLong(), anyLong(), anyString(),
+ eq(AppSchedulingModuleThread.getExecutor()), any());
+ }
+
+ @Test
public void testThresholdChangeWithStablePowerChange() {
setDeviceConfigLong(KEY_INACTIVITY_IDLE_THRESHOLD_MS, 10 * MINUTE_IN_MILLIS);
setDeviceConfigLong(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, 5 * MINUTE_IN_MILLIS);
diff --git a/services/tests/powerservicetests/Android.bp b/services/tests/powerservicetests/Android.bp
index 7351fc5f..8d455fe 100644
--- a/services/tests/powerservicetests/Android.bp
+++ b/services/tests/powerservicetests/Android.bp
@@ -11,6 +11,7 @@
],
static_libs: [
+ "flag-junit",
"frameworks-base-testutils",
"platform-compat-test-rules",
"platform-test-annotations",
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 8e1d8ab..d752ae4 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -26,6 +26,8 @@
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+import static com.android.server.deviceidle.Flags.FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -82,6 +84,7 @@
import android.os.PowerSaveState;
import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
@@ -175,6 +178,8 @@
@Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ @Rule public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private PowerManagerService mService;
private ContextWrapper mContextSpy;
private BatteryReceiver mBatteryReceiver;
@@ -2567,6 +2572,58 @@
}
@Test
+ public void testDisableWakelocksInLightDeviceIdle_FlagDisabled_BgApp() {
+ mSetFlagsRule.disableFlags(FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE);
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_RECEIVER);
+ mService.setDeviceIdleModeInternal(false);
+ mService.setLightDeviceIdleModeInternal(true);
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testDisableWakelocksInLightDeviceIdle_FlagDisabled_FgApp() {
+ mSetFlagsRule.disableFlags(FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE);
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_FOREGROUND_SERVICE);
+ mService.setDeviceIdleModeInternal(false);
+ mService.setLightDeviceIdleModeInternal(true);
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testDisableWakelocksInLightDeviceIdle_FlagEnabled_BgApp() {
+ mSetFlagsRule.enableFlags(FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE);
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_RECEIVER);
+ mService.setDeviceIdleModeInternal(false);
+ mService.setLightDeviceIdleModeInternal(true);
+
+ assertThat(wakeLock.mDisabled).isTrue();
+ }
+
+ @Test
+ public void testDisableWakelocksInLightDeviceIdle_FlagEnabled_FgApp() {
+ mSetFlagsRule.enableFlags(FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE);
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_FOREGROUND_SERVICE);
+ mService.setDeviceIdleModeInternal(false);
+ mService.setLightDeviceIdleModeInternal(true);
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
public void testLowPowerStandby_whenInactive_FgsWakeLockEnabled() {
createService();
startSystem();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index c88d6e4..612a091 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -29,6 +29,9 @@
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.TestableContext;
import android.util.DebugUtils;
import android.view.InputDevice;
@@ -40,6 +43,7 @@
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.Flags;
import com.android.server.accessibility.utils.TouchEventGenerator;
import org.junit.After;
@@ -59,20 +63,29 @@
@RunWith(AndroidJUnit4.class)
public class WindowMagnificationGestureHandlerTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
public static final int STATE_IDLE = 1;
public static final int STATE_SHOW_MAGNIFIER_SHORTCUT = 2;
public static final int STATE_TWO_FINGERS_DOWN = 3;
public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4;
public static final int STATE_NOT_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD = 5;
public static final int STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD = 6;
+ public static final int STATE_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP = 7;
+ public static final int STATE_NOT_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD = 8;
+ public static final int STATE_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD = 9;
//TODO: Test it after can injecting Handler to GestureMatcher is available.
public static final int FIRST_STATE = STATE_IDLE;
public static final int LAST_STATE = STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD;
+ public static final int LAST_STATE_WITH_MULTI_FINGER =
+ STATE_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD;
// Co-prime x and y, to potentially catch x-y-swapped errors
public static final float DEFAULT_TAP_X = 301;
public static final float DEFAULT_TAP_Y = 299;
+ public static final PointF DEFAULT_POINT = new PointF(DEFAULT_TAP_X, DEFAULT_TAP_Y);
private static final int DISPLAY_0 = MockWindowMagnificationConnection.TEST_DISPLAY;
@Rule
@@ -141,7 +154,22 @@
throw new AssertionError("Failed while testing state " + stateToString(state),
e);
}
- });
+ }, LAST_STATE);
+ }
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ public void testEachState_enabledMultiFinger_isReachableAndRecoverable() {
+ forEachState(state -> {
+ goFromStateIdleTo(state);
+ assertIn(state);
+ returnToNormalFrom(state);
+ try {
+ assertIn(STATE_IDLE);
+ } catch (AssertionError e) {
+ throw new AssertionError("Failed while testing state " + stateToString(state),
+ e);
+ }
+ }, LAST_STATE_WITH_MULTI_FINGER);
}
@Test
@@ -159,8 +187,29 @@
returnToNormalFrom(state1);
}
}
- });
- });
+ }, LAST_STATE);
+ }, LAST_STATE);
+ }
+
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ public void testStates_enabledMultiFinger_areMutuallyExclusive() {
+ forEachState(state1 -> {
+ forEachState(state2 -> {
+ if (state1 < state2) {
+ goFromStateIdleTo(state1);
+ try {
+ assertIn(state2);
+ fail("State " + stateToString(state1) + " also implies state "
+ + stateToString(state2) + stateDump());
+ } catch (AssertionError e) {
+ // expected
+ returnToNormalFrom(state1);
+ }
+ }
+ }, LAST_STATE_WITH_MULTI_FINGER);
+ }, LAST_STATE_WITH_MULTI_FINGER);
}
@Test
@@ -187,8 +236,8 @@
returnToNormalFrom(STATE_SHOW_MAGNIFIER_TRIPLE_TAP);
}
- private void forEachState(IntConsumer action) {
- for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
+ private void forEachState(IntConsumer action, int lastState) {
+ for (int state = FIRST_STATE; state <= lastState; state++) {
action.accept(state);
}
}
@@ -207,14 +256,16 @@
}
break;
case STATE_SHOW_MAGNIFIER_SHORTCUT:
- case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
+ case STATE_SHOW_MAGNIFIER_TRIPLE_TAP:
+ case STATE_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP:
check(isWindowMagnifierEnabled(DISPLAY_0), state);
check(mWindowMagnificationGestureHandler.mCurrentState
== mWindowMagnificationGestureHandler.mDetectingState, state);
- }
break;
case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD:
- case STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+ case STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD:
+ case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD:
+ case STATE_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD: {
check(isWindowMagnifierEnabled(DISPLAY_0), state);
check(mWindowMagnificationGestureHandler.mCurrentState
== mWindowMagnificationGestureHandler.mViewportDraggingState, state);
@@ -286,6 +337,29 @@
tapAndHold();
}
break;
+ case STATE_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP: {
+ twoFingerTap();
+ twoFingerTap();
+ twoFingerTap();
+ // Wait for two-finger tap gesture completed.
+ SystemClock.sleep(ViewConfiguration.getDoubleTapMinTime() + 500);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ break;
+ case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD: {
+ twoFingerTap();
+ twoFingerTap();
+ twoFingerTapAndHold();
+ }
+ break;
+ case STATE_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD: {
+ // enabled then perform two finger triple tap and hold gesture
+ goFromStateIdleTo(STATE_SHOW_MAGNIFIER_SHORTCUT);
+ twoFingerTap();
+ twoFingerTap();
+ twoFingerTapAndHold();
+ }
+ break;
default:
throw new IllegalArgumentException("Illegal state: " + state);
}
@@ -319,13 +393,22 @@
tap();
}
break;
- case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+ case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD:
+ case STATE_NOT_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD:
send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
- }
- break;
- case STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
+ break;
+ case STATE_ENABLED_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD:
+ case STATE_ENABLED_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP_AND_HOLD:
send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
returnToNormalFrom(STATE_SHOW_MAGNIFIER_SHORTCUT);
+ break;
+ case STATE_SHOW_MAGNIFIER_TWO_FINGER_TRIPLE_TAP: {
+ twoFingerTap();
+ twoFingerTap();
+ twoFingerTap();
+ // Wait for two-finger tap gesture completed.
+ SystemClock.sleep(ViewConfiguration.getDoubleTapMinTime() + 500);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
break;
default:
@@ -365,6 +448,16 @@
return TouchEventGenerator.downEvent(DISPLAY_0, x, y);
}
+ private MotionEvent pointerDownEvent(float x, float y) {
+ return TouchEventGenerator.pointerDownEvent(DISPLAY_0,
+ new PointF[] {DEFAULT_POINT, new PointF(x, y)});
+ }
+
+ private MotionEvent pointerUpEvent(float x, float y) {
+ return TouchEventGenerator.pointerUpEvent(DISPLAY_0,
+ new PointF[] {DEFAULT_POINT, new PointF(x, y)});
+ }
+
private MotionEvent upEvent(float x, float y) {
return TouchEventGenerator.upEvent(DISPLAY_0, x, y);
}
@@ -379,6 +472,19 @@
SystemClock.sleep(ViewConfiguration.getLongPressTimeout() + 100);
}
+ private void twoFingerTap() {
+ send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+ send(pointerDownEvent(DEFAULT_TAP_X * 2, DEFAULT_TAP_Y));
+ send(pointerUpEvent(DEFAULT_TAP_X * 2, DEFAULT_TAP_Y));
+ send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+ }
+
+ private void twoFingerTapAndHold() {
+ send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
+ send(pointerDownEvent(DEFAULT_TAP_X * 2, DEFAULT_TAP_Y));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout() + 100);
+ }
+
private String stateDump() {
return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index fbcde53..fcd16a0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -39,10 +39,36 @@
return generateSingleTouchEvent(displayId, ACTION_DOWN, x, y);
}
+ /**
+ * Create a test {@link MotionEvent#ACTION_POINTER_DOWN}, filling in all the basic values that
+ * define the motion.
+ *
+ * @param displayId The id of the display
+ * @param pointFs location on the screen of the all pointers
+ */
+ public static MotionEvent pointerDownEvent(int displayId, PointF[] pointFs) {
+ final int actionIndex = 1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int action = ACTION_POINTER_DOWN | actionIndex;
+ return generateMultiplePointersEvent(displayId, action, pointFs);
+ }
+
public static MotionEvent moveEvent(int displayId, float x, float y) {
return generateSingleTouchEvent(displayId, ACTION_MOVE, x, y);
}
+ /**
+ * Create a test {@link MotionEvent#ACTION_POINTER_UP}, filling in all the basic values that
+ * define the motion.
+ *
+ * @param displayId the id of the display
+ * @param pointFs location on the screen of the all pointers
+ */
+ public static MotionEvent pointerUpEvent(int displayId, PointF[] pointFs) {
+ final int actionIndex = 1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int action = ACTION_POINTER_UP | actionIndex;
+ return generateMultiplePointersEvent(displayId, action, pointFs);
+ }
+
public static MotionEvent upEvent(int displayId, float x, float y) {
return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
index 4e9ac7c..d4d3128 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
@@ -16,6 +16,8 @@
package com.android.server.audio;
+import static com.android.media.audio.Flags.FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME;
+
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -28,13 +30,22 @@
import android.media.AudioSystem;
import android.media.VolumeInfo;
import android.os.test.TestLooper;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
public class AudioDeviceVolumeManagerTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
private static final String TAG = "AudioDeviceVolumeManagerTest";
private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
@@ -96,4 +107,91 @@
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
AudioManager.STREAM_MUSIC, midIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
}
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
+ public void testConfigurablePreScaleAbsoluteVolume() throws Exception {
+ AudioManager am = mContext.getSystemService(AudioManager.class);
+ final int minIndex = am.getStreamMinVolume(AudioManager.STREAM_MUSIC);
+ final int maxIndex = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ final VolumeInfo volMedia = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+ .setMinVolumeIndex(minIndex)
+ .setMaxVolumeIndex(maxIndex)
+ .build();
+ final AudioDeviceAttributes bleDevice = new AudioDeviceAttributes(
+ /*native type*/ AudioSystem.DEVICE_OUT_BLE_HEADSET, /*address*/ "fake_ble");
+ final int maxPreScaleIndex = 3;
+ final float[] preScale = new float[3];
+ preScale[0] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+ 1, 1);
+ preScale[1] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+ 1, 1);
+ preScale[2] = mContext.getResources().getFraction(
+ com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+ 1, 1);
+
+ for (int i = 0; i < maxPreScaleIndex; i++) {
+ final int targetIndex = (int) (preScale[i] * maxIndex);
+ final VolumeInfo volCur = new VolumeInfo.Builder(volMedia)
+ .setVolumeIndex(i + 1).build();
+ // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:1~3)
+ mAudioService.setDeviceVolume(volCur, bleDevice, mPackageName);
+ mTestLooper.dispatchAll();
+
+ // Stream volume changes
+ verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+ AudioManager.STREAM_MUSIC, targetIndex,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
+ final VolumeInfo volIndex4 = new VolumeInfo.Builder(volMedia)
+ .setVolumeIndex(4).build();
+ mAudioService.setDeviceVolume(volIndex4, bleDevice, mPackageName);
+ mTestLooper.dispatchAll();
+
+ verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+ AudioManager.STREAM_MUSIC, maxIndex,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
+ public void testDisablePreScaleAbsoluteVolume() throws Exception {
+ AudioManager am = mContext.getSystemService(AudioManager.class);
+ final int minIndex = am.getStreamMinVolume(AudioManager.STREAM_MUSIC);
+ final int maxIndex = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ final VolumeInfo volMedia = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+ .setMinVolumeIndex(minIndex)
+ .setMaxVolumeIndex(maxIndex)
+ .build();
+ final AudioDeviceAttributes bleDevice = new AudioDeviceAttributes(
+ /*native type*/ AudioSystem.DEVICE_OUT_BLE_HEADSET, /*address*/ "bla");
+ final int maxPreScaleIndex = 3;
+
+ for (int i = 0; i < maxPreScaleIndex; i++) {
+ final VolumeInfo volCur = new VolumeInfo.Builder(volMedia)
+ .setVolumeIndex(i + 1).build();
+ // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:1~3)
+ mAudioService.setDeviceVolume(volCur, bleDevice, mPackageName);
+ mTestLooper.dispatchAll();
+
+ // Stream volume changes
+ verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+ AudioManager.STREAM_MUSIC, maxIndex,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
+ final VolumeInfo volIndex4 = new VolumeInfo.Builder(volMedia)
+ .setVolumeIndex(4).build();
+ mAudioService.setDeviceVolume(volIndex4, bleDevice, mPackageName);
+ mTestLooper.dispatchAll();
+
+ verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+ AudioManager.STREAM_MUSIC, maxIndex,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index ad09ef0..061b8ff 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -79,7 +79,7 @@
final AudioDeviceAttributes dev3 =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "R2:D2:bloop");
- doNothing().when(mSpyDeviceBroker).persistAudioDeviceSettings();
+ doNothing().when(mSpyDeviceBroker).postPersistAudioDeviceSettings();
mSpatHelper.initForTest(true /*binaural*/, true /*transaural*/);
// test with single device
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 6d13d87..b445226 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -16,8 +16,6 @@
package com.android.server.contentcapture;
-import static android.view.contentprotection.flags.Flags.FLAG_PARSE_GROUPS_CONFIG_ENABLED;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -548,48 +546,21 @@
}
@Test
- public void parseContentProtectionGroupsConfig_disabled_null() {
- mSetFlagsRule.disableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_null() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig(null)).isEmpty();
}
@Test
- public void parseContentProtectionGroupsConfig_disabled_empty() {
- mSetFlagsRule.disableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_empty() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig("")).isEmpty();
}
@Test
- public void parseContentProtectionGroupsConfig_disabled_notEmpty() {
- mSetFlagsRule.disableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
- ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
-
- assertThat(service.parseContentProtectionGroupsConfig("a")).isEmpty();
- }
-
- @Test
- public void parseContentProtectionGroupsConfig_enabled_null() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
- ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
-
- assertThat(service.parseContentProtectionGroupsConfig(null)).isEmpty();
- }
-
- @Test
- public void parseContentProtectionGroupsConfig_enabled_empty() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
- ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
-
- assertThat(service.parseContentProtectionGroupsConfig("")).isEmpty();
- }
-
- @Test
- public void parseContentProtectionGroupsConfig_enabled_singleValue() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_singleValue() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig("a"))
@@ -597,8 +568,7 @@
}
@Test
- public void parseContentProtectionGroupsConfig_enabled_multipleValues() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_multipleValues() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig("a,b"))
@@ -606,8 +576,7 @@
}
@Test
- public void parseContentProtectionGroupsConfig_enabled_multipleGroups() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_multipleGroups() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig("a,b;c;d,e"))
@@ -615,8 +584,7 @@
}
@Test
- public void parseContentProtectionGroupsConfig_enabled_emptyValues() {
- mSetFlagsRule.enableFlags(FLAG_PARSE_GROUPS_CONFIG_ENABLED);
+ public void parseContentProtectionGroupsConfig_emptyValues() {
ContentCaptureManagerService service = new ContentCaptureManagerService(sContext);
assertThat(service.parseContentProtectionGroupsConfig("a;b;;;c;,d,,e,;,;"))
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
index a28647e..195ab68 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
@@ -16,8 +16,6 @@
package com.android.server.contentprotection;
-import static android.view.contentprotection.flags.Flags.FLAG_BLOCKLIST_UPDATE_ENABLED;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
@@ -107,9 +105,7 @@
}
@Test
- public void start_updateEnabled_firstTime_beforeDelay() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
-
+ public void start_firstTime_beforeDelay() {
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.dispatchAll();
@@ -121,9 +117,7 @@
}
@Test
- public void start_updateEnabled_firstTime_afterDelay() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
-
+ public void start_firstTime_afterDelay() {
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.moveTimeForward(DELAY_MS);
mTestLooper.dispatchNext();
@@ -137,8 +131,7 @@
}
@Test
- public void start_updateEnabled_secondTime() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void start_secondTime() {
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.moveTimeForward(DELAY_MS);
mTestLooper.dispatchNext();
@@ -154,55 +147,7 @@
}
@Test
- public void start_updateDisabled_firstTime_beforeDelay() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
-
- mContentProtectionAllowlistManager.start(DELAY_MS);
- mTestLooper.dispatchAll();
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verifyZeroInteractions(mMockPackageMonitor);
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void start_updateDisabled_firstTime_afterDelay() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
-
- mContentProtectionAllowlistManager.start(DELAY_MS);
- mTestLooper.moveTimeForward(DELAY_MS);
- mTestLooper.dispatchNext();
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
- verify(mMockPackageMonitor, never()).unregister();
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void start_updateDisabled_secondTime() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
- mContentProtectionAllowlistManager.start(DELAY_MS);
- mTestLooper.moveTimeForward(DELAY_MS);
- mTestLooper.dispatchNext();
-
- mContentProtectionAllowlistManager.start(DELAY_MS);
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
- verify(mMockPackageMonitor, never()).unregister();
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void stop_updateEnabled_notStarted() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void stop_notStarted() {
doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
mContentProtectionAllowlistManager.stop();
@@ -216,8 +161,7 @@
}
@Test
- public void stop_updateEnabled_started_beforeDelay() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void stop_started_beforeDelay() {
doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.dispatchAll();
@@ -233,8 +177,7 @@
}
@Test
- public void stop_updateEnabled_started_afterDelay() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void stop_started_afterDelay() {
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.moveTimeForward(DELAY_MS);
mTestLooper.dispatchNext();
@@ -250,55 +193,6 @@
}
@Test
- public void stop_updateDisabled_notStarted() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
- doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
-
- mContentProtectionAllowlistManager.stop();
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verify(mMockPackageMonitor, never()).register(any(), any(), any());
- verify(mMockPackageMonitor).unregister();
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void stop_updateDisabled_started_beforeDelay() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
- doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
- mContentProtectionAllowlistManager.start(DELAY_MS);
- mTestLooper.dispatchAll();
-
- mContentProtectionAllowlistManager.stop();
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verify(mMockPackageMonitor, never()).register(any(), any(), any());
- verify(mMockPackageMonitor).unregister();
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void stop_updateDisabled_started_afterDelay() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
- mContentProtectionAllowlistManager.start(DELAY_MS);
- mTestLooper.moveTimeForward(DELAY_MS);
- mTestLooper.dispatchNext();
-
- mContentProtectionAllowlistManager.stop();
-
- assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
- verify(mMockPackageMonitor).unregister();
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
public void start_afterStop_beforeDelay() {
mContentProtectionAllowlistManager.start(DELAY_MS);
mTestLooper.dispatchAll();
@@ -375,21 +269,7 @@
}
@Test
- public void handlePackagesChanged_updateDisabled() {
- mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
- mUseMockPackageMonitor = false;
- ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
-
- manager.mPackageMonitor.onSomePackagesChanged();
-
- verifyZeroInteractions(mMockContentCaptureManagerService);
- verifyZeroInteractions(mMockRemoteContentProtectionService);
- verifyZeroInteractions(mMockAllowlistCallback);
- }
-
- @Test
- public void handlePackagesChanged_updateEnabled_noService() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void handlePackagesChanged_noService() {
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
@@ -401,8 +281,7 @@
}
@Test
- public void handlePackagesChanged_updateEnabled_withService() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void handlePackagesChanged_withService() {
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
@@ -416,8 +295,7 @@
}
@Test
- public void handlePackagesChanged_updateEnabled_withServiceException() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ public void handlePackagesChanged_withServiceException() {
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
@@ -436,7 +314,6 @@
@Test
public void handlePackagesChanged_rateLimit_noService() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
@@ -450,7 +327,6 @@
@Test
public void handlePackagesChanged_rateLimit_beforeTimeout() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
@@ -467,7 +343,6 @@
@Test
public void handlePackagesChanged_rateLimit_afterTimeout() {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
mUseMockPackageMonitor = false;
ContentProtectionAllowlistManager manager =
new TestContentProtectionAllowlistManager(/* timeoutMs= */ 0L);
@@ -485,7 +360,6 @@
@Test
public void handlePackagesChanged_rateLimit_afterUpdate() throws Exception {
- mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
mUseMockPackageMonitor = false;
mUseMockAllowlistCallback = false;
ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
index e7c3cab..a63d01b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
@@ -528,9 +528,15 @@
clearInvocations(mAudioManager);
// Repeat of earlier message: sets neither volume nor mute
+ // Exception: On TV, volume is set to ensure that UI is shown
receiveReportAudioStatus(32, false);
- verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
- anyInt());
+ if (getDeviceType() == HdmiDeviceInfo.DEVICE_TV) {
+ verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
+ anyInt());
+ } else {
+ verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
+ anyInt());
+ }
verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
eq(AudioManager.ADJUST_UNMUTE), anyInt());
clearInvocations(mAudioManager);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
index cb530c0..a410702 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
@@ -190,12 +190,13 @@
eq(AudioManager.ADJUST_UNMUTE), anyInt());
clearInvocations(mAudioManager);
- // Repeat of earlier message: sets neither volume nor mute
+ // Repeat of earlier message: sets volume only (to ensure volume UI is shown)
receiveReportAudioStatus(32, false);
- verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
+ verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
anyInt());
verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
eq(AudioManager.ADJUST_UNMUTE), anyInt());
+ clearInvocations(mAudioManager);
// Volume not within range [0, 100]: sets neither volume nor mute
receiveReportAudioStatus(127, true);
@@ -391,14 +392,16 @@
INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()));
mTestLooper.dispatchAll();
- // HdmiControlService calls setStreamVolume and adjustStreamVolume to trigger volume UI
+ // HdmiControlService calls setStreamVolume to trigger volume UI
verify(mAudioManager).setStreamVolume(
eq(AudioManager.STREAM_MUSIC),
// Volume level is rescaled to the max volume of STREAM_MUSIC
eq(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume()
* STREAM_MUSIC_MAX_VOLUME / AudioStatus.MAX_VOLUME),
eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
- verify(mAudioManager).adjustStreamVolume(
+ // adjustStreamVolume is not called because mute status didn't change,
+ // and setStreamVolume is sufficient to show volume UI
+ verify(mAudioManager, never()).adjustStreamVolume(
eq(AudioManager.STREAM_MUSIC),
eq(AudioManager.ADJUST_UNMUTE),
eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 8a0a764..db46532 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -27,10 +27,14 @@
import static android.app.UiModeManager.PROJECTION_TYPE_ALL;
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
+
import static com.android.server.UiModeManagerService.SUPPORTED_NIGHT_MODE_CUSTOM_TYPES;
+
import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
+
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
@@ -81,6 +85,7 @@
import android.os.UserHandle;
import android.os.test.FakePermissionEnforcer;
import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
import android.test.mock.MockContentResolver;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -131,6 +136,9 @@
private TwilightState mTwilightState;
@Mock
PowerManagerInternal mLocalPowerManager;
+
+ @Mock
+ DreamManagerInternal mDreamManagerInternal;
@Mock
private PackageManager mPackageManager;
@Mock
@@ -143,6 +151,7 @@
private ArgumentCaptor<BroadcastReceiver> mOrderedBroadcastReceiver;
private BroadcastReceiver mScreenOffCallback;
+ private BroadcastReceiver mDreamingStartedCallback;
private BroadcastReceiver mTimeChangedCallback;
private BroadcastReceiver mDockStateChangedCallback;
private AlarmManager.OnAlarmListener mCustomListener;
@@ -187,6 +196,9 @@
if (filter.hasAction(Intent.ACTION_SCREEN_OFF)) {
mScreenOffCallback = inv.getArgument(0);
}
+ if (filter.hasAction(Intent.ACTION_DREAMING_STARTED)) {
+ mDreamingStartedCallback = inv.getArgument(0);
+ }
if (filter.hasAction(Intent.ACTION_DOCK_EVENT)) {
mDockStateChangedCallback = inv.getArgument(0);
}
@@ -210,6 +222,7 @@
addLocalService(WindowManagerInternal.class, mWindowManager);
addLocalService(PowerManagerInternal.class, mLocalPowerManager);
addLocalService(TwilightManager.class, mTwilightManager);
+ addLocalService(DreamManagerInternal.class, mDreamManagerInternal);
mInjector = spy(new TestInjector());
mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
@@ -281,7 +294,7 @@
}
@Test
- public void setAutoMode_screenOffRegistered() throws RemoteException {
+ public void setAutoMode_deviceInactiveRegistered() throws RemoteException {
try {
mService.setNightMode(MODE_NIGHT_NO);
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
@@ -291,7 +304,7 @@
@Ignore // b/152719290 - Fails on stage-aosp-master
@Test
- public void setAutoMode_screenOffUnRegistered() throws RemoteException {
+ public void setAutoMode_deviceInactiveUnRegistered() throws RemoteException {
try {
mService.setNightMode(MODE_NIGHT_AUTO);
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
@@ -776,7 +789,7 @@
}
@Test
- public void customTime_darkThemeOn() throws RemoteException {
+ public void customTime_darkThemeOn_afterScreenOff() throws RemoteException {
LocalTime now = LocalTime.now();
mService.setNightMode(MODE_NIGHT_NO);
mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
@@ -787,7 +800,7 @@
}
@Test
- public void customTime_darkThemeOff() throws RemoteException {
+ public void customTime_darkThemeOff_afterScreenOff() throws RemoteException {
LocalTime now = LocalTime.now();
mService.setNightMode(MODE_NIGHT_YES);
mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
@@ -798,6 +811,28 @@
}
@Test
+ public void customTime_darkThemeOn_afterDreamingStarted() throws RemoteException {
+ LocalTime now = LocalTime.now();
+ mService.setNightMode(MODE_NIGHT_NO);
+ mService.setCustomNightModeStart(now.minusHours(1L).toNanoOfDay() / 1000);
+ mService.setCustomNightModeEnd(now.plusHours(1L).toNanoOfDay() / 1000);
+ mService.setNightMode(MODE_NIGHT_CUSTOM);
+ mDreamingStartedCallback.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STARTED));
+ assertTrue(isNightModeActivated());
+ }
+
+ @Test
+ public void customTime_darkThemeOff_afterDreamingStarted() throws RemoteException {
+ LocalTime now = LocalTime.now();
+ mService.setNightMode(MODE_NIGHT_YES);
+ mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
+ mService.setCustomNightModeEnd(now.minusHours(1L).toNanoOfDay() / 1000);
+ mService.setNightMode(MODE_NIGHT_CUSTOM);
+ mDreamingStartedCallback.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STARTED));
+ assertFalse(isNightModeActivated());
+ }
+
+ @Test
public void customTime_darkThemeOff_afterStartEnd() throws RemoteException {
LocalTime now = LocalTime.now();
mService.setNightMode(MODE_NIGHT_YES);
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 17367ef..0c996e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -18,10 +18,10 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
+import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 7b1fa03..6790dc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.window.BackNavigationInfo.typeToString;
@@ -227,6 +228,20 @@
}
@Test
+ public void backTypeDialogCloseWhenBackFromDialog() {
+ DialogCloseTestCase testCase = createTopTaskWithActivityAndDialog();
+ IOnBackInvokedCallback callback = withSystemCallback(testCase.task);
+
+ BackNavigationInfo backNavigationInfo = startBackNavigation();
+ assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
+ assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_DIALOG_CLOSE));
+ // verify if back animation would start.
+ assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
+ }
+
+ @Test
public void backInfoWithNullWindow() {
BackNavigationInfo backNavigationInfo = startBackNavigation();
assertThat(backNavigationInfo).isNull();
@@ -605,8 +620,14 @@
final ArrayList<ActivityRecord> openActivities = new ArrayList<>();
openActivities.add(homeActivity);
final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toHomeBuilder =
- animationHandler.prepareAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME,
- mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, openActivities);
+ animationHandler.prepareAnimation(
+ BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ mBackAnimationAdapter,
+ task,
+ mRootHomeTask,
+ bottomActivity,
+ openActivities,
+ task);
assertTrue(toHomeBuilder.mIsLaunchBehind);
toHomeBuilder.build();
verify(mAtm.mTaskOrganizerController, never()).addWindowlessStartingSurface(
@@ -619,8 +640,13 @@
openActivities.add(bottomActivity);
final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toActivityBuilder =
animationHandler.prepareAnimation(
- BackNavigationInfo.TYPE_CROSS_ACTIVITY, mBackAnimationAdapter, task, task,
- topActivity, openActivities);
+ BackNavigationInfo.TYPE_CROSS_ACTIVITY,
+ mBackAnimationAdapter,
+ task,
+ task,
+ topActivity,
+ openActivities,
+ topActivity);
assertFalse(toActivityBuilder.mIsLaunchBehind);
toActivityBuilder.build();
if (preferWindowlessSurface) {
@@ -649,6 +675,31 @@
}
@NonNull
+ private DialogCloseTestCase createTopTaskWithActivityAndDialog() {
+ Task task = createTask(mDefaultDisplay);
+ ActivityRecord record = createActivityRecord(task);
+ // enable OnBackInvokedCallbacks
+ record.info.applicationInfo.privateFlagsExt |=
+ PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
+ WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
+ WindowState dialog = createWindow(null, TYPE_APPLICATION, record, "dialog");
+ when(record.mSurfaceControl.isValid()).thenReturn(true);
+ Mockito.doNothing().when(task).reparentSurfaceControl(any(), any());
+ mAtm.setFocusedTask(task.mTaskId, record);
+ addToWindowMap(window, true);
+ addToWindowMap(dialog, true);
+
+ makeWindowVisibleAndDrawn(dialog);
+
+ DialogCloseTestCase testCase = new DialogCloseTestCase();
+ testCase.task = task;
+ testCase.record = record;
+ testCase.windowBack = window;
+ testCase.windowFront = dialog;
+ return testCase;
+ }
+
+ @NonNull
private CrossActivityTestCase createTopTaskWithTwoActivities() {
Task task = createTask(mDefaultDisplay);
ActivityRecord record1 = createActivityRecord(task);
@@ -696,4 +747,11 @@
public ActivityRecord recordFront;
public WindowState windowFront;
}
+
+ private class DialogCloseTestCase {
+ public Task task;
+ public ActivityRecord record;
+ public WindowState windowBack;
+ public WindowState windowFront;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6d67c8b..5b88c8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -970,6 +970,13 @@
assertEquals(
"Screen orientation must be defined by the window even on close-to-square display.",
window.mAttrs.screenOrientation, dc.getOrientation());
+
+ // Assume that a decor window occupies the display height, so the configuration orientation
+ // should be landscape.
+ dc.getDisplayPolicy().getDecorInsetsInfo(ROTATION_0, dc.mBaseDisplayHeight,
+ dc.mBaseDisplayWidth).mConfigFrame.set(0, 0, 1000, 990);
+ dc.computeScreenConfiguration(config, ROTATION_0);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 1ceb1a8..a7c14c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1117,7 +1117,7 @@
verify(mTask).onSizeCompatActivityChanged();
ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo();
- assertTrue(taskInfo.topActivityInSizeCompat);
+ assertTrue(taskInfo.appCompatTaskInfo.topActivityInSizeCompat);
// Make the activity resizable again by restarting it
clearInvocations(mTask);
@@ -1132,7 +1132,7 @@
verify(mTask).onSizeCompatActivityChanged();
taskInfo = mTask.getTaskInfo();
- assertFalse(taskInfo.topActivityInSizeCompat);
+ assertFalse(taskInfo.appCompatTaskInfo.topActivityInSizeCompat);
}
@Test
@@ -1150,7 +1150,7 @@
verify(mTask).onSizeCompatActivityChanged();
ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo();
- assertTrue(taskInfo.topActivityInSizeCompat);
+ assertTrue(taskInfo.appCompatTaskInfo.topActivityInSizeCompat);
// Create another Task to hold another size compat activity.
clearInvocations(mTask);
@@ -1170,7 +1170,7 @@
verify(mTask, never()).onSizeCompatActivityChanged();
taskInfo = secondTask.getTaskInfo();
- assertTrue(taskInfo.topActivityInSizeCompat);
+ assertTrue(taskInfo.appCompatTaskInfo.topActivityInSizeCompat);
}
@Test
@@ -4565,7 +4565,7 @@
assertTrue(mActivity.inSizeCompatMode());
assertEquals(mActivity.getState(), PAUSED);
assertTrue(mActivity.isVisible());
- assertTrue(mTask.getTaskInfo().topActivityInSizeCompat);
+ assertTrue(mTask.getTaskInfo().appCompatTaskInfo.topActivityInSizeCompat);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 435a835..898b751 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -580,18 +580,21 @@
doReturn(task).when(root).getOrganizedTask();
// The button should be eligible to be displayed
- assertTrue(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+ assertTrue(task.getTaskInfo()
+ .appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton);
// When shouldApplyUserMinAspectRatioOverride is disable the button is not enabled
doReturn(false).when(root.mLetterboxUiController)
.shouldEnableUserAspectRatioSettings();
- assertFalse(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+ assertFalse(task.getTaskInfo()
+ .appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton);
doReturn(true).when(root.mLetterboxUiController)
.shouldEnableUserAspectRatioSettings();
// When in size compat mode the button is not enabled
doReturn(true).when(root).inSizeCompatMode();
- assertFalse(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+ assertFalse(task.getTaskInfo()
+ .appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton);
doReturn(false).when(root).inSizeCompatMode();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 2c39173..1494f94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -1598,7 +1598,7 @@
verify(organizer).onTaskInfoChanged(infoCaptor.capture());
RunningTaskInfo info = infoCaptor.getValue();
assertEquals(rootTask.mTaskId, info.taskId);
- assertTrue(info.topActivityInSizeCompat);
+ assertTrue(info.appCompatTaskInfo.topActivityInSizeCompat);
// Ensure task info show top activity that is not visible as not in size compat.
clearInvocations(organizer);
@@ -1608,7 +1608,7 @@
verify(organizer).onTaskInfoChanged(infoCaptor.capture());
info = infoCaptor.getValue();
assertEquals(rootTask.mTaskId, info.taskId);
- assertFalse(info.topActivityInSizeCompat);
+ assertFalse(info.appCompatTaskInfo.topActivityInSizeCompat);
// Ensure task info show non size compat top activity as not in size compat.
clearInvocations(organizer);
@@ -1619,7 +1619,7 @@
verify(organizer).onTaskInfoChanged(infoCaptor.capture());
info = infoCaptor.getValue();
assertEquals(rootTask.mTaskId, info.taskId);
- assertFalse(info.topActivityInSizeCompat);
+ assertFalse(info.appCompatTaskInfo.topActivityInSizeCompat);
}
@Test
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 9f3b52e..1dc5dcf 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -33,6 +33,6 @@
"android.hardware.usb-V1.1-java",
"android.hardware.usb-V1.2-java",
"android.hardware.usb-V1.3-java",
- "android.hardware.usb-V2-java",
+ "android.hardware.usb-V3-java",
],
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 35e2fcf..fb13b33 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -1285,12 +1285,17 @@
pw.println(" dumpsys usb add-port \"matrix\" dual --compliance-warnings");
pw.println(" dumpsys usb set-compliance-reasons \"matrix\" <reason-list>");
pw.println(" dumpsys usb clear-compliance-reasons \"matrix\"");
- pw.println("<reason-list> is expected to be formatted as \"1, ..., 4\"");
+ pw.println("<reason-list> is expected to be formatted as \"1, ..., N\"");
pw.println("with reasons that need to be simulated.");
pw.println(" 1: other");
pw.println(" 2: debug accessory");
pw.println(" 3: bc12");
pw.println(" 4: missing rp");
+ pw.println(" 5: input power limited");
+ pw.println(" 6: missing data lines");
+ pw.println(" 7: enumeration fail");
+ pw.println(" 8: flaky connection");
+ pw.println(" 9: unreliable io");
pw.println();
pw.println("Example simulate DisplayPort Alt Mode Changes:");
pw.println(" dumpsys usb add-port \"matrix\" dual --displayport");
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index c7a7a9b..45b623b 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -39,6 +39,7 @@
import android.hardware.usb.AltModeData;
import android.hardware.usb.AltModeData.DisplayPortAltModeData;
import android.hardware.usb.DisplayPortAltModePinAssignment;
+import android.hardware.usb.flags.Flags;
import android.os.Build;
import android.os.ServiceManager;
import android.os.IBinder;
@@ -593,11 +594,21 @@
for (int warning : complianceWarnings) {
if (newComplianceWarnings.indexOf(warning) == -1
&& warning >= UsbPortStatus.COMPLIANCE_WARNING_OTHER) {
- // ComplianceWarnings range from [1, 4] in Android U
- if (warning > UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP) {
- newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ if (Flags.enableUsbDataComplianceWarning()) {
+ // ComplianceWarnings range extends to [1, 9] when feature flag is on
+ if (warning
+ > UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO) {
+ newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ } else {
+ newComplianceWarnings.add(warning);
+ }
} else {
- newComplianceWarnings.add(warning);
+ // ComplianceWarnings range from [1, 4] in Android U
+ if (warning > UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP) {
+ newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ } else {
+ newComplianceWarnings.add(warning);
+ }
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index f6c6a64..bb6cf52 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -51,6 +51,10 @@
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_SECURITY_EXCEPTION;
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_UNEXPECTED_CALLBACK;
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECT_UNEXPECTED_CALLBACK;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_SECURITY_EXCEPTION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_EGRESS_LIMIT_REACHED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_REMOTE_EXCEPTION;
import static com.android.server.voiceinteraction.HotwordDetectionConnection.ENFORCE_HOTWORD_PHRASE_ID;
import android.annotation.NonNull;
@@ -648,12 +652,21 @@
void sendTrainingData(
TrainingDataEgressCallback callback, HotwordTrainingData data) throws RemoteException {
Slog.d(TAG, "onTrainingData()");
+ int detectorType = getDetectorType();
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ detectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA,
+ mVoiceInteractionServiceUid);
// Check training data permission is granted.
try {
enforcePermissionForTrainingDataDelivery();
} catch (SecurityException e) {
Slog.w(TAG, "Ignoring training data due to a SecurityException", e);
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ detectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_SECURITY_EXCEPTION,
+ mVoiceInteractionServiceUid);
try {
callback.onHotwordDetectionServiceFailure(
new HotwordDetectionServiceFailure(
@@ -662,6 +675,10 @@
+ "in #onTrainingData method."));
} catch (RemoteException e1) {
notifyOnDetectorRemoteException();
+ HotwordMetricsLogger.writeDetectorEvent(
+ detectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION,
+ mVoiceInteractionServiceUid);
throw e1;
}
return;
@@ -672,6 +689,10 @@
.incrementEgressCount();
if (!withinEgressLimit) {
Slog.d(TAG, "Ignoring training data as exceeded egress limit.");
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ detectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_EGRESS_LIMIT_REACHED,
+ mVoiceInteractionServiceUid);
try {
callback.onHotwordDetectionServiceFailure(
new HotwordDetectionServiceFailure(
@@ -679,6 +700,10 @@
"Training data egress limit exceeded."));
} catch (RemoteException e) {
notifyOnDetectorRemoteException();
+ HotwordMetricsLogger.writeDetectorEvent(
+ detectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION,
+ mVoiceInteractionServiceUid);
throw e;
}
return;
@@ -692,6 +717,10 @@
callback.onTrainingData(data);
} catch (RemoteException e) {
notifyOnDetectorRemoteException();
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ detectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__TRAINING_DATA_REMOTE_EXCEPTION,
+ mVoiceInteractionServiceUid);
throw e;
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 216f45a..d722f2f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -279,6 +279,7 @@
mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY
| Context.BIND_SCHEDULE_LIKE_TOP_APP
+ | Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
new UserHandle(mUser));
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index cb7926c..11cbcb1 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -568,7 +568,6 @@
private final int mSkip464Xlat;
private final boolean mAlwaysOn;
private final @InfrastructureBitmask int mInfrastructureBitmask;
- private final boolean mEsimBootstrapProvisioning;
/**
* Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
@@ -980,18 +979,6 @@
return mInfrastructureBitmask;
}
- /**
- * Returns esim bootstrap provisioning flag for which the APN can be used on. For example,
- * some APNs are only allowed to bring up network, when the device esim bootstrap provisioning
- * is being activated.
- *
- * {@code true} if the APN is used for eSIM bootstrap provisioning, {@code false} otherwise.
- * @hide
- */
- public boolean isEsimBootstrapProvisioning() {
- return mEsimBootstrapProvisioning;
- }
-
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
@@ -1029,7 +1016,6 @@
this.mSkip464Xlat = builder.mSkip464Xlat;
this.mAlwaysOn = builder.mAlwaysOn;
this.mInfrastructureBitmask = builder.mInfrastructureBitmask;
- this.mEsimBootstrapProvisioning = builder.mEsimBootstrapProvisioning;
}
/**
@@ -1111,8 +1097,6 @@
.setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
.setInfrastructureBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.INFRASTRUCTURE_BITMASK)))
- .setEsimBootstrapProvisioning(cursor.getInt(
- cursor.getColumnIndexOrThrow(Carriers.ESIM_BOOTSTRAP_PROVISIONING)) == 1)
.buildWithoutCheck();
}
@@ -1153,7 +1137,6 @@
.setSkip464Xlat(apn.mSkip464Xlat)
.setAlwaysOn(apn.mAlwaysOn)
.setInfrastructureBitmask(apn.mInfrastructureBitmask)
- .setEsimBootstrapProvisioning(apn.mEsimBootstrapProvisioning)
.buildWithoutCheck();
}
@@ -1201,7 +1184,6 @@
sb.append(", ").append(mAlwaysOn);
sb.append(", ").append(mInfrastructureBitmask);
sb.append(", ").append(Objects.hash(mUser, mPassword));
- sb.append(", ").append(mEsimBootstrapProvisioning);
return sb.toString();
}
@@ -1265,7 +1247,7 @@
mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
- mAlwaysOn, mInfrastructureBitmask, mEsimBootstrapProvisioning);
+ mAlwaysOn, mInfrastructureBitmask);
}
@Override
@@ -1307,8 +1289,7 @@
&& mCarrierId == other.mCarrierId
&& mSkip464Xlat == other.mSkip464Xlat
&& mAlwaysOn == other.mAlwaysOn
- && mInfrastructureBitmask == other.mInfrastructureBitmask
- && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning);
+ && mInfrastructureBitmask == other.mInfrastructureBitmask;
}
/**
@@ -1359,8 +1340,7 @@
&& Objects.equals(mCarrierId, other.mCarrierId)
&& Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask)
- && Objects.equals(mEsimBootstrapProvisioning, other.mEsimBootstrapProvisioning);
+ && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask);
}
/**
@@ -1398,9 +1378,7 @@
&& Objects.equals(this.mCarrierId, other.mCarrierId)
&& Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
&& Objects.equals(this.mAlwaysOn, other.mAlwaysOn)
- && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask)
- && Objects.equals(this.mEsimBootstrapProvisioning,
- other.mEsimBootstrapProvisioning);
+ && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask);
}
// Equal or one is null.
@@ -1473,7 +1451,6 @@
apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
apnValue.put(Telephony.Carriers.INFRASTRUCTURE_BITMASK, mInfrastructureBitmask);
- apnValue.put(Carriers.ESIM_BOOTSTRAP_PROVISIONING, mEsimBootstrapProvisioning);
return apnValue;
}
@@ -1747,7 +1724,6 @@
dest.writeInt(mSkip464Xlat);
dest.writeBoolean(mAlwaysOn);
dest.writeInt(mInfrastructureBitmask);
- dest.writeBoolean(mEsimBootstrapProvisioning);
}
private static ApnSetting readFromParcel(Parcel in) {
@@ -1784,7 +1760,6 @@
.setSkip464Xlat(in.readInt())
.setAlwaysOn(in.readBoolean())
.setInfrastructureBitmask(in.readInt())
- .setEsimBootstrapProvisioning(in.readBoolean())
.buildWithoutCheck();
}
@@ -1867,7 +1842,6 @@
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
- private boolean mEsimBootstrapProvisioning;
/**
* Default constructor for Builder.
@@ -2306,19 +2280,6 @@
}
/**
- * Sets esim bootstrap provisioning flag
- *
- * @param esimBootstrapProvisioning {@code true} if the APN is used for eSIM bootstrap
- * provisioning, {@code false} otherwise.
- * @hide
- */
- @NonNull
- public Builder setEsimBootstrapProvisioning(boolean esimBootstrapProvisioning) {
- this.mEsimBootstrapProvisioning = esimBootstrapProvisioning;
- return this;
- }
-
- /**
* Builds {@link ApnSetting} from this builder.
*
* @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp
new file mode 100644
index 0000000..9eeec7c
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsOther",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ package_name: "com.android.server.wm.flicker",
+ instrumentation_target_package: "com.android.server.wm.flicker",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
index 6bc7cbe..f867ffb 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flick">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
index ed71531..439cf13 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml
@@ -84,20 +84,6 @@
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
similarity index 63%
rename from tests/FlickerTests/manifests/AndroidManifestOther.xml
rename to tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/ActivityEmbedding/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index adff579..955e801 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -23,9 +23,9 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
similarity index 93%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 47d6d23..790da34 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -36,9 +36,8 @@
/**
* Test launching a secondary Activity into Picture-In-Picture mode.
*
- * Setup: Start from a split A|B.
- * Transition: B enters PIP, observe the window first goes fullscreen then shrink to the bottom
- * right corner on screen.
+ * Setup: Start from a split A|B. Transition: B enters PIP, observe the window first goes fullscreen
+ * then shrink to the bottom right corner on screen.
*
* To run this test: `atest FlickerTestsOther:SecondaryActivityEnterPipTest`
*/
@@ -64,16 +63,10 @@
}
}
- /**
- * We expect the background layer to be visible during this transition.
- */
- @Presubmit
- @Test
- override fun backgroundLayerNeverVisible(): Unit {}
+ /** We expect the background layer to be visible during this transition. */
+ @Presubmit @Test override fun backgroundLayerNeverVisible() {}
- /**
- * Main and secondary activity start from a split each taking half of the screen.
- */
+ /** Main and secondary activity start from a split each taking half of the screen. */
@Presubmit
@Test
fun layersStartFromEqualSplit() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 4f7d8a4..e8389d19 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -23,9 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
-import com.android.server.wm.flicker.rotation.RotationTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
new file mode 100644
index 0000000..1123c5b
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.server.wm.flicker.activityembedding.rotation
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.BaseTest
+import com.android.server.wm.flicker.helpers.setRotation
+import org.junit.Test
+
+/** Base class for app rotation tests */
+abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+ protected abstract val testApp: StandardAppHelper
+
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup { this.setRotation(flicker.scenario.startRotation) }
+ teardown { testApp.exit(wmHelper) }
+ transitions { this.setRotation(flicker.scenario.endRotation) }
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers =
+ listOf(
+ ComponentNameMatcher.SPLASH_SCREEN,
+ ComponentNameMatcher.SNAPSHOT,
+ ComponentNameMatcher("", "SecondaryHomeHandle")
+ )
+ )
+ }
+ }
+
+ /** Checks that [testApp] layer covers the entire screen at the start of the transition */
+ @Presubmit
+ @Test
+ open fun appLayerRotates_StartingPos() {
+ flicker.assertLayersStart {
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ /** Checks that [testApp] layer covers the entire screen at the end of the transition */
+ @Presubmit
+ @Test
+ open fun appLayerRotates_EndingPos() {
+ flicker.assertLayersEnd {
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
+ }
+ }
+ }
+
+ override fun cujCompleted() {
+ super.cujCompleted()
+ appLayerRotates_StartingPos()
+ appLayerRotates_EndingPos()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
similarity index 63%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
rename to tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index 93a5bf5..576eec8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -24,8 +24,8 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.toFlickerComponent
-import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.utils.SplitScreenUtils
@@ -39,11 +39,11 @@
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-/***
+/**
* Test entering System SplitScreen with Activity Embedding Split and another app.
*
- * Setup: Launch A|B in split and secondaryApp, return to home.
- * Transitions: Let AE Split A|B enter splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
+ * Setup: Launch A|B in split and secondaryApp, return to home. Transitions: Let AE Split A|B enter
+ * splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
*
* To run this test: `atest FlickerTestsOther:EnterSystemSplitTest`
*/
@@ -51,8 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSystemSplitTest(flicker: LegacyFlickerTest) :
- ActivityEmbeddingTestBase(flicker) {
+class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBase(flicker) {
private val secondaryApp = SplitScreenUtils.getPrimary(instrumentation)
override val transition: FlickerBuilder.() -> Unit = {
@@ -62,17 +61,22 @@
secondaryApp.launchViaIntent(wmHelper)
tapl.goHome()
wmHelper
- .StateSyncBuilder()
- .withAppTransitionIdle()
- .withHomeActivityVisible()
- .waitForAndVerify()
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
startDisplayBounds =
- wmHelper.currentState.layerState.physicalDisplayBounds
- ?: error("Display not found")
+ wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
}
transitions {
- SplitScreenUtils.enterSplit(wmHelper, tapl, device, testApp, secondaryApp,
- flicker.scenario.startRotation)
+ SplitScreenUtils.enterSplit(
+ wmHelper,
+ tapl,
+ device,
+ testApp,
+ secondaryApp,
+ flicker.scenario.startRotation
+ )
SplitScreenUtils.waitForSplitComplete(wmHelper, testApp, secondaryApp)
}
}
@@ -85,7 +89,10 @@
@Test
fun activityEmbeddingSplitLayerBecomesVisible() {
flicker.splitAppLayerBoundsIsVisibleAtEnd(
- testApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+ testApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false
+ )
}
@Presubmit
@@ -96,7 +103,10 @@
@Test
fun secondaryLayerBecomesVisible() {
flicker.splitAppLayerBoundsIsVisibleAtEnd(
- secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+ secondaryApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true
+ )
}
@Presubmit
@@ -105,73 +115,73 @@
/**
* After the transition there should be both ActivityEmbedding activities,
- * SplitScreenPrimaryActivity and the system split divider on screen.
- * Verify the layers are in expected sizes.
+ * SplitScreenPrimaryActivity and the system split divider on screen. Verify the layers are in
+ * expected sizes.
*/
@Presubmit
@Test
fun activityEmbeddingSplitSurfaceAreEven() {
flicker.assertLayersEnd {
val leftAELayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightAELayerRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
val secondaryAppLayerRegion =
- visibleRegion(
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
val systemDivider = visibleRegion(SPLIT_SCREEN_DIVIDER_COMPONENT)
leftAELayerRegion
- .plus(rightAELayerRegion.region)
- .plus(secondaryAppLayerRegion.region)
- .plus(systemDivider.region)
- .coversExactly(startDisplayBounds)
+ .plus(rightAELayerRegion.region)
+ .plus(secondaryAppLayerRegion.region)
+ .plus(systemDivider.region)
+ .coversExactly(startDisplayBounds)
check { "ActivityEmbeddingSplitHeight" }
- .that(leftAELayerRegion.region.height)
- .isEqual(rightAELayerRegion.region.height)
+ .that(leftAELayerRegion.region.height)
+ .isEqual(rightAELayerRegion.region.height)
check { "SystemSplitHeight" }
- .that(rightAELayerRegion.region.height)
- .isEqual(secondaryAppLayerRegion.region.height)
+ .that(rightAELayerRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
// TODO(b/292283182): Remove this special case handling.
check { "ActivityEmbeddingSplitWidth" }
- .that(Math.abs(
- leftAELayerRegion.region.width - rightAELayerRegion.region.width))
- .isLower(2)
+ .that(Math.abs(leftAELayerRegion.region.width - rightAELayerRegion.region.width))
+ .isLower(2)
check { "SystemSplitWidth" }
- .that(Math.abs(secondaryAppLayerRegion.region.width -
- 2 * rightAELayerRegion.region.width))
- .isLower(2)
+ .that(
+ Math.abs(
+ secondaryAppLayerRegion.region.width - 2 * rightAELayerRegion.region.width
+ )
+ )
+ .isLower(2)
}
}
- /**
- * Verify the windows are in expected sizes.
- */
+ /** Verify the windows are in expected sizes. */
@Presubmit
@Test
fun activityEmbeddingSplitWindowsAreEven() {
flicker.assertWmEnd {
val leftAEWindowRegion =
- visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightAEWindowRegion =
- visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
// There's no window for the divider bar.
val secondaryAppLayerRegion =
- visibleRegion(
- ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+ visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
check { "ActivityEmbeddingSplitHeight" }
- .that(leftAEWindowRegion.region.height)
- .isEqual(rightAEWindowRegion.region.height)
+ .that(leftAEWindowRegion.region.height)
+ .isEqual(rightAEWindowRegion.region.height)
check { "SystemSplitHeight" }
- .that(rightAEWindowRegion.region.height)
- .isEqual(secondaryAppLayerRegion.region.height)
+ .that(rightAEWindowRegion.region.height)
+ .isEqual(secondaryAppLayerRegion.region.height)
check { "ActivityEmbeddingSplitWidth" }
- .that(Math.abs(
- leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
- .isLower(2)
+ .that(Math.abs(leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
+ .isLower(2)
check { "SystemSplitWidth" }
- .that(Math.abs(secondaryAppLayerRegion.region.width -
- 2 * rightAEWindowRegion.region.width))
- .isLower(2)
+ .that(
+ Math.abs(
+ secondaryAppLayerRegion.region.width - 2 * rightAEWindowRegion.region.width
+ )
+ )
+ .isLower(2)
}
}
@@ -191,4 +201,4 @@
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 3d49d81..514f895 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -24,75 +24,14 @@
}
filegroup {
- name: "FlickerTestsBase-src",
- srcs: ["src/com/android/server/wm/flicker/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppClose-src",
- srcs: ["src/**/close/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsActivityEmbedding-src",
- srcs: [
- "src/**/activityembedding/*.kt",
- "src/**/activityembedding/open/*.kt",
- "src/**/activityembedding/close/*.kt",
- "src/**/activityembedding/layoutchange/*.kt",
- "src/**/activityembedding/pip/*.kt",
- "src/**/activityembedding/rotation/*.kt",
- "src/**/activityembedding/rtl/*.kt",
- "src/**/activityembedding/splitscreen/*.kt",
- ],
-}
-
-filegroup {
- name: "FlickerTestsIme-src",
- srcs: ["src/**/ime/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunchCommon-src",
- srcs: ["src/**/launch/common/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunch1-src",
- srcs: ["src/**/launch/OpenApp*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsAppLaunch2-src",
- srcs: ["src/**/launch/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsNotification-src",
- srcs: ["src/**/notification/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsQuickswitch-src",
- srcs: ["src/**/quickswitch/*.kt"],
-}
-
-filegroup {
- name: "FlickerTestsRotation-src",
- srcs: ["src/**/rotation/*.kt"],
-}
-
-filegroup {
name: "FlickerServiceTests-src",
srcs: [
- "src/com/android/server/wm/flicker/service/**/*.kt",
+ "src/**/*",
],
}
java_defaults {
name: "FlickerTestsDefault",
- manifest: "manifests/AndroidManifest.xml",
- test_config_template: "AndroidTestTemplate.xml",
platform_apis: true,
certificate: "platform",
optimize: {
@@ -116,139 +55,6 @@
],
}
-android_test {
- name: "FlickerTestsOther",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestOther.xml"],
- package_name: "com.android.server.wm.flicker",
- instrumentation_target_package: "com.android.server.wm.flicker",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- exclude_srcs: [
- ":FlickerTestsAppClose-src",
- ":FlickerTestsIme-src",
- ":FlickerTestsAppLaunch1-src",
- ":FlickerTestsAppLaunch2-src",
- ":FlickerTestsQuickswitch-src",
- ":FlickerTestsRotation-src",
- ":FlickerTestsNotification-src",
- ":FlickerServiceTests-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppClose",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppClose.xml"],
- package_name: "com.android.server.wm.flicker.close",
- instrumentation_target_package: "com.android.server.wm.flicker.close",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppClose-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsIme",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestIme.xml"],
- package_name: "com.android.server.wm.flicker.ime",
- instrumentation_target_package: "com.android.server.wm.flicker.ime",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsIme-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppLaunch1",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
- package_name: "com.android.server.wm.flicker.launch",
- instrumentation_target_package: "com.android.server.wm.flicker.launch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppLaunchCommon-src",
- ":FlickerTestsAppLaunch1-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsAppLaunch2",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
- package_name: "com.android.server.wm.flicker.launch",
- instrumentation_target_package: "com.android.server.wm.flicker.launch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsAppLaunchCommon-src",
- ":FlickerTestsAppLaunch2-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ":FlickerTestsAppLaunch1-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsNotification",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestNotification.xml"],
- package_name: "com.android.server.wm.flicker.notification",
- instrumentation_target_package: "com.android.server.wm.flicker.notification",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsNotification-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsQuickswitch",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestQuickswitch.xml"],
- package_name: "com.android.server.wm.flicker.quickswitch",
- instrumentation_target_package: "com.android.server.wm.flicker.quickswitch",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsQuickswitch-src",
- ],
-}
-
-android_test {
- name: "FlickerTestsRotation",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestRotation.xml"],
- package_name: "com.android.server.wm.flicker.rotation",
- instrumentation_target_package: "com.android.server.wm.flicker.rotation",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerTestsRotation-src",
- ],
- exclude_srcs: [
- ":FlickerTestsActivityEmbedding-src",
- ],
-}
-
-android_test {
- name: "FlickerServiceTests",
- defaults: ["FlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestService.xml"],
- package_name: "com.android.server.wm.flicker.service",
- instrumentation_target_package: "com.android.server.wm.flicker.service",
- srcs: [
- ":FlickerTestsBase-src",
- ":FlickerServiceTests-src",
- ],
-}
-
java_library {
name: "wm-flicker-common-assertions",
platform_apis: true,
@@ -259,9 +65,6 @@
"src/**/*Assertions.java",
"src/**/*Assertions.kt",
],
- exclude_srcs: [
- "**/helpers/*",
- ],
static_libs: [
"flickerlib",
"flickerlib-helpers",
@@ -270,26 +73,6 @@
],
}
-java_library {
- name: "wm-flicker-common-app-helpers",
- platform_apis: true,
- optimize: {
- enabled: false,
- },
- srcs: [
- "**/helpers/*",
- ],
- static_libs: [
- "flickertestapplib",
- "flickerlib",
- "flickerlib-apphelpers",
- "flickerlib-helpers",
- "truth",
- "app-helpers-core",
- "wm-flicker-window-extensions",
- ],
-}
-
android_library_import {
name: "wm-flicker-window-extensions_nodeps",
aars: ["libs/window-extensions-release.aar"],
@@ -304,3 +87,9 @@
],
installable: false,
}
+
+java_library {
+ name: "FlickerTestsBase",
+ defaults: ["FlickerTestsDefault"],
+ srcs: ["src/**/*"],
+}
diff --git a/tests/FlickerTests/AppClose/Android.bp b/tests/FlickerTests/AppClose/Android.bp
new file mode 100644
index 0000000..151d12f
--- /dev/null
+++ b/tests/FlickerTests/AppClose/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsAppClose",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/AppClose/AndroidManifest.xml
similarity index 91%
rename from tests/FlickerTests/manifests/AndroidManifest.xml
rename to tests/FlickerTests/AppClose/AndroidManifest.xml
index 6bc7cbe..e75e178 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/AppClose/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.close">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.close"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/AppClose/AndroidTestTemplate.xml
index ed71531..4b6224e 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS b/tests/FlickerTests/AppClose/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/OWNERS
rename to tests/FlickerTests/AppClose/OWNERS
diff --git a/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/AppClose/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/AppClose/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/AppClose/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/AppClose/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 288558ae..64dd44d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 32305c6..eb256b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
rename to tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 8d752cc..ea025c7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/AppClose/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/AppClose/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
new file mode 100644
index 0000000..f33384d
--- /dev/null
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunchCommon-src",
+ srcs: ["src/**/common/*"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunch1-src",
+ srcs: ["src/**/OpenApp*"],
+}
+
+java_library {
+ name: "FlickerTestsAppLaunchCommon",
+ defaults: ["FlickerTestsDefault"],
+ srcs: [":FlickerTestsAppLaunchCommon-src"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch1",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [":FlickerTestsAppLaunch1-src"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch2",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ exclude_srcs: [
+ ":FlickerTestsAppLaunchCommon-src",
+ ":FlickerTestsAppLaunch1-src",
+ ],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/AppLaunch/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/AppLaunch/AndroidManifest.xml
index 6bc7cbe..b89af1a 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.launch">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.launch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
index ed71531..583bcb7 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS b/tests/FlickerTests/AppLaunch/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OWNERS
rename to tests/FlickerTests/AppLaunch/OWNERS
diff --git a/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/AppLaunch/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/AppLaunch/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index f788efa..413767c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index d86dc50..4168bdc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index be07053..9c55c98 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index f66eff9..fc6cdb1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 65214764..de666dd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 4d31c28..f8a9961 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 42e34b3..0aceb35 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
index 97ba99e..f41a2a2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch.common
+package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
@@ -24,6 +24,7 @@
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
+import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index 98e3646..93ca41c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -31,7 +31,6 @@
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.R
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index b82a129..9c2899ac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
index c854701..802c755 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
@@ -44,4 +44,4 @@
}
teardown { testApp.exit(wmHelper) }
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
rename to tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/FlickerService/Android.bp b/tests/FlickerTests/FlickerService/Android.bp
new file mode 100644
index 0000000..1a38115
--- /dev/null
+++ b/tests/FlickerTests/FlickerService/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerServiceTests",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/FlickerService/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/FlickerService/AndroidManifest.xml
index 6bc7cbe..f31e820 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/FlickerService/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.service">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.service"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
index ed71531..d6ae2b3 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml
@@ -83,20 +83,6 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
diff --git a/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/FlickerService/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/FlickerService/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
similarity index 99%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
index 3cae1c4..fcf442a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.tools.common.NavBar
import android.tools.common.Rotation
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
import android.tools.device.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
@@ -30,7 +31,6 @@
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
@Ignore("Base Test Class")
abstract class QuickSwitchBetweenTwoAppsForward(val rotation: Rotation = Rotation.ROTATION_0) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
rename to tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
new file mode 100644
index 0000000..057d9fc
--- /dev/null
+++ b/tests/FlickerTests/IME/Android.bp
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "FlickerTestsImeCommon-src",
+ srcs: ["src/**/common/*"],
+}
+
+filegroup {
+ name: "FlickerTestsIme1-src",
+ srcs: ["src/**/Close*"],
+}
+
+android_test {
+ name: "FlickerTestsIme",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+java_library {
+ name: "FlickerTestsImeCommon",
+ defaults: ["FlickerTestsDefault"],
+ srcs: [":FlickerTestsImeCommon-src"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+android_test {
+ name: "FlickerTestsIme1",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: [":FlickerTestsIme1-src"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsImeCommon",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsIme2",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ exclude_srcs: [
+ ":FlickerTestsIme1-src",
+ ":FlickerTestsImeCommon-src",
+ ],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsImeCommon",
+ ],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/IME/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/IME/AndroidManifest.xml
index 6bc7cbe..d6ca683 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/IME/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.ime">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.ime"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/IME/AndroidTestTemplate.xml
index ed71531..988f76f 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS b/tests/FlickerTests/IME/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/OWNERS
rename to tests/FlickerTests/IME/OWNERS
diff --git a/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/IME/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/IME/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/IME/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/IME/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
rename to tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/IME/trace_config/trace_config.textproto
similarity index 100%
rename from tests/FlickerTests/trace_config/trace_config.textproto
rename to tests/FlickerTests/IME/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Notification/Android.bp b/tests/FlickerTests/Notification/Android.bp
new file mode 100644
index 0000000..5bed568
--- /dev/null
+++ b/tests/FlickerTests/Notification/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsNotification",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/Notification/AndroidManifest.xml
similarity index 90%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/Notification/AndroidManifest.xml
index 6bc7cbe..d212c10 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/Notification/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.notification">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.notification"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/Notification/AndroidTestTemplate.xml
index ed71531..4036858 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Notification/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS b/tests/FlickerTests/Notification/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS
rename to tests/FlickerTests/Notification/OWNERS
diff --git a/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/Notification/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/Notification/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/Notification/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/Notification/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/Consts.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
rename to tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/Notification/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/Notification/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/QuickSwitch/Android.bp b/tests/FlickerTests/QuickSwitch/Android.bp
new file mode 100644
index 0000000..64f7183
--- /dev/null
+++ b/tests/FlickerTests/QuickSwitch/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsQuickswitch",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/QuickSwitch/AndroidManifest.xml
similarity index 90%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/QuickSwitch/AndroidManifest.xml
index 6bc7cbe..41b0cd4 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.quickswitch">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.quickswitch"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
similarity index 86%
copy from tests/FlickerTests/AndroidTestTemplate.xml
copy to tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
index ed71531..797ca4e 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS b/tests/FlickerTests/QuickSwitch/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/OWNERS
rename to tests/FlickerTests/QuickSwitch/OWNERS
diff --git a/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/QuickSwitch/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/QuickSwitch/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
rename to tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/Rotation/Android.bp b/tests/FlickerTests/Rotation/Android.bp
new file mode 100644
index 0000000..8e93b5b
--- /dev/null
+++ b/tests/FlickerTests/Rotation/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FlickerTestsRotation",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: ["FlickerTestsBase"],
+}
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/Rotation/AndroidManifest.xml
similarity index 91%
copy from tests/FlickerTests/manifests/AndroidManifest.xml
copy to tests/FlickerTests/Rotation/AndroidManifest.xml
index 6bc7cbe..6bbb1f6 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/Rotation/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flicker">
+ package="com.android.server.wm.flicker.rotation">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
@@ -59,4 +59,9 @@
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.rotation"
+ android:label="WindowManager Flicker Tests">
+ </instrumentation>
</manifest>
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
similarity index 86%
rename from tests/FlickerTests/AndroidTestTemplate.xml
rename to tests/FlickerTests/Rotation/AndroidTestTemplate.xml
index ed71531..b5ea739 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml
@@ -83,21 +83,7 @@
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="pull-pattern-keys" value="perfetto_file_path"/>
<option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.close/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.ime/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.launch/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.quickswitch/files"/>
- <option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
- <option name="directory-keys"
- value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS b/tests/FlickerTests/Rotation/OWNERS
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/OWNERS
rename to tests/FlickerTests/Rotation/OWNERS
diff --git a/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml b/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml
new file mode 100644
index 0000000..7b3f07e
--- /dev/null
+++ b/tests/FlickerTests/Rotation/res/anim/show_hide_show_3000ms.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fillAfter="true">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="1000" />
+
+ <alpha
+ android:startOffset="2000"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:duration="1000" />
+</set>
\ No newline at end of file
diff --git a/tests/FlickerTests/manifests/AndroidManifestOther.xml b/tests/FlickerTests/Rotation/res/xml/network_security_config.xml
similarity index 63%
copy from tests/FlickerTests/manifests/AndroidManifestOther.xml
copy to tests/FlickerTests/Rotation/res/xml/network_security_config.xml
index 47749b8..4bd9ca0 100644
--- a/tests/FlickerTests/manifests/AndroidManifestOther.xml
+++ b/tests/FlickerTests/Rotation/res/xml/network_security_config.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
@@ -14,11 +15,8 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
rename to tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
diff --git a/tests/FlickerTests/trace_config/trace_config.textproto b/tests/FlickerTests/Rotation/trace_config/trace_config.textproto
similarity index 100%
copy from tests/FlickerTests/trace_config/trace_config.textproto
copy to tests/FlickerTests/Rotation/trace_config/trace_config.textproto
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppClose.xml b/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
deleted file mode 100644
index 4cdcb90..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestAppClose.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.close">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.close"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml b/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
deleted file mode 100644
index 659a745..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestAppLaunch.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.launch">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.launch"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestIme.xml b/tests/FlickerTests/manifests/AndroidManifestIme.xml
deleted file mode 100644
index abd03af..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestIme.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.ime">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.ime"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestNotification.xml b/tests/FlickerTests/manifests/AndroidManifestNotification.xml
deleted file mode 100644
index ad33dee..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestNotification.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.close">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.notification"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml b/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
deleted file mode 100644
index 203035d..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestQuickswitch.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.quickswitch">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.quickswitch"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestRotation.xml b/tests/FlickerTests/manifests/AndroidManifestRotation.xml
deleted file mode 100644
index 2852cf2..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestRotation.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.rotation">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.rotation"
- android:label="WindowManager Flicker Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/manifests/AndroidManifestService.xml b/tests/FlickerTests/manifests/AndroidManifestService.xml
deleted file mode 100644
index 3a7bc509..0000000
--- a/tests/FlickerTests/manifests/AndroidManifestService.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.service">
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.wm.flicker.service"
- android:label="WindowManager Flicker Service Tests">
- </instrumentation>
-</manifest>
diff --git a/tests/FlickerTests/test-apps/app-helpers/Android.bp b/tests/FlickerTests/test-apps/app-helpers/Android.bp
new file mode 100644
index 0000000..fc4d71c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/app-helpers/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "wm-flicker-common-app-helpers",
+ platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
+ srcs: ["src/**/*"],
+ static_libs: [
+ "flickertestapplib",
+ "flickerlib",
+ "flickerlib-apphelpers",
+ "flickerlib-helpers",
+ "truth",
+ "app-helpers-core",
+ "wm-flicker-window-extensions",
+ ],
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GestureHelper.java
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index e106f65..d3cee64 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -121,7 +121,7 @@
else -> null
}
if (matcher != null && matcher.find()) {
- return matcher.group(1).equals("VISIBLE")
+ return matcher.group(1) == "VISIBLE"
}
}
return false
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index da51eff..73cc2f2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,11 +250,12 @@
launchedAppComponentMatcherOverride,
action,
stringExtras,
- waitConditionsBuilder = wmHelper
- .StateSyncBuilder()
- .add(ConditionsFactory.isWMStateComplete())
- .withAppTransitionIdle()
- .add(ConditionsFactory.hasPipWindow())
+ waitConditionsBuilder =
+ wmHelper
+ .StateSyncBuilder()
+ .add(ConditionsFactory.isWMStateComplete())
+ .withAppTransitionIdle()
+ .add(ConditionsFactory.hasPipWindow())
)
wmHelper
@@ -265,8 +266,7 @@
}
/** Expand the PIP window back to full screen via intent and wait until the app is visible */
- fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
- launchViaIntent(wmHelper)
+ fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) = launchViaIntent(wmHelper)
fun changeAspectRatio() {
val intent = Intent("com.android.wm.shell.flicker.testapp.ASPECT_RATIO")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
similarity index 100%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
rename to tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
diff --git a/tools/fonts/update_font_metadata.py b/tools/fonts/update_font_metadata.py
index c07a98a..04a5528 100755
--- a/tools/fonts/update_font_metadata.py
+++ b/tools/fonts/update_font_metadata.py
@@ -19,7 +19,7 @@
args_parser.add_argument('--revision', help='Updated font revision. Use + to update revision based on the current revision')
args = args_parser.parse_args()
- font = ttLib.TTFont(args.input)
+ font = ttLib.TTFont(args.input, recalcTimestamp=False)
update_font_revision(font, args.revision)
font.save(args.output)
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index 226e2fad..182940e 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -12,6 +12,7 @@
name: "hoststubgen-for-prototype-only-genrule",
visibility: [
":__subpackages__",
+ "//frameworks/base",
"//frameworks/base/ravenwood:__subpackages__",
],
}
@@ -21,6 +22,7 @@
name: "hoststubgen-for-prototype-only-java",
visibility: [
":__subpackages__",
+ "//frameworks/base",
"//frameworks/base/ravenwood:__subpackages__",
],
}
@@ -30,6 +32,7 @@
name: "hoststubgen-for-prototype-only-filegroup",
visibility: [
":__subpackages__",
+ "//frameworks/base",
"//frameworks/base/ravenwood:__subpackages__",
],
}
@@ -44,8 +47,6 @@
],
host_supported: true,
- // Seems like we need it to avoid circular deps.
- // Copied it from "app-compat-annotations".
sdk_version: "core_current",
}
@@ -66,6 +67,21 @@
visibility: ["//visibility:public"],
}
+java_library {
+ name: "hoststubgen-helper-runtime.ravenwood",
+ srcs: [
+ "helper-runtime-src/**/*.java",
+ ],
+ libs: [
+ "junit",
+ ],
+ static_libs: [
+ "guava",
+ ],
+ jarjar_rules: "jarjar-rules.txt",
+ visibility: ["//visibility:public"],
+}
+
// Host-side stub generator tool.
java_binary_host {
name: "hoststubgen",
@@ -73,6 +89,7 @@
srcs: ["src/**/*.kt"],
static_libs: [
"hoststubgen-helper-runtime",
+ "junit",
"ow2-asm",
"ow2-asm-analysis",
"ow2-asm-commons",
@@ -245,6 +262,18 @@
],
}
+java_library {
+ name: "hoststubgen-helper-framework-runtime.ravenwood",
+ defaults: ["hoststubgen-for-prototype-only-java"],
+ srcs: [
+ "helper-framework-runtime-src/framework/**/*.java",
+ ],
+ libs: [
+ "hoststubgen-helper-runtime.ravenwood",
+ "framework-minus-apex.ravenwood",
+ ],
+}
+
// Defaults for host side test modules.
// We need two rules for each test.
// 1. A "-test-lib" jar, which compiles the test against the stub jar.
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerStub.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerStub.java
new file mode 100644
index 0000000..dab8e89
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStaticInitializerStub.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestStaticInitializerStub {
+}
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
index 295498d..ff0fe32 100644
--- a/tools/hoststubgen/hoststubgen/framework-policy-override.txt
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -62,6 +62,7 @@
# Used by ArrayMap. No need to put them in the stub, but we need them in impl.
class android.util.MapCollections keepclass
class android.util.ContainerHelpers keepclass
+class android.util.EmptyArray stubclass
class com.android.internal.util.XmlUtils keepclass
class com.android.internal.util.FastMath keepclass
class android.util.MathUtils keepclass
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
index 9f83597..25abbac 100644
--- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -23,6 +23,8 @@
import javax.annotation.concurrent.GuardedBy;
+import org.junit.AssumptionViolatedException;
+
/**
* Utilities used in the host side test environment.
*/
@@ -63,7 +65,7 @@
*/
public static void onThrowMethodCalled() {
// TODO: Maybe add call tracking?
- throw new RuntimeException("This method is not supported on the host side");
+ throw new AssumptionViolatedException("This method is not supported on the host side");
}
/**
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
index 3f87527..43f9cb9b 100644
--- a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -39,3 +39,6 @@
--class-load-hook-annotation
android.hosttest.annotation.HostSideTestClassLoadHook
+
+--stub-static-initializer-annotation
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 7531759..872d568 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -17,9 +17,9 @@
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.filters.AnnotationBasedFilter
-import com.android.hoststubgen.filters.DefaultHookInjectingFilter
import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
import com.android.hoststubgen.filters.ConstantFilter
+import com.android.hoststubgen.filters.DefaultHookInjectingFilter
import com.android.hoststubgen.filters.FilterPolicy
import com.android.hoststubgen.filters.ImplicitOutputFilter
import com.android.hoststubgen.filters.KeepAllClassesFilter
@@ -28,6 +28,7 @@
import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
import com.android.hoststubgen.filters.printAsTextPolicy
import com.android.hoststubgen.visitors.BaseAdapter
+import com.android.hoststubgen.visitors.PackageRedirectRemapper
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
@@ -179,6 +180,7 @@
options.substituteAnnotations,
options.nativeSubstituteAnnotations,
options.classLoadHookAnnotations,
+ options.stubStaticInitializerAnnotations,
filter
)
@@ -237,6 +239,8 @@
val start = System.currentTimeMillis()
+ val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
+
log.withIndent {
// Open the input jar file and process each entry.
ZipFile(inJar).use { inZip ->
@@ -246,7 +250,7 @@
while (inEntries.hasMoreElements()) {
val entry = inEntries.nextElement()
convertSingleEntry(inZip, entry, stubOutStream, implOutStream,
- filter, enableChecker, classes, errors)
+ filter, packageRedirector, enableChecker, classes, errors)
}
log.i("Converted all entries.")
}
@@ -268,6 +272,7 @@
stubOutStream: ZipOutputStream,
implOutStream: ZipOutputStream,
filter: OutputFilter,
+ packageRedirector: PackageRedirectRemapper,
enableChecker: Boolean,
classes: ClassNodes,
errors: HostStubGenErrors,
@@ -284,7 +289,7 @@
// If it's a class, convert it.
if (name.endsWith(".class")) {
processSingleClass(inZip, entry, stubOutStream, implOutStream, filter,
- enableChecker, classes, errors)
+ packageRedirector, enableChecker, classes, errors)
return
}
@@ -334,37 +339,40 @@
stubOutStream: ZipOutputStream,
implOutStream: ZipOutputStream,
filter: OutputFilter,
+ packageRedirector: PackageRedirectRemapper,
enableChecker: Boolean,
classes: ClassNodes,
errors: HostStubGenErrors,
) {
- val className = entry.name.replaceFirst("\\.class$".toRegex(), "")
- val classPolicy = filter.getPolicyForClass(className)
+ val classInternalName = entry.name.replaceFirst("\\.class$".toRegex(), "")
+ val classPolicy = filter.getPolicyForClass(classInternalName)
if (classPolicy.policy == FilterPolicy.Remove) {
- log.d("Removing class: %s %s", className, classPolicy)
+ log.d("Removing class: %s %s", classInternalName, classPolicy)
return
}
// Generate stub first.
if (classPolicy.policy.needsInStub) {
- log.v("Creating stub class: %s Policy: %s", className, classPolicy)
+ log.v("Creating stub class: %s Policy: %s", classInternalName, classPolicy)
log.withIndent {
BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
val newEntry = ZipEntry(entry.name)
stubOutStream.putNextEntry(newEntry)
- convertClass(/*forImpl=*/false, bis, stubOutStream, filter, enableChecker,
- classes, errors)
+ convertClass(classInternalName, /*forImpl=*/false, bis,
+ stubOutStream, filter, packageRedirector, enableChecker, classes,
+ errors)
stubOutStream.closeEntry()
}
}
}
- log.v("Creating impl class: %s Policy: %s", className, classPolicy)
+ log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy)
if (classPolicy.policy.needsInImpl) {
log.withIndent {
BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
val newEntry = ZipEntry(entry.name)
implOutStream.putNextEntry(newEntry)
- convertClass(/*forImpl=*/true, bis, implOutStream, filter, enableChecker,
- classes, errors)
+ convertClass(classInternalName, /*forImpl=*/true, bis,
+ implOutStream, filter, packageRedirector, enableChecker, classes,
+ errors)
implOutStream.closeEntry()
}
}
@@ -375,14 +383,16 @@
* Convert a single class to either "stub" or "impl".
*/
private fun convertClass(
- forImpl: Boolean,
- input: InputStream,
- out: OutputStream,
- filter: OutputFilter,
- enableChecker: Boolean,
- classes: ClassNodes,
- errors: HostStubGenErrors,
- ) {
+ classInternalName: String,
+ forImpl: Boolean,
+ input: InputStream,
+ out: OutputStream,
+ filter: OutputFilter,
+ packageRedirector: PackageRedirectRemapper,
+ enableChecker: Boolean,
+ classes: ClassNodes,
+ errors: HostStubGenErrors,
+ ) {
val cr = ClassReader(input)
// COMPUTE_FRAMES wouldn't be happy if code uses
@@ -397,11 +407,11 @@
val visitorOptions = BaseAdapter.Options(
enablePreTrace = options.enablePreTrace,
enablePostTrace = options.enablePostTrace,
- enableMethodLogging = options.enablePreTrace,
enableNonStubMethodCallDetection = options.enableNonStubMethodCallDetection,
errors = errors,
)
- outVisitor = BaseAdapter.getVisitor(classes, outVisitor, filter, forImpl, visitorOptions)
+ outVisitor = BaseAdapter.getVisitor(classInternalName, classes, outVisitor, filter,
+ packageRedirector, forImpl, visitorOptions)
cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
val data = cw.toByteArray()
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index bbb7dab..d74612d 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -47,6 +47,9 @@
var substituteAnnotations: MutableSet<String> = mutableSetOf(),
var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(),
var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
+ var stubStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
+
+ var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
var defaultClassLoadHook: String? = null,
var defaultMethodCallHook: String? = null,
@@ -77,6 +80,15 @@
return this
}
+ private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
+ val colon = fromColonTo.indexOf(':')
+ if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
+ throw ArgumentsException("--package-redirect must be a colon-separated string")
+ }
+ // TODO check for duplicates
+ return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
+ }
+
fun parseArgs(args: Array<String>): HostStubGenOptions {
val ret = HostStubGenOptions()
@@ -150,7 +162,14 @@
"--class-load-hook-annotation" ->
ret.classLoadHookAnnotations +=
- ensureUniqueAnnotation(ai.nextArgRequired(arg))
+ ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+ "--stub-static-initializer-annotation" ->
+ ret.stubStaticInitializerAnnotations +=
+ ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+ "--package-redirect" ->
+ ret.packageRedirects += parsePackageRedirect(ai.nextArgRequired(arg))
"--default-class-load-hook" ->
ret.defaultClassLoadHook = ai.nextArgRequired(arg)
@@ -294,6 +313,7 @@
substituteAnnotations=$substituteAnnotations,
nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
classLoadHookAnnotations=$classLoadHookAnnotations,
+ packageRedirects=$packageRedirects,
defaultClassLoadHook=$defaultClassLoadHook,
defaultMethodCallHook=$defaultMethodCallHook,
intersectStubJars=$intersectStubJars,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
index 3f492e8..9f3ec4d 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -20,6 +20,8 @@
import com.android.hoststubgen.HostStubGenInternalException
import com.android.hoststubgen.InvalidAnnotationException
import com.android.hoststubgen.addNonNullElement
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.findAnnotationValueAsString
import com.android.hoststubgen.asm.findAnyAnnotation
@@ -48,6 +50,7 @@
substituteAnnotations_: Set<String>,
nativeSubstituteAnnotations_: Set<String>,
classLoadHookAnnotations_: Set<String>,
+ stubStaticInitializerAnnotations_: Set<String>,
fallback: OutputFilter,
) : DelegatingFilter(fallback) {
private var stubAnnotations = convertToInternalNames(stubAnnotations_)
@@ -59,6 +62,7 @@
private var substituteAnnotations = convertToInternalNames(substituteAnnotations_)
private var nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_)
private var classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_)
+ private var stubStaticInitializerAnnotations = convertToInternalNames(stubStaticInitializerAnnotations_)
/** Annotations that control API visibility. */
private var visibilityAnnotations: Set<String> = convertToInternalNames(
@@ -158,6 +162,7 @@
findAnyAnnotation(removeAnnotations, visibles, invisibles)?.let {
return FilterPolicy.Remove.withReason(reasonAnnotation)
}
+
return null
}
@@ -208,6 +213,13 @@
): FilterPolicyWithReason {
val cn = classes.getClass(className)
+ if (methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC) {
+ findAnyAnnotation(stubStaticInitializerAnnotations,
+ cn.visibleAnnotations, cn.invisibleAnnotations)?.let {
+ return FilterPolicy.Stub.withReason(reasonAnnotation)
+ }
+ }
+
cn.methods?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
// @SubstituteWith is going to complicate the policy here, so we ask helper
// what to do.
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
index f11ac2f..9317996 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
@@ -56,6 +56,12 @@
Throw,
/**
+ * Only usable with methods. The item will be kept in the impl jar file, but when called,
+ * it'll no-op. Currently only supported for methods returning `void`.
+ */
+ Ignore,
+
+ /**
* Remove the item completely.
*/
Remove;
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
index c6334c4..07a023c 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -23,6 +23,7 @@
import com.android.hoststubgen.log
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+import org.objectweb.asm.tree.ClassNode
/**
* Filter implementing "implicit" rules, such as:
@@ -35,10 +36,7 @@
private val classes: ClassNodes,
fallback: OutputFilter
) : DelegatingFilter(fallback) {
- private fun getClassImplicitPolicy(className: String): FilterPolicyWithReason? {
- // TODO: This check should be cached.
- val cn = classes.getClass(className)
-
+ private fun getClassImplicitPolicy(className: String, cn: ClassNode): FilterPolicyWithReason? {
if (isAnonymousInnerClass(cn)) {
log.forDebug {
// log.d(" anon-inner class: ${className} outer: ${cn.outerClass} ")
@@ -57,10 +55,24 @@
}
override fun getPolicyForClass(className: String): FilterPolicyWithReason {
- // Use the implicit policy, if any.
- getClassImplicitPolicy(className)?.let { return it }
+ val fallback = super.getPolicyForClass(className)
- return super.getPolicyForClass(className)
+ // TODO: This check should be cached.
+ val cn = classes.getClass(className)
+
+ if (cn.superName == "java/lang/Enum" &&
+ fallback.policy == FilterPolicy.Keep) {
+ return FilterPolicy.KeepClass.withReason("enum")
+ }
+ if (cn.interfaces.contains("java/lang/annotation/Annotation") &&
+ fallback.policy == FilterPolicy.Keep) {
+ return FilterPolicy.KeepClass.withReason("annotation")
+ }
+
+ // Use the implicit policy, if any.
+ getClassImplicitPolicy(className, cn)?.let { return it }
+
+ return fallback
}
override fun getPolicyForMethod(
@@ -86,10 +98,10 @@
// If we throw from the static initializer, the class would be useless, so we convert it
// "keep" instead.
if (methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC &&
- fallback.policy == FilterPolicy.Throw) {
+ fallback.policy == FilterPolicy.Throw) {
// TODO Maybe show a warning?? But that'd be too noisy with --default-throw.
- return FilterPolicy.Keep.withReason(
- "'throw' on static initializer is handled as 'keep'" +
+ return FilterPolicy.Ignore.withReason(
+ "'throw' on static initializer is handled as 'ignore'" +
" [original throw reason: ${fallback.reason}]")
}
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 3cf9a1d..f25e862 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
@@ -30,6 +30,7 @@
import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
+import org.objectweb.asm.commons.ClassRemapper
import org.objectweb.asm.util.TraceClassVisitor
import java.io.PrintWriter
@@ -49,9 +50,8 @@
val errors: HostStubGenErrors,
val enablePreTrace: Boolean,
val enablePostTrace: Boolean,
- val enableMethodLogging: Boolean,
val enableNonStubMethodCallDetection: Boolean,
- )
+ )
protected lateinit var currentPackageName: String
protected lateinit var currentClassName: String
@@ -219,9 +219,11 @@
companion object {
fun getVisitor(
+ classInternalName: String,
classes: ClassNodes,
nextVisitor: ClassVisitor,
filter: OutputFilter,
+ packageRedirector: PackageRedirectRemapper,
forImpl: Boolean,
options: Options,
): ClassVisitor {
@@ -229,12 +231,27 @@
val verbosePrinter = PrintWriter(log.getVerbosePrintStream())
- // TODO: This doesn't work yet.
-
// Inject TraceClassVisitor for debugging.
if (options.enablePostTrace) {
next = TraceClassVisitor(next, verbosePrinter)
}
+
+ // Handle --package-redirect
+ if (!packageRedirector.isEmpty) {
+ // Don't apply the remapper on redirect-from classes.
+ // Otherwise, if the target jar actually contains the "from" classes (which
+ // may or may not be the case) they'd be renamed.
+ // But we update all references in other places, so, a method call to a "from" class
+ // would be replaced with the "to" class. All type references (e.g. variable types)
+ // will be updated too.
+ if (!packageRedirector.isTarget(classInternalName)) {
+ next = ClassRemapper(next, packageRedirector)
+ } else {
+ log.v("Class $classInternalName is a redirect-from class, not applying" +
+ " --package-redirect")
+ }
+ }
+
var ret: ClassVisitor
if (forImpl) {
ret = ImplGeneratingAdapter(classes, next, filter, options)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
index ce72a8e..e63efd0 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -192,6 +192,18 @@
return ThrowingMethodAdapter(
access, name, descriptor, signature, exceptions, innerVisitor)
}
+ if (policy.policy == FilterPolicy.Ignore) {
+ when (Type.getReturnType(descriptor)) {
+ Type.VOID_TYPE -> {
+ log.v("Making method ignored...")
+ return IgnoreMethodAdapter(
+ access, name, descriptor, signature, exceptions, innerVisitor)
+ }
+ else -> {
+ throw RuntimeException("Ignored policy only allowed for void methods")
+ }
+ }
+ }
}
return innerVisitor
@@ -252,6 +264,23 @@
}
/**
+ * A method adapter that replaces the method body with a no-op return.
+ */
+ private inner class IgnoreMethodAdapter(
+ access: Int,
+ val name: String,
+ descriptor: String,
+ signature: String?,
+ exceptions: Array<String>?,
+ next: MethodVisitor?
+ ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
+ override fun emitNewCode() {
+ visitInsn(Opcodes.RETURN)
+ visitMaxs(0, 0) // We let ASM figure them out.
+ }
+ }
+
+ /**
* A method adapter that replaces a native method call with a call to the "native substitution"
* class.
*/
@@ -379,4 +408,4 @@
false)
}
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
new file mode 100644
index 0000000..b3790e1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.visitors
+
+import com.android.hoststubgen.asm.toJvmClassName
+import org.objectweb.asm.commons.Remapper
+
+/**
+ * A [Remapper] for `--package-redirect`
+ */
+class PackageRedirectRemapper(
+ packageRedirects: List<Pair<String, String>>,
+ ) : Remapper() {
+
+ /**
+ * Example: `dalvik/` -> `com/android/hostsubgen/substitution/dalvik/`
+ */
+ private val packageRedirectsWithSlash: List<Pair<String, String>> = packageRedirects.map {
+ p -> Pair(p.first.toJvmClassName() + "/", p.second.toJvmClassName() + "/")
+ }
+
+ /**
+ * Cache.
+ * If a class is a redirect-from class, then the "to" class name will be stored as the value.
+ * Otherwise, "" will be stored.
+ */
+ private val cache = mutableMapOf<String, String>()
+
+ /**
+ * Return whether any redirect is defined.
+ */
+ val isEmpty get() = packageRedirectsWithSlash.isEmpty()
+
+ override fun map(internalName: String?): String? {
+ if (internalName == null) {
+ return null
+ }
+ val to = mapInner(internalName)
+ return to ?: internalName
+ }
+
+ /**
+ * Internal "map" function. Unlike [map(String)], this method will return null
+ * if a class is not a redirect-from class.
+ */
+ private fun mapInner(internalName: String): String? {
+ cache[internalName]?.let {
+ return if (it.isEmpty()) null else it
+ }
+
+ var ret = ""
+ packageRedirectsWithSlash.forEach { fromTo ->
+ if (internalName.startsWith(fromTo.first)) {
+ ret = fromTo.second + internalName.substring(fromTo.first.length)
+ }
+ }
+ cache.set(internalName, ret)
+
+ return if (ret.isEmpty()) null else ret
+ }
+
+ /**
+ * Return true if a class is a redirect-from class.
+ */
+ fun isTarget(internalName: String): Boolean {
+ return mapInner(internalName) != null
+ }
+}
+
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
index b71e5c4..1f8382a 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
@@ -42,3 +42,16 @@
],
test_suites: ["general-tests"],
}
+
+// "Productionized" build rule.
+android_ravenwood_test {
+ name: "HostStubGenTest-framework-test",
+ srcs: [
+ "src/**/*.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+ "mockito",
+ ],
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
index 62bbf48..2c5949c 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
@@ -23,16 +23,10 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.Log;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.AbstractMap;
import java.util.Arrays;
@@ -50,111 +44,9 @@
/**
* Some basic tests for {@link android.util.ArrayMap}.
*/
-@RunWith(AndroidJUnit4.class)
public class ArrayMapTest {
static final boolean DEBUG = false;
- static final int OP_ADD = 1;
- static final int OP_REM = 2;
-
- static int[] OPS = new int[]{
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
-
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
-
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
-
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
-
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
- OP_ADD, OP_ADD, OP_ADD,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
- OP_REM, OP_REM, OP_REM,
- OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
- };
-
- static int[] KEYS = new int[]{
- // General adding and removing.
- -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900,
- 2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400,
- 600, -1, 1900, 600, 300, 2100, 200, 800, 800,
- 1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900,
-
- // Shrink when removing item from end.
- 100, 200, 300, 400, 500, 600, 700, 800, 900,
- 900, 800, 700, 600, 500, 400, 300, 200, 100,
-
- // Shrink when removing item from middle.
- 100, 200, 300, 400, 500, 600, 700, 800, 900,
- 900, 800, 700, 600, 500, 400, 200, 300, 100,
-
- // Shrink when removing item from front.
- 100, 200, 300, 400, 500, 600, 700, 800, 900,
- 900, 800, 700, 600, 500, 400, 100, 200, 300,
-
- // Test hash collisions.
- 105, 106, 108, 104, 102, 102, 107, 5, 205,
- 4, 202, 203, 3, 5, 101, 109, 200, 201,
- 0, -1, 100,
- 106, 108, 104, 102, 103, 105, 107, 101, 109,
- -1, 100, 0,
- 4, 5, 3, 5, 200, 203, 202, 201, 205,
- };
-
- public static class ControlledHash implements Parcelable {
- final int mValue;
-
- ControlledHash(int value) {
- mValue = value;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o == null) {
- return false;
- }
- return mValue == ((ControlledHash)o).mValue;
- }
-
- @Override
- public final int hashCode() {
- return mValue/100;
- }
-
- @Override
- public final String toString() {
- return Integer.toString(mValue);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mValue);
- }
-
- public static final Parcelable.Creator<ControlledHash> CREATOR
- = new Parcelable.Creator<ControlledHash>() {
- public ControlledHash createFromParcel(Parcel in) {
- return new ControlledHash(in.readInt());
- }
-
- public ControlledHash[] newArray(int size) {
- return new ControlledHash[size];
- }
- };
- }
-
private static boolean compare(Object v1, Object v2) {
if (v1 == null) {
return v2 == null;
@@ -287,35 +179,6 @@
}
}
- private static void compareBundles(Bundle bundle1, Bundle bundle2) {
- Set<String> keySet1 = bundle1.keySet();
- Iterator<String> iterator1 = keySet1.iterator();
- while (iterator1.hasNext()) {
- String key = iterator1.next();
- int value1 = bundle1.getInt(key);
- if (bundle2.get(key) == null) {
- fail("Bad Bundle: bundle2 didn't have expected key " + key);
- }
- int value2 = bundle2.getInt(key);
- if (value1 != value2) {
- fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
- }
- }
- Set<String> keySet2 = bundle2.keySet();
- Iterator<String> iterator2 = keySet2.iterator();
- while (iterator2.hasNext()) {
- String key = iterator2.next();
- if (bundle1.get(key) == null) {
- fail("Bad Bundle: bundle1 didn't have expected key " + key);
- }
- int value1 = bundle1.getInt(key);
- int value2 = bundle2.getInt(key);
- if (value1 != value2) {
- fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
- }
- }
- }
-
private static void dump(Map map, ArrayMap array) {
Log.e("test", "HashMap of " + map.size() + " entries:");
Set<Map.Entry> mapSet = map.entrySet();
@@ -339,96 +202,6 @@
}
}
- private static void dump(Bundle bundle1, Bundle bundle2) {
- Log.e("test", "First Bundle of " + bundle1.size() + " entries:");
- Set<String> keys1 = bundle1.keySet();
- for (String key : keys1) {
- Log.e("test", " " + key + " -> " + bundle1.get(key));
- }
- Log.e("test", "Second Bundle of " + bundle2.size() + " entries:");
- Set<String> keys2 = bundle2.keySet();
- for (String key : keys2) {
- Log.e("test", " " + key + " -> " + bundle2.get(key));
- }
- }
-
- @Test
- public void testBasicArrayMap() {
- HashMap<ControlledHash, Integer> hashMap = new HashMap<>();
- ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<>();
- Bundle bundle = new Bundle();
-
- for (int i = 0; i < OPS.length; i++) {
- Integer oldHash;
- Integer oldArray;
- ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
- String strKey = KEYS[i] < 0 ? null : Integer.toString(KEYS[i]);
- switch (OPS[i]) {
- case OP_ADD:
- if (DEBUG) Log.i("test", "Adding key: " + key);
- oldHash = hashMap.put(key, i);
- oldArray = arrayMap.put(key, i);
- bundle.putInt(strKey, i);
- break;
- case OP_REM:
- if (DEBUG) Log.i("test", "Removing key: " + key);
- oldHash = hashMap.remove(key);
- oldArray = arrayMap.remove(key);
- bundle.remove(strKey);
- break;
- default:
- fail("Bad operation " + OPS[i] + " @ " + i);
- return;
- }
- if (!compare(oldHash, oldArray)) {
- String msg = "Bad result: expected " + oldHash + ", got " + oldArray;
- Log.e("test", msg);
- dump(hashMap, arrayMap);
- fail(msg);
- }
- try {
- validateArrayMap(arrayMap);
- } catch (Throwable e) {
- Log.e("test", e.getMessage());
- dump(hashMap, arrayMap);
- throw e;
- }
- try {
- compareMaps(hashMap, arrayMap);
- } catch (Throwable e) {
- Log.e("test", e.getMessage());
- dump(hashMap, arrayMap);
- throw e;
- }
- Parcel parcel = Parcel.obtain();
- bundle.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- Bundle bundle2 = parcel.readBundle();
- try {
- compareBundles(bundle, bundle2);
- } catch (Throwable e) {
- Log.e("test", e.getMessage());
- dump(bundle, bundle2);
- throw e;
- }
- }
-
- arrayMap.put(new ControlledHash(50000), 100);
- ControlledHash lookup = new ControlledHash(50000);
- Iterator<ControlledHash> it = arrayMap.keySet().iterator();
- while (it.hasNext()) {
- if (it.next().equals(lookup)) {
- it.remove();
- }
- }
- if (arrayMap.containsKey(lookup)) {
- String msg = "Bad map iterator: didn't remove test key";
- Log.e("test", msg);
- dump(hashMap, arrayMap);
- fail(msg);
- }
- }
-
@Test
public void testCopyArrayMap() {
// map copy constructor test
@@ -481,44 +254,6 @@
}
}
-// /**
-// * Test creating a malformed array map with duplicated keys and that we will catch this when
-// * unparcelling.
-// */
-// @Test
-// public void testDuplicateKeys() throws NoSuchMethodException,
-// InvocationTargetException, IllegalAccessException, NoSuchFieldException {
-// ArrayMap<String, Object> map1 = new ArrayMap(2);
-//
-// Method appendMethod = ArrayMap.class.getMethod("append", Object.class, Object.class);
-// appendMethod.invoke(map1, Integer.toString(100000), "foo");
-// appendMethod.invoke(map1, Integer.toString(100000), "bar");
-//
-// // Now parcel/unparcel, and verify we get the expected error.
-// Parcel parcel = Parcel.obtain();
-// Method writeArrayMapMethod = Parcel.class.getMethod("writeArrayMap", ArrayMap.class);
-// writeArrayMapMethod.invoke(parcel, map1);
-// parcel.setDataPosition(0);
-// ArrayMap<String, Object> map2 = new ArrayMap(2);
-//
-// try {
-// Parcel.class.getMethod("readArrayMap", ArrayMap.class, ClassLoader.class).invoke(
-// parcel, map2, null);
-// } catch (InvocationTargetException e) {
-// Throwable cause = e.getCause();
-// if (cause instanceof IllegalArgumentException) {
-// // Good!
-// return;
-// }
-// throw e;
-// }
-//
-// String msg = "Didn't throw expected IllegalArgumentException";
-// Log.e("test", msg);
-// dump(map1, map2);
-// fail(msg);
-// }
-
private static void checkEntrySetToArray(ArrayMap<?, ?> testMap) {
try {
testMap.entrySet().toArray();
@@ -734,4 +469,4 @@
fail("ArrayMap replaceAll failure, expect " + expectedMap + ", but " + map);
}
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
index 56544b4..3e33b54 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
import android.util.Log;
-import android.util.Slog;
import org.junit.Test;
@@ -33,12 +32,6 @@
Log.i("TAG", "Test i log");
Log.w("TAG", "Test w log");
Log.e("TAG", "Test e log");
-
- Slog.v("TAG", "Test v slog");
- Slog.d("TAG", "Test d slog");
- Slog.i("TAG", "Test i slog");
- Slog.w("TAG", "Test w slog");
- Slog.e("TAG", "Test e slog");
}
@Test
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
index f9dc305..3dc6da3 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -24,7 +24,8 @@
defaults: ["hoststubgen-command-defaults"],
cmd: hoststubgen_common_options +
"--in-jar $(location :hoststubgen-test-tiny-framework) " +
- "--policy-override-file $(location policy-override-tiny-framework.txt) ",
+ "--policy-override-file $(location policy-override-tiny-framework.txt) " +
+ "--package-redirect com.unsupported:com.supported ",
srcs: [
":hoststubgen-test-tiny-framework",
"policy-override-tiny-framework.txt",
@@ -61,6 +62,7 @@
cmd: hoststubgen_common_options +
"--in-jar $(location :hoststubgen-test-tiny-framework) " +
"--policy-override-file $(location policy-override-tiny-framework.txt) " +
+ "--package-redirect com.unsupported:com.supported " +
// More options.
"--default-method-call-hook com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall " +
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 0c1d88a..f627c6e 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
@@ -84,6 +84,26 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
+## Class: android/hosttest/annotation/HostSideTestStaticInitializerStub.class
+ Compiled from "HostSideTestStaticInitializerStub.java"
+public interface android.hosttest.annotation.HostSideTestStaticInitializerStub extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 61
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStaticInitializerStub.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
## Class: android/hosttest/annotation/HostSideTestStub.class
Compiled from "HostSideTestStub.java"
public interface android.hosttest.annotation.HostSideTestStub extends java.lang.annotation.Annotation
@@ -745,20 +765,30 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
- Compiled from "TinyFrameworkClassWithInitializer.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 2
+ interfaces: 0, fields: 2, methods: 2, attributes: 2
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
@@ -769,26 +799,86 @@
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault;
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
- stack=1, locals=0, args_size=0
+ stack=2, locals=0, args_size=0
x: iconst_1
x: putstatic #x // Field sInitialized:Z
- x: return
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
LineNumberTable:
}
-SourceFile: "TinyFrameworkClassWithInitializer.java"
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 2, attributes: 2
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub;
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
+ x: return
+ LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
RuntimeInvisibleAnnotations:
x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ android.hosttest.annotation.HostSideTestStub
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
@@ -1669,3 +1759,138 @@
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/unsupported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/unsupported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/unsupported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 2
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/supported/UnsupportedClass;
+ 0 10 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/supported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 2
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/unsupported/UnsupportedClass;
+ 0 14 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/unsupported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 0761edc..d7f0149 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -364,31 +364,74 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
- Compiled from "TinyFrameworkClassWithInitializer.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 1, attributes: 3
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ static {};
descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
+ flags: (0x0008) ACC_STATIC
Code:
- stack=3, locals=1, args_size=1
+ stack=3, locals=0, args_size=0
x: new #x // class java/lang/RuntimeException
x: dup
x: ldc #x // String Stub!
x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
x: athrow
}
-SourceFile: "TinyFrameworkClassWithInitializer.java"
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
@@ -400,7 +443,9 @@
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ android.hosttest.annotation.HostSideTestStub
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
@@ -824,3 +869,83 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index faf0a46..131e0b1 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -710,46 +710,80 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
- Compiled from "TinyFrameworkClassWithInitializer.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 3
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
x: iconst_1
x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
x: return
LineNumberTable:
}
-SourceFile: "TinyFrameworkClassWithInitializer.java"
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
@@ -761,7 +795,9 @@
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ android.hosttest.annotation.HostSideTestStub
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
@@ -1772,3 +1808,163 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class com/supported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/supported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/supported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 12 0 value I
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // String com/supported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 15 10 0 this Lcom/supported/UnsupportedClass;
+ 15 10 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // String com/supported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 15 5 0 this Lcom/supported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 14 0 this Lcom/unsupported/UnsupportedClass;
+ 0 14 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/unsupported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 0761edc..d7f0149 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -364,31 +364,74 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
- Compiled from "TinyFrameworkClassWithInitializer.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 1, attributes: 3
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ static {};
descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
+ flags: (0x0008) ACC_STATIC
Code:
- stack=3, locals=1, args_size=1
+ stack=3, locals=0, args_size=0
x: new #x // class java/lang/RuntimeException
x: dup
x: ldc #x // String Stub!
x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
x: athrow
}
-SourceFile: "TinyFrameworkClassWithInitializer.java"
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
@@ -400,7 +443,9 @@
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ android.hosttest.annotation.HostSideTestStub
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
@@ -824,3 +869,83 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 874789e..3318c7d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -950,59 +950,88 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
- Compiled from "TinyFrameworkClassWithInitializer.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
+ Compiled from "TinyFrameworkClassWithInitializerDefault.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
minor version: 0
major version: 61
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 3
+ interfaces: 0, fields: 2, methods: 0, attributes: 3
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
- x: ldc #x // String <init>
- x: ldc #x // String ()V
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+}
+SourceFile: "TinyFrameworkClassWithInitializerDefault.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.class
+ Compiled from "TinyFrameworkClassWithInitializerStub.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerStub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
+ public static boolean sInitialized;
+ descriptor: Z
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static java.lang.Object sObject;
+ descriptor: Ljava/lang/Object;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=4, locals=0, args_size=0
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
x: ldc #x // String <clinit>
x: ldc #x // String ()V
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
x: iconst_1
x: putstatic #x // Field sInitialized:Z
+ x: new #x // class java/lang/Object
+ x: dup
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: putstatic #x // Field sObject:Ljava/lang/Object;
x: return
LineNumberTable:
}
-SourceFile: "TinyFrameworkClassWithInitializer.java"
+SourceFile: "TinyFrameworkClassWithInitializerStub.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
@@ -1014,7 +1043,9 @@
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ android.hosttest.annotation.HostSideTestStub
+ x: #x()
+ android.hosttest.annotation.HostSideTestStaticInitializerStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
@@ -2346,3 +2377,223 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
+ Compiled from "TinyFrameworkPackageRedirect.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect;
+
+ public static int foo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
+ x: ldc #x // String foo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class com/supported/UnsupportedClass
+ x: dup
+ x: iload_0
+ x: invokespecial #x // Method com/supported/UnsupportedClass."<init>":(I)V
+ x: invokevirtual #x // Method com/supported/UnsupportedClass.getValue:()I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 12 0 value I
+}
+SourceFile: "TinyFrameworkPackageRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/supported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.supported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/supported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 3, attributes: 3
+ private final int mValue;
+ descriptor: I
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.supported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/supported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field mValue:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 26 10 0 this Lcom/supported/UnsupportedClass;
+ 26 10 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/supported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/supported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: getfield #x // Field mValue:I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 26 5 0 this Lcom/supported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/unsupported/UnsupportedClass.class
+ Compiled from "UnsupportedClass.java"
+public class com.unsupported.UnsupportedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/unsupported/UnsupportedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 3
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.unsupported.UnsupportedClass(int);
+ descriptor: (I)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String (I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 14 0 this Lcom/unsupported/UnsupportedClass;
+ 11 14 1 value I
+
+ public int getValue();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/unsupported/UnsupportedClass
+ x: ldc #x // String getValue
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String This class is not supported
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/unsupported/UnsupportedClass;
+}
+SourceFile: "UnsupportedClass.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index 8fcd2fb..079d2a8 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -15,8 +15,3 @@
# Class load hook
class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
-
-
-class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer stubclass
- # Testing 'throw' on a static initializer. This should be handled as 'keep'.
- method <clinit> ()V throw
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
index 523106f..e212890 100755
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
@@ -92,6 +92,7 @@
--policy-override-file policy-override-tiny-framework.txt \
--gen-keep-all-file out/tiny-framework_keep_all.txt \
--gen-input-dump-file out/tiny-framework_dump.txt \
+ --package-redirect com.unsupported:com.supported \
$HOSTSTUBGEN_OPTS
# Extract the jar files, so we can look into them.
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
similarity index 66%
copy from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
copy to tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
index 01a690b..8324ed9 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.java
@@ -16,19 +16,17 @@
package com.android.hoststubgen.test.tinyframework;
import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestStub;
import android.hosttest.annotation.HostSideTestWholeClassStub;
-
-// Note, policy-override-tiny-framework.txt hss an override on this class.
-@HostSideTestClassLoadHook(
- "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
-@HostSideTestWholeClassStub
-public class TinyFrameworkClassWithInitializer {
- // Note, this method has a 'throw' in the policy file, which is handled as a 'keep' (because
- // it's a static initializer), so this won't show up in the stub jar.
+@HostSideTestStub
+public class TinyFrameworkClassWithInitializerDefault {
static {
sInitialized = true;
}
+ @HostSideTestStub
public static boolean sInitialized;
+ @HostSideTestStub
+ public static Object sObject = new Object();
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
similarity index 75%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
rename to tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
index 01a690b..998acf2 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub.java
@@ -16,19 +16,21 @@
package com.android.hoststubgen.test.tinyframework;
import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestStaticInitializerStub;
+import android.hosttest.annotation.HostSideTestStub;
import android.hosttest.annotation.HostSideTestWholeClassStub;
-
-// Note, policy-override-tiny-framework.txt hss an override on this class.
@HostSideTestClassLoadHook(
"com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
-@HostSideTestWholeClassStub
-public class TinyFrameworkClassWithInitializer {
- // Note, this method has a 'throw' in the policy file, which is handled as a 'keep' (because
- // it's a static initializer), so this won't show up in the stub jar.
+@HostSideTestStub
+@HostSideTestStaticInitializerStub
+public class TinyFrameworkClassWithInitializerStub {
static {
sInitialized = true;
}
+ @HostSideTestStub
public static boolean sInitialized;
+ @HostSideTestStub
+ public static Object sObject = new Object();
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java
new file mode 100644
index 0000000..a82be54
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkPackageRedirect {
+ /**
+ * A method that uses "unsupported" class. HostStubGen will redirect them to the "supported"
+ * one (because of --package-redirect), so this test will pass.
+ */
+ public static int foo(int value) {
+ // This method throws, so it's not callable as-is. But HostStubGen
+ // will rewrite it, it will actually work.
+ return new com.unsupported.UnsupportedClass(value).getValue();
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java
new file mode 100644
index 0000000..fa58664
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/supported/UnsupportedClass.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.supported;
+
+import android.hosttest.annotation.HostSideTestWholeClassKeep;
+
+// Used for testing --package-redirect.
+@HostSideTestWholeClassKeep
+public class UnsupportedClass {
+ private final int mValue;
+
+ public UnsupportedClass(int value) {
+ mValue = value;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java
new file mode 100644
index 0000000..0409b02
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/unsupported/UnsupportedClass.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.unsupported;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+// Used for testing --package-redirect.
+@HostSideTestWholeClassStub
+public class UnsupportedClass {
+ public UnsupportedClass(int value) {
+ throw new RuntimeException("This class is not supported");
+ }
+
+ public int getValue() {
+ throw new RuntimeException("This class is not supported");
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index cd604ff..29aabc7 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -127,11 +127,11 @@
@Test
public void testClassLoadHook() {
- assertThat(TinyFrameworkClassWithInitializer.sInitialized).isTrue();
+ assertThat(TinyFrameworkClassWithInitializerStub.sInitialized).isTrue();
// Having this line before assertThat() will ensure these class are already loaded.
- var classes = new Class[] {
- TinyFrameworkClassWithInitializer.class,
+ var classes = new Class[]{
+ TinyFrameworkClassWithInitializerStub.class,
TinyFrameworkClassAnnotations.class,
TinyFrameworkForTextPolicy.class,
};
@@ -145,6 +145,18 @@
.doesNotContain(TinyFrameworkNestedClasses.class);
}
+ @Test
+ public void testStaticInitializer_Default() {
+ assertThat(TinyFrameworkClassWithInitializerDefault.sInitialized).isFalse();
+ assertThat(TinyFrameworkClassWithInitializerDefault.sObject).isNull();
+ }
+
+ @Test
+ public void testStaticInitializer_Stub() {
+ assertThat(TinyFrameworkClassWithInitializerStub.sInitialized).isTrue();
+ assertThat(TinyFrameworkClassWithInitializerStub.sObject).isNotNull();
+ }
+
/**
* Test to try accessing JDK private fields using reflections + setAccessible(true),
* which is now disallowed due to Java Modules, unless you run the javacommand with.
@@ -182,4 +194,9 @@
m.invoke(fd, 0);
assertThat(f.get(fd)).isEqualTo(0);
}
+
+ @Test
+ public void testPackageRedirect() throws Exception {
+ assertThat(TinyFrameworkPackageRedirect.foo(1)).isEqualTo(1);
+ }
}
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index 8bc88de..ba1d404 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -24,8 +24,14 @@
hoststubgen-test-tiny-test
)
-# First, build all the test modules. This shouldn't fail.
-run m run-ravenwood-test ${READY_TEST_MODULES[*]} ${NOT_READY_TEST_MODULES[*]}
+MUST_BUILD_MODULES=(
+ run-ravenwood-test
+ "${NOT_READY_TEST_MODULES[*]}"
+ HostStubGenTest-framework-test
+)
+
+# First, build all the test / etc modules. This shouldn't fail.
+run m "${MUST_BUILD_MODULES[@]}"
# Next, run the golden check. This should always pass too.
# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
index dcd94f1..83b8f16 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
@@ -197,6 +197,15 @@
/* Check that we are connected to the super class */
val overridingMethod = node as PsiMethod
val parents = overridingMethod.findSuperMethods()
+ if (parents.isEmpty()) {
+ context.report(
+ ISSUE_MISUSING_ENFORCE_PERMISSION,
+ node,
+ context.getLocation(node),
+ "The method ${node.name} does not override an AIDL generated method"
+ )
+ return
+ }
for (overriddenMethod in parents) {
// The equivalence check can be skipped, if both methods are
// annotated, it will be verified by visitAnnotationUsage.
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
index b3dacbd..d8afcb9 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
@@ -28,7 +28,9 @@
override fun getIssues(): List<Issue> = listOf(
EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
- EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION
+ EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
+ EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
+ EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION
)
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
@@ -41,7 +43,9 @@
public class TestClass2 extends IFooMethod.Stub {
@Override
@EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -58,7 +62,9 @@
public class TestClass11 extends IFooMethod.Stub {
@Override
@EnforcePermission(allOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAll() {}
+ public void testMethodAll() {
+ testMethodAll_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -75,7 +81,10 @@
public class TestClass111 extends IFooMethod.Stub {
@Override
@EnforcePermission(allOf={"android.permission.INTERNET", android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAllLiteral() {}
+ public void testMethodAllLiteral() {
+ testMethodAllLiteral_enforcePermission();
+
+ }
}
""").indented(),
*stubs
@@ -92,7 +101,9 @@
public class TestClass12 extends IFooMethod.Stub {
@Override
@EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAny() {}
+ public void testMethodAny() {
+ testMethodAny_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -109,7 +120,9 @@
public class TestClass121 extends IFooMethod.Stub {
@Override
@EnforcePermission(anyOf={"android.permission.INTERNET", android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAnyLiteral() {}
+ public void testMethodAnyLiteral() {
+ testMethodAnyLiteral_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -124,7 +137,9 @@
package test.pkg;
public class TestClass4 extends IFooMethod.Stub {
@android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -132,21 +147,44 @@
.run()
.expect("""
src/test/pkg/TestClass4.java:4: Error: The method TestClass4.testMethod is annotated with @android.annotation.EnforcePermission(android.Manifest.permission.INTERNET) \
- which differs from the overridden method Stub.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). \
+ which differs from the overridden method IFooMethod.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethod() {}
+ public void testMethod() {
~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
}
+ fun testDetectIssuesAnnotationOnNonStubMethod() {
+ lint().files(java(
+ """
+ package test.pkg;
+ public class TestClass42 extends IFooMethod.Stub {
+ @android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
+ public void aRegularMethodNotPartOfStub() {
+ }
+ }
+ """).indented(),
+ *stubs
+ )
+ .run()
+ .expect("""
+ src/test/pkg/TestClass42.java:3: Error: The method aRegularMethodNotPartOfStub does not override an AIDL generated method [MisusingEnforcePermissionAnnotation]
+ @android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
+ ^
+ 1 errors, 0 warnings
+ """.addLineContinuation())
+ }
+
fun testDetectIssuesEmptyAnnotationOnMethod() {
lint().files(java(
"""
package test.pkg;
public class TestClass41 extends IFooMethod.Stub {
@android.annotation.EnforcePermission
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -154,9 +192,9 @@
.run()
.expect("""
src/test/pkg/TestClass41.java:4: Error: The method TestClass41.testMethod is annotated with @android.annotation.EnforcePermission \
- which differs from the overridden method Stub.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). \
+ which differs from the overridden method IFooMethod.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethod() {}
+ public void testMethod() {
~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -168,7 +206,9 @@
package test.pkg;
public class TestClass9 extends IFooMethod.Stub {
@android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.NFC})
- public void testMethodAny() {}
+ public void testMethodAny() {
+ testMethodAny_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -177,10 +217,10 @@
.expect("""
src/test/pkg/TestClass9.java:4: Error: The method TestClass9.testMethodAny is annotated with \
@android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.NFC}) \
- which differs from the overridden method Stub.testMethodAny: \
+ which differs from the overridden method IFooMethod.testMethodAny: \
@android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE}). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAny() {}
+ public void testMethodAny() {
~~~~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -192,7 +232,9 @@
package test.pkg;
public class TestClass91 extends IFooMethod.Stub {
@android.annotation.EnforcePermission(anyOf={"android.permission.INTERNET", "android.permissionoopsthisisatypo.READ_PHONE_STATE"})
- public void testMethodAnyLiteral() {}
+ public void testMethodAnyLiteral() {
+ testMethodAnyLiteral_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -201,10 +243,10 @@
.expect("""
src/test/pkg/TestClass91.java:4: Error: The method TestClass91.testMethodAnyLiteral is annotated with \
@android.annotation.EnforcePermission(anyOf={"android.permission.INTERNET", "android.permissionoopsthisisatypo.READ_PHONE_STATE"}) \
- which differs from the overridden method Stub.testMethodAnyLiteral: \
+ which differs from the overridden method IFooMethod.testMethodAnyLiteral: \
@android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"}). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAnyLiteral() {}
+ public void testMethodAnyLiteral() {
~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -216,7 +258,9 @@
package test.pkg;
public class TestClass10 extends IFooMethod.Stub {
@android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, android.Manifest.permission.NFC})
- public void testMethodAll() {}
+ public void testMethodAll() {
+ testMethodAll_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -225,10 +269,10 @@
.expect("""
src/test/pkg/TestClass10.java:4: Error: The method TestClass10.testMethodAll is annotated with \
@android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, android.Manifest.permission.NFC}) \
- which differs from the overridden method Stub.testMethodAll: \
+ which differs from the overridden method IFooMethod.testMethodAll: \
@android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE}). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAll() {}
+ public void testMethodAll() {
~~~~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -240,7 +284,9 @@
package test.pkg;
public class TestClass101 extends IFooMethod.Stub {
@android.annotation.EnforcePermission(allOf={"android.permission.INTERNET", "android.permissionoopsthisisatypo.READ_PHONE_STATE"})
- public void testMethodAllLiteral() {}
+ public void testMethodAllLiteral() {
+ testMethodAllLiteral_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -249,10 +295,10 @@
.expect("""
src/test/pkg/TestClass101.java:4: Error: The method TestClass101.testMethodAllLiteral is annotated with \
@android.annotation.EnforcePermission(allOf={"android.permission.INTERNET", "android.permissionoopsthisisatypo.READ_PHONE_STATE"}) \
- which differs from the overridden method Stub.testMethodAllLiteral: \
+ which differs from the overridden method IFooMethod.testMethodAllLiteral: \
@android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"}). \
The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAllLiteral() {}
+ public void testMethodAllLiteral() {
~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -263,16 +309,18 @@
"""
package test.pkg;
public class TestClass6 extends IFooMethod.Stub {
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
)
.run()
.expect("""
- src/test/pkg/TestClass6.java:3: Error: The method TestClass6.testMethod overrides the method Stub.testMethod which is annotated with @EnforcePermission. \
+ src/test/pkg/TestClass6.java:3: Error: The method TestClass6.testMethod overrides the method IFooMethod.testMethod which is annotated with @EnforcePermission. \
The same annotation must be used on TestClass6.testMethod [MissingEnforcePermissionAnnotation]
- public void testMethod() {}
+ public void testMethod() {
~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -284,16 +332,18 @@
package test.pkg;
public class TestClass7 extends IBar.Stub {
@android.annotation.EnforcePermission(android.Manifest.permission.INTERNET)
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
)
.run()
.expect("""
- src/test/pkg/TestClass7.java:4: Error: The method TestClass7.testMethod overrides the method Stub.testMethod which is not annotated with @EnforcePermission. \
- The same annotation must be used on Stub.testMethod. Did you forget to annotate the AIDL definition? [MissingEnforcePermissionAnnotation]
- public void testMethod() {}
+ src/test/pkg/TestClass7.java:4: Error: The method TestClass7.testMethod overrides the method IBar.testMethod which is not annotated with @EnforcePermission. \
+ The same annotation must be used on IBar.testMethod. Did you forget to annotate the AIDL definition? [MissingEnforcePermissionAnnotation]
+ public void testMethod() {
~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation())
@@ -304,7 +354,9 @@
"""
package test.pkg;
public class Default extends IFooMethod.Stub {
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -313,8 +365,8 @@
.expect(
"""
src/test/pkg/Default.java:3: Error: The method Default.testMethod \
- overrides the method Stub.testMethod which is annotated with @EnforcePermission. The same annotation must be used on Default.testMethod [MissingEnforcePermissionAnnotation]
- public void testMethod() {}
+ overrides the method IFooMethod.testMethod which is annotated with @EnforcePermission. The same annotation must be used on Default.testMethod [MissingEnforcePermissionAnnotation]
+ public void testMethod() {
~~~~~~~~~~
1 errors, 0 warnings
""".addLineContinuation()
@@ -329,16 +381,24 @@
public class TestClass121 extends IFooMethod.Stub {
@Override
@EnforcePermission("READ_PHONE_STATE")
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
@Override
@EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethodParentShortPermission() {}
+ public void testMethodParentShortPermission() {
+ testMethodParentShortPermission_enforcePermission();
+ }
@Override
@EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"})
- public void testMethodAnyLiteral() {}
+ public void testMethodAnyLiteral() {
+ testMethodAnyLiteral_enforcePermission();
+ }
@Override
@EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAnyLiteralParentsShortPermission() {}
+ public void testMethodAnyLiteralParentsShortPermission() {
+ testMethodAnyLiteralParentsShortPermission_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -355,16 +415,24 @@
public class TestClass121 extends IFooMethod.Stub {
@Override
@EnforcePermission("READ_WRONG_PHONE_STATE")
- public void testMethod() {}
+ public void testMethod() {
+ testMethod_enforcePermission();
+ }
@Override
@EnforcePermission(android.Manifest.permission.READ_WRONG_PHONE_STATE)
- public void testMethodParentShortPermission() {}
+ public void testMethodParentShortPermission() {
+ testMethodParentShortPermission_enforcePermission();
+ }
@Override
@EnforcePermission(anyOf={"WRONG_INTERNET", "READ_PHONE_STATE"})
- public void testMethodAnyLiteral() {}
+ public void testMethodAnyLiteral() {
+ testMethodAnyLiteral_enforcePermission();
+ }
@Override
@EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_WRONG_PHONE_STATE})
- public void testMethodAnyLiteralParentsShortPermission() {}
+ public void testMethodAnyLiteralParentsShortPermission() {
+ testMethodAnyLiteralParentsShortPermission_enforcePermission();
+ }
}
""").indented(),
*stubs
@@ -372,17 +440,17 @@
.run()
.expect(
"""
- src/test/pkg/TestClass121.java:6: Error: The method TestClass121.testMethod is annotated with @EnforcePermission("READ_WRONG_PHONE_STATE") which differs from the overridden method Stub.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethod() {}
+ src/test/pkg/TestClass121.java:6: Error: The method TestClass121.testMethod is annotated with @EnforcePermission("READ_WRONG_PHONE_STATE") which differs from the overridden method IFooMethod.testMethod: @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
+ public void testMethod() {
~~~~~~~~~~
- src/test/pkg/TestClass121.java:9: Error: The method TestClass121.testMethodParentShortPermission is annotated with @EnforcePermission(android.Manifest.permission.READ_WRONG_PHONE_STATE) which differs from the overridden method Stub.testMethodParentShortPermission: @android.annotation.EnforcePermission("READ_PHONE_STATE"). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodParentShortPermission() {}
+ src/test/pkg/TestClass121.java:11: Error: The method TestClass121.testMethodParentShortPermission is annotated with @EnforcePermission(android.Manifest.permission.READ_WRONG_PHONE_STATE) which differs from the overridden method IFooMethod.testMethodParentShortPermission: @android.annotation.EnforcePermission("READ_PHONE_STATE"). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
+ public void testMethodParentShortPermission() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- src/test/pkg/TestClass121.java:12: Error: The method TestClass121.testMethodAnyLiteral is annotated with @EnforcePermission(anyOf={"WRONG_INTERNET", "READ_PHONE_STATE"}) which differs from the overridden method Stub.testMethodAnyLiteral: @android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"}). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAnyLiteral() {}
+ src/test/pkg/TestClass121.java:16: Error: The method TestClass121.testMethodAnyLiteral is annotated with @EnforcePermission(anyOf={"WRONG_INTERNET", "READ_PHONE_STATE"}) which differs from the overridden method IFooMethod.testMethodAnyLiteral: @android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"}). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
+ public void testMethodAnyLiteral() {
~~~~~~~~~~~~~~~~~~~~
- src/test/pkg/TestClass121.java:15: Error: The method TestClass121.testMethodAnyLiteralParentsShortPermission is annotated with @EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_WRONG_PHONE_STATE}) which differs from the overridden method Stub.testMethodAnyLiteralParentsShortPermission: @android.annotation.EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"}). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
- public void testMethodAnyLiteralParentsShortPermission() {}
+ src/test/pkg/TestClass121.java:21: Error: The method TestClass121.testMethodAnyLiteralParentsShortPermission is annotated with @EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_WRONG_PHONE_STATE}) which differs from the overridden method IFooMethod.testMethodAnyLiteralParentsShortPermission: @android.annotation.EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"}). The same annotation must be used for both methods. [MismatchingEnforcePermissionAnnotation]
+ public void testMethodAnyLiteralParentsShortPermission() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 errors, 0 warnings
""".addLineContinuation()
@@ -396,27 +464,6 @@
"""
public interface IFooMethod extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements IFooMethod {
- @Override
- @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod() {}
- @Override
- @android.annotation.EnforcePermission("READ_PHONE_STATE")
- public void testMethodParentShortPermission() {}
- @Override
- @android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAny() {}
- @Override
- @android.annotation.EnforcePermission(anyOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"})
- public void testMethodAnyLiteral() {}
- @Override
- @android.annotation.EnforcePermission(anyOf={"INTERNET", "READ_PHONE_STATE"})
- public void testMethodAnyLiteralParentsShortPermission() {}
- @Override
- @android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, android.Manifest.permission.READ_PHONE_STATE})
- public void testMethodAll() {}
- @Override
- @android.annotation.EnforcePermission(allOf={android.Manifest.permission.INTERNET, "android.permission.READ_PHONE_STATE"})
- public void testMethodAllLiteral() {}
}
@android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
public void testMethod();
@@ -441,8 +488,6 @@
"""
public interface IBar extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements IBar {
- @Override
- public void testMethod() {}
}
public void testMethod();
}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt
index 3ef02f8..a4b0bc3 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorCodegenTest.kt
@@ -28,7 +28,8 @@
override fun getDetector(): Detector = EnforcePermissionDetector()
override fun getIssues(): List<Issue> = listOf(
- EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER
+ EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
+ EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION
)
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)